|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionOther ATL7 changes are covered here and here. First let's go over some of the new classes added for simplifying the ATL Server development. These classes can be used anywhere you need them not just for ATL Server development.Cryptography (CCryptProv, CCryptKey, CCryptKeyedHash, etc):
Hashing:CCryptProv prov; prov.Initialize(); char rand[256]; memset(rand, 0, sizeof(rand)); //generating cryptographically random bytes HRESULT hr = prov.GenRandom(sizeof(rand), (BYTE*)rand); if(hr != S_OK) return 0; ///////////////////////////////////////////// //hashing //TODO: input password from user. never hard code it like this! const char* szPassword = "#$%^!SDD%$^&%^&~"; char Hash1st[256]; DWORD dwSize=256; char Hash2nd[256]; memset(Hash1st, 0, sizeof(Hash1st)); memset(Hash2nd, 0, sizeof(Hash2nd)); CCryptKeyedHash hash; //use SHA-1 or any other such as MD5, HMAC, etc hash.Initialize(prov, CALG_SHA1, CCryptKey::EmptyKey, 0); // add data to hash hr = hash.AddString(szPassword); if(hr != S_OK) return 0; //get the hashed value hr = hash.GetValue((BYTE*)Hash1st, &dwSize); if(hr != S_OK) return 0; hash.Destroy(); // now we can check the hashed value against original whenever we want hash.Initialize(prov, CALG_SHA1, CCryptKey::EmptyKey, 0); //add data to hash hr = hash.AddString(szPassword); if(hr != S_OK) return 0; //get hashed value hr = hash.GetValue((BYTE*)Hash2nd, &dwSize); if(hr != S_OK) return 0; //hash values should matched if(memcmp(Hash1st, Hash2nd, sizeof(Hash1st)) == 0) ATLTRACE("\npassword matched.\n\n"); Encryption:const int ENCRYPT_BLOCK_SIZE = 64; //since TripleDES is used, which uses block cipher mode, //the data size must be a multiple of block size (8 for TripleDes) DWORD dwBlockLen = 2000 - 1000 % ENCRYPT_BLOCK_SIZE; ATLASSERT((dwBlockLen%8)==0); CHeapPtr<BYTE> buff; buff.Allocate(dwBlockLen); CCryptProv prov; //need MS_ENHANCED_PROV or MS_STRONG_PROV for TripleDES algo HRESULT hr = prov.Initialize(PROV_RSA_FULL, NULL, MS_STRONG_PROV); //TODO: create some file named testpln.txt with some data for example code // to work //encrypt file using TripleDES and based on password { CCryptDerivedKey derKey; //let's use md5 hash to hash the password for the file to be encrypted //normally you would use sha, this is only to show how you can easily use Regular Expressions:Regular Expression Reference(MSDN)CAtlRegExp<> regexp; CAtlREMatchContext<> mc; // match any line that starts with any number of digits, // has a dash, and ends with any number of digits if(regexp.Parse("^\\d+-\\d+$") == REPARSE_ERROR_OK) { const char* szNumDashNum="5663-4662"; if(regexp.Match(szNumDashNum, &mc)) { ATLTRACE("Matched"); } } Support for sending SMTP email:MIME & SMTP Reference(MSDN)CoInitialize(0); { CSMTPConnection conn; conn.Connect("SMTP Server Address"); CMimeMessage msg; msg.SetSender(_T("sender@address")); msg.AddRecipient(_T("recepient@address")); msg.SetPriority(ATL_MIME_HIGH_PRIORITY); //msg.AttachFile(_T("filename")); msg.AddText(_T("message text")); msg.SetSubject(_T("Subject line")); conn.SendMessage(msg); } CoUninitialize(); Encoding:Encoding Reference(MSDN) CString sSource = "some string"; int nDestLen = Base64EncodeGetRequiredLength(sSource.GetLength()); CString str64; Base64Encode((const BYTE*)(LPCSTR)sSource, sSource.GetLength(), HTML Generation:HTML Generation Reference(MSDN)CHtmlGen html; CWriteStreamOnCString stream; html.Initialize(&stream); html.html(); html.head(); html.title(_T("Sample Page")); html.headEnd(); html.body(_T("Gray")); html.WriteRaw(_T("Using ATL7!")); html.bodyEnd(); html.htmlEnd(); cout<<(LPCTSTR)stream.m_str; HTTP Client:HTTP Client Reference(MSDN)class CHttpClientWithCookie : public CAtlHttpClient { template<> void OnSetCookie(LPCTSTR cookie) { std::cout<<"Got Cookie from server: "<<std::endl<<cookie<<std::endl; return; } }; { CHttpClientWithCookie client; //client.NavigateChunked() client.Navigate("http://www.microsoft.com"); const char* pszBody = (const char*)client.GetBody(); CString sRawHdr; DWORD dwLen; client.GetRawResponseHeader(0, &dwLen); client.GetRawResponseHeader((BYTE*)sRawHdr.GetBufferSetLength(dwLen), &dwLen); std::cout<<"Raw Response Header: "<<std::endl<<(LPCTSTR)sRawHdr; }There are many other miscellaneous helper classes and more specific ones that deal with Web Application/Web Service development. Debugging:Debugging(MSDN) ISAPI Filter/Extension Overview:ISAPI stands for Internet Server Application Programming Interface. ISAPI programming is divided into Filters and Extensions. Both are DLLs with specific exported functions. ISAPI filters are loaded with the IIS and stay in memory until HTTP Web service shuts down. ISAPI Extensions are loaded on demand and provide extended functionality to web applications. ISAPI filters are useful for examining/filtering incoming and outgoing HTTP requests under IIS (for example, implementing custom authentication, encryption, compression, logging, etc). ISAPI extensions are useful for developing dynamic web pages and work per URL reference. There is no class for ISAPI filter under ATL7. ATL Server provides support for ISAPI extensions in form of DLL cache, file cache, page cache, memory cache, data source cache, thread pool, remote management with web based or web service based interfaces, predefined performance counters, session support, etc. As you can see that's quite a lot of functionality/services. In addition it's easy to add your own services to the existing ones.
Web Application:
ATL7 Web Application is a combination of ISAPI extension and a handler DLL (or both can be combined into one dll) to create dynamic web pages. ISAPI extension is a DLL that exports three functions: ATL7 web applications are built upon stencils. Stencil is a text file normally with .srf extension, resides in the virtual directory of ISAPI extension, and can have a mixed content of static html and dynamic/run-time replaceable tags. In The main function that does all the work is So when any of these worker threads get the chance and successfully dequeue the completion request from the port, they execute the request. Executing request means processing the stencil file, first the whole processed page is looked up in page cache (controlled by overriding The handler's DLL entry point is called, that is The wizard generated code (when you choose Data Source Cache, you're free to do it yourself also, but this can serve as an example) also produces a custom ATL Server also provides a number of ways to control and configure your web application. It provides default implementation for remotely controlling the Thread Pool, SRF file cache, and Web App DLL Cache. All you do is define the appropriate symbols for whatever service you want to expose through HTML web interface or Web services, restrict to specific users, etc and you get the full implementation for free! You can follow the steps described in Extension Management Services on how to do it step by step! The services that you choose when you create new project: Blob cache, File Cache, Data Source Cache, Browser capabilities, Session services and in addition the framework provided services: DllCache, StencilCache, ThreadPoolConfig, and AtlMemMgr are all exposed through
Web Service:
ATL Web service support is also implemented as ISAPI extension. You can either use the wizard or try it manually for learning purposes. Create simple Win32 DLL project. Add .def file to export the 3 ISAPI extension functions. Then in its most simplest form the web service implemented with ATL7 can look as follows: //websvc.h #pragma once namespace ATL7WebService { [export] struct S { int n; double d; }; [uuid("86C903DD-4D9F-4928-A3B5-AE242EA86D7A")] __interface IWebSvc { HRESULT GetString([out,retval] BSTR* pVal); HRESULT GetData([out, retval] ATLSOAP_BLOB* pBlob); HRESULT GetStruct([out, retval] S* pVal); //etc }; [request_handler(name="Default", sdl="WSDL")] [soap_handler(name="WebSvc", namespace="urn:ATL7WebService")] class CWebSvc : public IWebSvc { public: [soap_method] HRESULT GetString(/*[out,retval]*/ BSTR* pVal) { CComBSTR strOut("Some String"); *pVal = strOut.Detach(); return S_OK; } [soap_method] HRESULT GetData(/*[out, retval]*/ ATLSOAP_BLOB* pBlob) { IAtlMemMgr* pMem = GetMemMgr(); pBlob->size = 1000; pBlob->data = (unsigned char*)pMem->Allocate(pBlob->size); memset(pBlob->data, 'a', pBlob->size); return S_OK; } [soap_method] HRESULT GetStruct(/*[out, retval]*/ S* pVal) { pVal->n = 10; pVal->d = 1.1; return S_OK; } //etc }; } //websvc.cpp #define _WIN32_WINNT 0x0403 //need for attributes #define _ATL_ATTRIBUTES //not using COM for this simple project #define _ATL_NO_COM_SUPPORT #include <atlisapi.h> #include <atlsoap.h> #include "websvc.h" [ module(name="WebSvc", type="dll") ]; //don't need any .idl, .tlb, etc files generated [ emitidl(restricted) ]; CIsapiExtension<> theExtension; extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB) { return theExtension.HttpExtensionProc(lpECB); } extern "C" BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO* pVer) { return theExtension.GetExtensionVersion(pVer); } extern "C" BOOL WINAPI TerminateExtension(DWORD dwFlags) { return theExtension.TerminateExtension(dwFlags); } Either use the VC++.NET project properties for Web Deployment and add .dll extension under Application Mappings or create the virtual directory and register the App mappings manually under IIS. After that you can access the WSDL of the web service in web browser as follows http://localhost/websvc/WebSvc.dll?Handler=WSDL Now when you access it again as in Web Application in previous section, If using //client.cpp #include <iostream> #include "client.h" int main() { CoInitialize(NULL); { WebSvc::CWebSvc svc; CComBSTR str; if(svc.GetString(&str.m_str) == S_OK) { std::wcout<<str.m_str<<std::endl; ATLSOAP_BLOB blob; if(svc.GetData(&blob) == S_OK) { std::cout<<"blob of size: "<<blob.size<<std::endl; std::cout<<blob.data[0]<<blob.data If you want to use Windows Integrated Authentication or Basic, you can use CoInitialize(NULL);
{
//by default uses CSoapSocketClientT
WebSvc::CWebSvc svc;
//this code is specific to CSoapSocketClientT
CAtlHttpClient& httpClient = svc.m_socket;
CNTLMAuthObject authUser;
httpClient.AddAuthObj(_T("NTLM"), &authUser);
httpClient.NegotiateAuth(true);
CComBSTR str;
if(svc.GetString(&str.m_str) == S_OK)
{
//etc
}
}
CoUninitialize();
If you want to use HTTPS connection you can look at the Secure SOAP sample: WebSvc::CWebSvcT<CSoapWininetClient> svc; CComBSTR str; if(svc.GetString(&str.m_str) == S_OK) { //etc } Or your own implementation for the SOAP transport. This sample demonstrates the creation of SOAP servers and clients that communicate using different transports: sockets, Microsoft Message Queue, the file system, and a custom HTTP listener: | ||||||||||||||||||||