Built-in Global ISAPI Services


The simplest case of a service is a stateless package of reusable functions. You can easily implement such a service as a class with no members . The IGenericService package described in the previous section is a good example of this type of service.

As the service is stateless, no problems will occur from simultaneously using it from multiple threads. (ATL Server processes multiple requests on multiple threads, so it s possible ”even likely ”that the service will be used by multiple threads at the same time.) This raises some problems if the service contains some persistent data (such as a cache service) that s to be shared by multiple threads. You have to use a synchronization mechanism to ensure thread safety of the persistent data. This is the solution used by the BLOB cache and file cache services in ATL Server.

Examples of commonly used functionalities that you can easily implement using global ISAPI services are as follows :

  • Basic authentication service: Use such a service to validate a user based on login name and password.

  • Counter service: Use such a service to display the number of hits on the Web application.

Here follows some analysis of a hypothetical counter service, as it has a few particularities that make it a good case study for global services. Such a service would increment (in a thread-safe manner; for instance, with the InterlockedIncrement API) a counter whenever a page (therefore, a request handler) is hit by an HTTP request. In addition, the service would provide an interface for retrieving the current number of hits to display it on pages. The service would also be responsible for persisting to a selected medium (usually the hard drive or a database) the current counter value, to preserve it while the Web application is shut down.

You can implement a simple version of the counter service by modifying the previous generic service to make it expose methods for incrementing, serializing, and retrieving the counter. Then, each request handler would be responsible for incrementing the counter and asking for a serialization of the value (or the increment functionality would also ensure that the value is persisted ).

A more refined implementation would take advantage of the behavior of the ISAPI extensions. You can do this by overriding the following functions in the CIsapiExtension derivative:

  • First, override the HttpExtensionProc function. This function is invoked anytime an HTTP request is processed by the ISAPI extension; therefore, it s a very good place for incrementing the counter value. The function has to call the base class s implementation to actually handle the request.

     DWORD HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)  {          // add Counter incrementing code here,          // then call the default implementation>          return __super::HttpExtensionProc(lpECB);  } 
  • Override the TerminateExtension function. This function is invoked anytime an ISAPI extension is unloaded; therefore, it s a good place to ensure that the counter value is persisted.

     BOOL TerminateExtension(DWORD dwFlags)  {          // add code here for saving the Counter value          //  to the persistence medium          return __super:: TerminateExtension (dwFlags)  } 
  • Override the GetExtensionVersion function. This function is invoked anytime an ISAPI extension is loaded; therefore, it s a good place to ensure that the counter value is loaded from the persistence storage.

     BOOL GetExtensionVersion(HSE_VERSION_INFO* pVer)  {          // add code here for loading the Counter value          // from the persistence medium          return __super:: GetExtensionVersion(pVer)  } 

By using these overrides , the request handlers don t have to worry anymore about incrementing the request counter and, therefore, you can use precompiled application DLLs (containing request handlers) and the page counter will be incremented for those as well.

In conclusion, the global ISAPI services are a flexible mechanism for shared functionalities that involve little or no contention . If the service is stateless, then the only thing to do (besides actually implementing the service) is to expose it by overriding the ISAPI extension class s QueryService method. If the service has a state and that state has to be persisted, then the GetExtensionVersion and TerminateExtension methods of the ISAPI extension class are very good opportunities for saving and restoring the state of the service. Also, for services with state, the routines that might change the state have to be thread-safe.




ATL Server. High Performance C++ on. NET
Observing the User Experience: A Practitioners Guide to User Research
ISBN: B006Z372QQ
EAN: 2147483647
Year: 2002
Pages: 181

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net