Observing the User Experience: A Practitioners Guide to User Research
In this section you ll take a look at the architecture of an ATL Server application. We walk you through the basics of processing a request and then drill down in further detail into each of the components .
First, a client makes an HTTP request to a server (running Windows and IIS), as shown in Figure 1-1.
When the server receives the request, it passes it on to the appropriate ISAPI (extension) DLL. In Figure 1-2, you can see that the request is handed off to MyISAPI.dll.
At its heart, the ISAPI DLL is designed to dispatch requests to the appropriate application DLL (see Figure 1-3). But the ISAPI DLL is capable of doing much more than this. Because it s common to all your application DLLs (all the application DLLs in any given virtual root [vroot]), it s a great place for providing cross-application features. An obvious example of a feature suitable for the ISAPI DLL is the various caches, so that each application DLL doesn t have to keep its own cache. Every vroot on your server that you enable has to point to one ISAPI DLL that will handle and dispatch the requests to this vroot.
The ISAPI DLL is designed to dispatch requests, and in this case (an ATL Server application), the ISAPI DLL will dispatch the request to an appropriate application DLL. The application DLL is where the application logic resides. The reason for separating application DLLs from the ISAPI DLL is that the ISAPI DLL gets locked by IIS; therefore, in order to change the ISAPI DLL, the server needs to be restarted (via iisreset). Because restarting IIS on a server is a procedure that most companies don t want to do often (if the IIS process is resetting, then you ll lose all incoming client requests), ATL Server provides application DLLs that can be changed without needing to restart IIS, through a process referred to as hot swapping. In fact, the system has been designed so that when you change an application DLL, requests currently being processed will use the old application, and new requests will go to the new one. Not only does ATL Server provide this functionality, but it also handles flushing the DLL cache and resetting other appropriate components so you can make the change seamless.
Of course, if you really want to, you can combine the application DLL and ISAPI DLL into a single DLL, but outside of the file maintenance issue, there s no real advantage in doing this and you ll lose the ability to hot swap your application DLL.
The application DLL also has the ability to work with ATL Server stencil or server response file (SRF) files. SRF is a new file type created by the ATL Server team that is designed to make it easy to cleanly separate static and dynamic HTML content. SRF files are basically HTML files with dynamic tags that indicate where dynamic content is to be injected. (The stencil processor allows your application to spit into the HTML stream whenever a dynamic tag occurs.)
Figure 1-4 shows how SRF files fit into the picture with ISAPI and the application DLL.
It s important to remember that not only can these features (and subfeatures) be used separately in any appropriate applications, but also they re completely extensible. This means that whenever you want to add or modify the functionality they provide, it s always possible to do so. In the next sections, you ll briefly examine each of these components.
SRF Basics
SRF allows developers to easily create the user interface (UI) aspects of their Web applications. The file allows for the mixing of static HTML content with dynamic HTML content using the double brace tag syntax: {{}}. SRF also was designed to allow teams to completely separate layout design from development. This key design goal means that Web designers can work solely in the SRF files and developers can work solely in the code. Here s an example of a basic SRF file:
<html> <head> Basic SRF </head> <body> Hello </body> </html>
We ll come back to the first tag in the preceding sample, but for now we d like you to focus on the second tag. The second tag, , will be associated with a method in your handler class (which we explain in a moment ”for now, just think of it as any C++ method in a C++ class). The stencil processor is designed (like the rest of ATL Server) to be very efficient. In the interest of efficiency, the ATL Server design team decided to make the stencil processor parse an SRF file only once (i.e., it will only move forward through an SRF file, never backward). The advantage of this design is great performance, and the disadvantage is that you can t do some of the things you can with scripting files, such as have variables and variable parameters. This actually helps push you to keep application logic in the code and only layout information in the SRF file. The SRF file will make a call to the associated function (in your handler class) when it parses a tag.
You may be wondering why the double braces are good for denoting tags. Well, there are two main reasons. First, the braces are ignored by most HTML editors, which means that Web designers can focus on developing layout without worrying about dynamic content. Second, the braces can be placed anywhere within an HTML file, including within HTML tags (as you ll see later on), again without disturbing the use of layout or other HTML tools.
The SRF syntax includes some basic flow control and, as always, the model is completely extensible. The existing flow control, as well as the extensibility mechanism and everything else you may want to know about SRF files, is covered in Chapters 2 and 17.
Now let s examine the first tag in the preceding sample: . The first tag is required in all SRF files, and it must be the first noncomment tag. This is the handler tag, and it tells the stencil processor which application DLL will be handling requests for this file. It also tells the processor which class in that application DLL will handle requests. You can have more than one handler in an SRF file, but you must have at least one.
You can see that the BasicSrf DLL will handle requests for the example SRF file. In the code in our application DLL, we ll use a handler map to map the string Example with a handler class in our application. This class will then contain another map that will map the string World with a method in that class. To better understand how this works, you ll look at application basics and handler classes in the next section.
Application Basics
The application DLL is where the logic of your application resides. A single application DLL can contain one or more handlers. At this point, it s probably worth explaining exactly what a handler is. A handler is simply a class that derives from CRequestHandlerT (or, at a lower level, IRequestHandlerImpl ) and is exposed via a handler map. A handler map is simply a mapping between text strings and the name of a class. The code for the handler map looks like this:
BEGIN_HANDLER_MAP() HANDLER_ENTRY("Example", CExampleHandler) END_HANDLER_MAP()
The following code shows an example of an actual request handler:
class CExampleHandler : CRequestHandlerT<CExampleHandler> { public: BEGIN_REPLACEMENT_METHOD_MAP(CExampleHandler) REPLACEMENT_METHOD_ENTRY("World", OnWorld) END_REPLACEMENT_METHOD_MAP() HTTP_CODE ValidateAndExchange { return HTTP_SUCCESS; } HTTP_CODE OnWorld { m_HttpResponse << "World"; return HTTP_SUCCESS; } };
In this case, you can see that we re associating the text string Example with the class CExampleHandler . You ll notice that within the handler itself we have a REPLACEMENT_METHOD_MAP map that maps the text string World with a method, in this case the OnWorld method. Thus, whenever we use the tag in an SRF file associated with this handler class (e.g., the SRF file from the previous example), the OnWorld method will be called with the capability to inject characters into the HTML stream at the point where the tag occurs.
We can easily rewrite this handler to work with the new Visual C++ .NET attributes. We discuss attributes in more detail later on, but for now you should understand that they re basically a new design philosophy in Visual C++ that allows you to focus on your application logic and not on implementation details. You can view them as compile-time wizards. The compiler tells the attribute provider whenever it sees an attribute (and what the attribute is). When the compiler has finished parsing the class, it calls the attribute provider, which in turn injects code based on information about the class and its methods that it learns from the compiler. This allows for very rich and powerful code injections. You can view the injected code by using the /Fx compiler switch.
You can see that this attribute feature not only simplifies the implementation, but also helps create a more logical structure to the code, which makes the code easier to read and maintain. (Note, for example, that we no longer need the maps that generally exist in the .cpp file and not the header.) Here s an example of a request handler created using attributes:
[ request_handler("Example") ] class CExampleHandler { public: HTTP_CODE ValidateAndExchange { return HTTP_SUCCESS; } [ tag_name(name= "World") ] HTTP_CODE OnWorld() { m_HttpResponse << "World"; return HTTP_SUCCESS; } };
You can see in the preceding code that the attributes are denoted by square brackets [] and go on top of the class or method on which they interact. You ll see a lot more attributes throughout this book. In Visual C++ .NET, there are attributes to help with COM development, database development, ATL Server Web application development, and ATL Server Web service development.
Now that you understand the basics of handlers and SRF files, in the next section you ll explore the basics of the ISAPI DLL.
ISAPI Basics
Your ISAPI DLL is the DLL that receives all incoming requests (from IIS) and dispatches them to the appropriate application DLL. Because it s global to all your application DLLs, it s the perfect place for putting cross-application logic. (Application DLLs are spun off a thread pool per request, so if you want to store information permanently between requests, you need to put the information in a global store located in a permanent place such as the ISAPI DLL.) The permanent information and the cross-application logic includes, but isn t limited to, items such as your caches, session, and PerfMon counters.
You ll notice that there s no binary version of the ISAPI DLL; instead, the ATL Server Project Wizard generates the code for a simple yet fully functional ISAPI DLL for you. This allows (and encourages) you to customize your ISAPI DLL as you see fit. For more information on how to do this, please refer to Chapter 4.
The basic ISAPI DLL (with attributes) looks like the following:
[ module(name="Example", type="dll") ]; [ emitidl(restricted) ]; // The ATL Server ISAPI extension ExtensionType 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); }
Let s briefly look at what the three main functions here are for. The first function is HttpExtensionProc . This is your main application (i.e., the main entry point for your application). In the case of ATL Server, this function will queue HTTP requests on the thread pool and return HSE_STATUS_PENDING on a successful queue and HSE_STATUS_ERROR otherwise .
The second function is GetExtensionVersion . This function is called when your application is invoked on the server for the first time. It s used to exchange version numbers : the version your application is coded against and the version on the server. It also provides a short text description of your application. Because it s called on the first initialization of your application, it s useful for any initialization required, including thread pool and cache initialization. This function returns TRUE on success and FALSE on failure.
The third function is TerminateExtension . This function is called only when your application is terminated and is used for any cleanup and shutdown tasks required by your application. This includes freeing up any resources that your extension might have accessed. This function returns TRUE on success and FALSE on failure.
Other Features of ATL Server
This section provides a brief look at some of the features that ATL Server provides. Although this section isn t by any means a complete description, it should give you an excellent feel for the sort of functionality provided by ATL Server. We go into much more detail about each of these features (as well as some others) later in the book.
ATL Server provides a number of caches that you can customize for your specific application. Some of the out-of-the-box caches are as follows :
-
The database connection cache allows you to cache your database connections and save network trips to your SQL Server machine.
-
The file cache is very useful for caching files that can be quickly returned to the user by IIS. SRF files can be (and are by default) cached into files after their first processing and then passed back quickly as static files by IIS.
-
The BLOB cache allows you to store binary large object (BLOB) data.
The session state facilities provided by ATL Server can back session state to any store that you desire . There are two storage techniques fully implemented for you, one being memory-backed session state and the other being database- backed session state. Memory-backed session state is great for single Web-server situations, as it provides a fast and efficient way of storing session. Database-backed session state is more appropriate for Web farm systems, as it s less vulnerable to corruption (through system failure, for example) than memory-backed session state. The nice thing about the session state is that the interfaces are identical, so moving between these two types of storage (or to or from your own custom storage) is seamless and requires changes to only two or three lines of code.
The ATL Server thread pool is used to take the burden off IIS s threads. Because IIS has a fixed number of threads and will block all incoming requests if these threads are busy, it s best to move all but static requests off to your own thread pool. The ATL Server thread pool is completely customizable ”it s created at start-up and is dynamically resizable. The threads in this pool are completely asynchronous, so if you need to wait on an expensive call, you can send the thread back to the pool to process incoming requests and keep your Web application running at maximum efficiency. The thread pool is an excellent example of a feature that can be used outside of Web applications. For example, you could use this thread pool to handle DirectPlay events for a DirectX application (this was done by some of the developers on the ATL Server team).
The cookie helper functions are designed to make working with cookies easy and efficient. ATL Server lets you work with both single value and multiple value cookies. It provides simple set and lookup functions to make working with cookies trivial.
ATL Server also provides query and form helper classes. These classes are designed to help with all the tasks associated with working with query and form data. These tasks include validating the form and query parameters, and exchanging form and query parameters into member variables in your class.
The Simple Mail Transfer Protocol (SMTP) support provided by ATL Server makes it easy to compose and automatically send e-mail. SMTP is perfect for creating automatic confirmations and status messages.
The Web service support allows you to create unmanaged Web services. The ATL Server model takes advantage of the fact that Web services (like COM) rely on having an interface and an IDL. This knowledge has been used to make Web service development similar to (attributed) COM development. This protection of investment (in both knowledge and code) extends to making it easy to expose objects as both Web services and COM components. Thus, with ATL Server it becomes easy to expose existing or newly written COM components as Web services, as well as newly written Web services as COM components.
Web services represent a new direction in software development, and ATL Server is the tool that helps unmanaged C++ developers easily move to embrace this new technology if they so desire.
With the introduction of attributes, both COM and Web service development has become a lot faster, more readable, and more maintainable .
NTLM security support allows developers to take advantage of the security of the Windows NT Logon Manager. This feature makes it easy to secure sites with Windows security, which is great for securing intranets and parts of your site that control administration features or contain privileged information.
There are also now wrapper classes for generating Windows PerfMon counters. PerfMon is the perfect way to store statistics about your Web site. The provided counters measure common statistics such as site hits and downloaded files, and the helper classes make it easy for you to add your own counters.
The ATL Server browser capabilities support is designed so that developers can take advantage of the capabilities of modern browsers without denying access to users with older browsers. An initialization file is used to set up the capabilities for different browsers, making it easy to modify browser support over time (including adding support for new browsers).
Along with the functionalities described in this section, ATL Server provides myriad of classes designed to make Web application development easier. Many of the features mentioned here build on lower-level ATL Server functionality. This lower-level functionality is almost always exposed to the developer so that he or she can build customized high-level features off these low-level bases. A good example of a great lower-level feature is the request/response classes, which are designed to make handling requests and generating responses much more efficient.
Категории