Using Database-Backed Session State


Using Database- Backed Session State

The last topic we cover in this chapter is how to store your session state in a database rather than in memory. Storing your session state in a database has numerous advantages. For example, if your Web service crashes, your session state will still be preserved. Also, using a database allows you to use session state in a Web farm scenario. In a Web farm, you can t guarantee that a set of requests in a given session will be processed by the same Web server. That means that the session state can t be stored in the memory of one Web server. If you use a central database, then your request can be processed by any of the Web servers in your Web farm.

As we mentioned before, ATL Server provides an implementation of a database-backed session state service. To use it, you only have to change the way you templatized the CSessionStateService class in your ATL Server ISAPI extension class.

The code in Listing 8-3 is necessary to use database-backed session state. This code may look daunting, but rest assured, it s completely generated for you by the ATL Server Project Wizard. You simply need to choose the OLE DB “backed session state services under the Server Options tab in the ATL Server Project Wizard.

Listing 8.3: Using Database-Backed Session State
start example
 1 #pragma once  2  3 #include <atlisapi.h>  4 #include <atldbcli.h>  5 #include <atlsession.h>  6 #define _DATASOURCE_CACHE 1  7  8 class CIsapiExtensionWorker : public CIsapiWorker  9 {  10  typedef CDataSourceCache<>      ds_cache_type;  11  CComObjectGlobal<ds_cache_type> m_dsCache;  12  13  public:  14      CIsapiExtensionWorker()  15      {}  16  17  ~CIsapiExtensionWorker()  18  {}  19  20  virtual BOOL GetWorkerData(DWORD dwParam, void **ppvData)  21  {  22      if (dwParam == _DATASOURCE_CACHE && ppvData)  23      {  24          *ppvData = (void *)&m_dsCache;  25          m_dsCache.AddRef();  26          return TRUE;  27      }  28  29      return FALSE;  30  }  31 };  32  33  34  template <class ThreadPoolClass=CThreadPool<CIsapiExtensionWorker>,  35            class CStatClass=CNoRequestStats,  36            class HttpUserErrorTextProvider=CDefaultErrorProvider,  37            class WorkerThreadTraits=DefaultThreadTraits >  38  class CIsapiExtension :  39      public CIsapiExtension<ThreadPoolClass,  40                             CStatClass,  41                             HttpUserErrorTextProvider,  42                             WorkerThreadTraits>  43 {  44  protected:  45      typedef CIsapiExtension<ThreadPoolClass,  46                              CStatClass,  47                              HttpUserErrorTextProvider,  48                              WorkerThreadTraits> baseISAPI;  49      typedef CWorkerThread<WorkerThreadTraits> WorkerThreadClass;  50      typedef CSessionStateService<WorkerThreadClass,  51                                   CDBSessionServiceImpl> sessionSvcType;  52      CComObjectGlobal<sessionSvcType> m_SessionStateSvc;  53  54 public:  55  BOOL GetExtensionVersion(HSE_VERSION_INFO* pVer)  56  {  57      if (!baseISAPI::GetExtensionVersion(pVer))  58      {  59          return FALSE;  60      }  61  62      if (GetCriticalIsapiError() != 0)  63      {  64          return TRUE;  65      }  66  67      if (S_OK != m_SessionStateSvc.Initialize(  68                           &m_WorkerThread,  69                           static_cast<IServiceProvider*>(this),  70                           L"Provider=SQLOLEDB.1;\  71                           Integrated Security=SSPI;\  72                           Persist Security Info=False;\  73                           Initial Catalog=pubs;\  74                           Data Source=TestServer\vsdotnet;\  75                           Use Procedure for Prepare=1;\  76                           Auto Translate=True;\  77                           Packet Size=4096;\  78                           Workstation ID=TestServer;\  79                           Use Encryption for Data=False;\  80                           Tag with column collation when possible=False",  81                           ATL_SESSION_TIMEOUT))  82      {  83          ATLTRACE("Session service failed to initialize\n");  84          TerminateExtension(0);  85  86          return SetCriticalIsapiError(IDS_ATLSRV_CRITICAL_SESSIONSTATEFAILED);  87      }  88  89      return TRUE;  90  }  91  92  BOOL TerminateExtension(DWORD dwFlags)  93  {  94      m_SessionStateSvc.Shutdown();  95      BOOL bRet = baseISAPI::TerminateExtension(dwFlags);  96  97      return bRet;  98  }  99  100     HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService,  101                                       REFIID  riid,  102                                        void**  ppvObject)  103{  104    if (InlineIsEqualGUID(guidService,  105                           __uuidof(ISessionStateService)))  106     {  107         return m_SessionStateSvc.QueryInterface(riid, ppvObject);  108     }  109  110     if (InlineIsEqualGUID(guidService,  111                           __uuidof(IDataSourceCache)))  112     {  113         CIsapiWorker *pWorker = GetThreadWorker();  114         if (pWorker)  115         {  116             CDataSourceCache<> *pCache = NULL;  117             if (pWorker->GetWorkerData(_DATASOURCE_CACHE,  118                                        (void **)&pCache))  119             {  120                 *ppvObject = static_cast<IDataSourceCache *>(pCache);  121  122                 return S_OK;  123             }  124         }  125     }  126  127     return baseISAPI::QueryService(guidService, riid, ppvObject);  128 }  129  130virtual void OnThreadTerminate(DWORD /*dwThreadId*/)  131 {}  132 }; 
end example
 

The difference between the code in Listing 8-3 and what you saw earlier is actually quite minimal. Let s look at these differences line-by-line :

  • Lines 8 through 11: For every thread you have in your thread pool, you want to create and maintain one database connection. This will save you the overhead of connecting to the database each time you read or write to it. In many cases, especially when the amount of data being written is small (as it will likely be in this case), the time necessary to connect to the database is actually the dominant time. As usual, any time you want to do anything on a per-thread basis, you want to create a class that derives from CIsapiWorker .

  • Lines 34 through 42: The only difference between this class declaration than what you ve seen before is that you ll use your CIsapiExtensionWorker class instead of the default CIsapiWorker class.

  • Lines 50 and 51: Earlier, you used the CMemSessionServiceImpl implementation class to create your session state service type. In order to use database-backed session state, you ll change the implementation to use CDBSessionServiceImpl instead.

  • Lines 67 through 81: The initialization for your database-backed session state service is slightly different. You need to supply a connection string to the database that you re using. This connection string is built from the ATL Server Project Wizard. Keep in mind that for security reasons, you should always use Windows Integrated security instead of embedding credentials in the connection string.

Those are the only differences between using memory-backed session state and database-backed session state. The process of actually storing and retrieving values from either type of session state is identical.

One last important point: Before you can use the database-backed session state, you have to set up the database schema that it will use to store the session values. The schema that ATL Server requires can be created by executing the SessionServices.sql file located in the VC7\bin directory of your Visual Studio .NET installation. You can run this .sql file against any database that you deem suitable.

As we mentioned before, you use database-backed session state through the same ISession interface that you use any session state implementation in your ATL Server application. The only difference is that session variables aren t automatically removed from the database. So, when you re done with your session, you have to call ISession::RemoveAllVariables to remove the values of that session s variables.




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