Share via


ISAPI Programming Tips

OverviewHow Do I

It is important to remember that your ISAPI application is running in the context of a service on NT. This means your code must be thread safe, it must be reentrant, and it has no user interface on the server.

  • Watch your resource usage. Release acquired resources. For example, you might not be able to keep an ODBC connection for the life of the server.

  • Be thread safe. Use synchronization objects to protect data. Don’t use global variables.

  • Write your filters to use the appropriate priority notification, at the lowest priority possible. A filter to authorize users may need to run at high priority. In this case, if a user fails authorization, the other lower-priority filter notifications will never be called.

  • Be efficient in your filter processing. Filter functions can be called for all server requests, and an inefficient filter could slow down processing noticeably. If you are not using all the filter notifications you originally specified, alter dwFlags in GetFilterVersion to delete unneeded notifications.

  • Do not display dialog boxes on the server, which may be running unattended with no one to click OK. Instead, log error information to a log file or a database.

Server Extension (ISA) Memory Management

If you want to allocate data on a per-call basis, you must use the data carefully within a synchronization object. The example below demonstrates overriding the HttpExtensionProc member function and using a critical section to associate per-call data with the ConnID. The base class is then called to process the request. Any member functions that use the data must protect it with a synchronization object. Upon return from HttpExtensionProc processing, the data for that ConnID is freed.

// in your .H file, declare variables and override HttpExtensionProc
class CISAPIWizExtension : public CHttpServer
{
    // per-call data
    CString* pData;
    CCriticalSection m_critSect;
    CMap < HCONN, HCONN&, CString*, CString* > m_map;

    // allocate per-call data
    DWORD HttpExtensionProc(EXTENSION_CONTROL_BLOCK* pECB);
};

// in your .CPP file, override HttpExtensionProc,
// to set per-call data for this connection
DWORD CISAPIWizExtension::HttpExtensionProc(EXTENSION_CONTROL_BLOCK* pECB)
{
    DWORD dwResult;
    // allocate per-call data
    // using the data type of your choice
    pData = new CString("whatever data you want");
    m_critSect.Lock();
    m_map.SetAt(pECB->ConnID, pData);
    m_critSect.Unlock();


    // call base class to do the work
    // remember, any member functions
    // that use the per-call data
    // must also access it within critical sections
    dwResult = CHttpServer::HttpExtensionProc(pECB);

    // delete per-call data
    m_critSect.Lock();
    m_map.Lookup(pECB->ConnID, pData);
    m_map.RemoveKey(pECB->ConnID);
    delete pData;
    m_critSect.Unlock();
    return dwResult;
}

Filter Memory Management

Most filters will register for the end of net session event. You can use this event to recycle any buffers used by that client request. For performance reasons, most filters will probably keep a pool of filter buffers and only allocate or free memory when the pool becomes empty or so large it no longer saves on the overhead of memory management. To allocate memory that is automatically freed when the communication with the client is terminated, use . Using AllocMem presents a tradeoff: It is a valuable memory management tool, but it can affect performance, as noted earlier.

See Also Internet First Steps: Application Design Choices, ISAPI: Debugging, Internet: Where Is..., ISAPI: Debugging