Writing Web Applications Using ATL Server

team lib

An ATL Server Web application is the ATL Server equivalent of an ASP.NET application. In ASP.NET applications, .aspx files contain HTML that uses custom tags to execute methods in page handler classes. In ATL Server Web applications, SRF files contain fixed HTML and text, and they use SRF tags to execute methods on handler classes. In both cases, the handler code is supplied in DLLs.

Using Attributes

You can write Web applications using pure C++ code, but two attributes have been supplied that make it easier to write handler classes.

The request_handler Attribute

The request_handler attribute marks a class as implementing request handler methods and takes a parameter that sets the alias that SRF files will use to identify the handler class:

 [request_handler("MyHandler")] classCMyhandler { ... }; 

If the preceding class was compiled into Handlers.dll, it would be referred to in an SRF file like this:

 {{//Thehandlertagforthefile}} {{handlerHandlers.dll/MyHandler}} 

Using the request_handler attribute will normally result in the addition of the ATL Server class CRequestHandlerT as a base class and in the addition of a DECLARE_REQUEST_HANDLER macro that exposes the class to IIS.

Note 

I use the word normally because CRequestHandlerT will not be added as a base class if the attributed class already explicitly implements the IRequestHandler interface.

The CRequestHandlerT class has several useful members that you might end up using in your handler code. These members are summarized in Table 7-13.

Table 7-13: Commonly Used Members of the CRequestHandlerT Class

Member

Description

CheckValidRequest

Override this method if you need to check the validity of the request.

ClearResponse

Clears the response object of any headers and buffered data.

FormFlags

Returns one or more of the ATL Server form flags, which specifies how forms are processed . See below for an explanation of form flags.

HandleRequest

You can override this method to provide your own handling for the HTTP request. For the majority of cases, the default implementation is sufficient.

InitializeChild

Called to initialize the handler when an instance is created during processing a subhandler or include tag. This method initializes the request and response objects, and calls ValidateAndExchange .

InitializeHandler

Called to initialize the handler when an instance is created during processing a handler tag. This method initializes the response object, calls CheckValidRequest , initializes the request object, and finally calls ValidateAndExchange .

MaxFormSize

Returns the maximum size of form that will be accepted. You can override this function if the default value of 48 KB is not acceptable.

ServerTransferRequest

Transfers the request to another handler.

ValidateAndExchange

Override this method to initialize the request handler.

m_dwRequestType

Data member holding the type of the request. The value of this member can be ATLSRV_REQUEST_STENCIL , showing that an SRF file was requested ; or ATLSRV_REQUEST_DLL , showing that a handler DLL was requested; or ATLSRV_REQUEST_UNKNOWN .

m_HttpRequest

Returns a CHttpRequest object representing the current request.

m_HttpResponse

Returns a CHttpResponse object used to write the response to the client.

m_pRequestInfo

Returns a pointer to an AtlServerRequest object that holds information about the ATL Server request handling infrastructure. This data will not be used by the majority of users.

The FormFlags method is used to return a value that defines how forms will be processed. The following flag values are supported:

  • ATL_FORM_FLAG_NONE (numerical value 0), which specifies that forms are processed and files will be created

  • ATL_FORM_FLAG_IGNORE_FILES (numerical value 1), which specifies that attempts to upload files will be ignored

  • ATL_FORM_FLAG_REFUSE_FILES (numerical value 2), which specifies that attempts to upload files will be treated as an error

  • ATL_FORM_FLAG_IGNORE_EMPTY_FILES (numerical value 4), which specifies that files of size zero bytes will be ignored

  • ATL_FORM_FLAG_IGNORE_EMPTY_FIELDS (numerical value 8), which specifies that fields with no content will be ignored

The default implementation provided by CRequestHandlerT returns ATL_FORM_FLAG_IGNORE_FILES . You can override this method to define other behavior, ORing together values as required.

The tag_name Attribute

The tag_name attribute establishes the tag name that will be used to call a handler method from within SRF files. Heres an example of a handler function that doesnt take any parameters:

 [tag_name(name="DoThis")] HTTP_CODESomeFunction() { //IfallisOK... returnHTTP_SUCCESS; } 

Defining Handler Methods

Handler methods are simply C++ class member functions. These functions can take arguments, but any arguments passed in will need to be converted because HTTP request arguments are always passed as strings. There are three situations to be considered :

  • The handler takes no arguments.

  • The handler takes one argument that can be parsed automatically.

  • The handler takes more than one argument, the argument is of a type that cannot be parsed automatically, or both.

The first case is trivial because there are no arguments to convert. In the second case, if the method takes a single argument that is a bool , an integer type ( char , short , int , or __int64 , and their unsigned equivalents), or a floating point type ( float or double ), then the conversion from a string will be done automatically. Such methods should be declared to take a pointer of the requisite type, for example,

 //Ahandlerfunctionthattakesaboolean [tag_name(name="PassABool")] HTTP_CODEBoolHandler(bool*pArg) { //IfallisOK... returnHTTP_SUCCESS; } 

This function could be invoked from an SRF file like this:

 {{PassABool(true)}} 

If the first four characters of the parameter passed in evaluate to true with the comparison being case-insensitivea Boolean value of true will be passed to the handler function. If the parameter cannot be converted for some reason, the conversion process will pass an HTTP error back to the client.

Note 

Parameters used with replacement tags cannot contain a closing parenthesis character). Be careful not to choose a character encoding that results in one of the bytes having the same value as an ANSI closing parenthesis (decimal 41, hex 29).

Using Parsing Functions

If the handler method is going to take a single parameter of a type that isnt automatically parsed, or its going to take more than one parameter of any type, youll need to write a parsing function to decode the input data and convert it to a form that can be used by the handler method. The prototype for a parsing function looks like this:

 HTTP_CODEParsingFunction(IAtlMemMgr*pMemoryManager, LPCSTRszArgumentData,  parameterType  **ppArgument); 

The first parameter is a pointer to a memory manager object that you use to allocate memory for the converted argument data. The second parameter is the string containing the data from the HTTP request, and the third parameter is a pointer of the appropriate type, through which the function passes the converted value to the handler function.

You link a parsing function to a handler by using the optional second parameter to the tag_name attribute:

 [tag_name(name="DoThis",parse_func="ParsingFunction")] HTTP_CODESomeFunction(bool*pb) { //IfallisOK... returnHTTP_SUCCESS; } 

The parse_func parameter specifies the name of the parsing function, and this function will automatically be called to parse the input data whenever the handler is invoked. If parse_func is used, the handler method must take an argument of the same type that will be emitted by the parsing function.

A Sample ATL Server Application

The following example shows how to write a simple ATL Server Web application, which has the following characteristics:

  • It has two handler classes, one of which is used as a subhandler.

  • It implements handler methods that do not require custom parsing.

  • It implements handler methods that do require custom parsing functions.

    Note 

    To create and test Web applications, you must have access to a Web server, and have permission to install ISAPI extensions.

Creating the Project

Bring up the New Project dialog box, and in the Visual C++ project types folder select ATL Server Project , choosing an appropriate location and name, as shown in Figure 7-2.

click to expand
Figure 7-2: Creating an ATL Server Web application project

You can see in the ATL Server Project Wizard dialog box shown in Figure 7-3, that there are a number of project settings that can be used to customize the code and the way it is deployed.

click to expand
Figure 7-3: The Project Wizard Overview page for an ATL Server Web application project

The default settings will generate attributed code and will automatically deploy the project to a virtual root on the Web server with the same name as the project. The Project Settings page, shown in Figure 7-4, lets you choose how many DLLs are generated. Remember that an ATL Server application consists of one ISAPI extension DLL and one or more ATL Server handler DLLs. You can choose to build these as two separate DLLs, or to merge them into one. You might want to merge them if you have only one Web application DLL.

click to expand
Figure 7-4: The Project Settings page lets you specify how the DLLs will be generated, as well as deployment details.

When you press Finish to exit from the wizard, youll find that two projects have been generated for you, one for each of the ISAPI and Web application DLLs. The interesting code is in the AtlWebApp.h file, which contains the definition of the handler class and its methods:

 [request_handler("Default")] classCAtlWebAppHandler { private: //Putprivatemembershere protected: //Putprotectedmembershere public: //Putpublicmembershere HTTP_CODEValidateAndExchange() { //TODO:Putallinitializationandvalidationcodehere //Setthecontent-type m_HttpResponse.SetContentType("text/html"); returnHTTP_SUCCESS; } protected: //Hereisanexampleofhowtouseareplacement //tagwiththestencilprocessor. [tag_name(name="Hello")] HTTP_CODEOnHello(void) { m_HttpResponse<< "HelloWorld!"; returnHTTP_SUCCESS; } };//classCAtlWebAppHandler 

The handler class is decorated with the request_handler attribute and given a name of "Default" . This is the name given to the default handler class within a DLL, and it enables writers of SRF files to specify the default handler in a DLL without having to know a specific handler name. The class defines the ValidateAndExchange method, which simply sets the response type to HTML. It also defines a simple replacement tag method named "Hello" , which echoes a string to the HTTP response stream. Replacement tag method names often start with On , although this is only a convention, and not a requirement.

The project also contains a sample SRF file, which uses the test Hello tag:

 {{//useMSDN's "ATLServerResponseFileReference" to learnaboutSRFfiles.}} {{handlerAtlWebApp.dll/Default}} Thisisatest:{{Hello}} 

You should test the Web application at this point by building the project. When the build has finished, you should find that a new directory has been created under the Web servers wwwroot directory, and that this new directory contains three files: the two DLLs and the sample SRF file.

Now open a browser window and navigate to the URL of the SRF file. You should see the output displayed in Figure 7-5.

click to expand
Figure 7-5: The output from the test SRF page that is included in every ATL Server Web application project

Handling Simple Arguments

The following method shows how to implement a handler function that takes a single argument of a type that can be automatically parsed:

 //Amethodthatusesbuilt-inparsing [tag_name(name="Square")] HTTP_CODEOnSquare(short*pVal) { longresult=(*pVal)*(*pVal); m_HttpResponse<< "Squareof " <<(*pVal)<< " is " <<result; returnHTTP_SUCCESS; } 

The method takes an int* as an argument; because int is one of the types that can be automatically parsed, the string parameter passed in with the HTTP request will be converted before the method is called. You can test this method by editing the test SRF file as follows :

 Testingthesquaretag:{{Square(3)}} 
Note 

You dont enclose arguments in quotesconversion to strings is automatic.

Implementing Custom Parsing

If you experiment, youll find that the Square method isnt very satisfactory. It uses the atoi C Runtime Library function to convert the argument, and one of the properties of this function is that it returns zero if it cant perform the conversion. This means that if you give an invalid argument to the Square tag such as {{Square(Tuesday)}} the OnSquare method will be called with an argument of zero. This means that if zero is a valid input value, you cant tell when an invalid argument has been used.

To get around this problem, you can implement a custom parsing function instead of relying on the built-in parsing. The following pair of functions show how to do this:

 //Parsingfunctiontoparseoneshortvalue HTTP_CODEParseSquareData(IAtlMemMgr*pMemMgr,LPCSTRszParams, short**ppDest) { //Ifanyoftheparametersarenull,fail if(pMemMgr==0szParams==0ppDest==0) { returnHTTP_FAIL; } //Verysimplemindedcheck... for(inti=0;i<strlen(szParams);i++) { boolbOK=false; switch(szParams[i]) { case'-': if(i==0)bOK=true; elsebOK=false; break; case'+': if(i==0)bOK=true; elsebOK=false; break; case'0':case'1':case'2':case'3': case'4':case'5':case'6':case'7': case'8':case'9': bOK=true; break; default: bOK=false; break; } if(bOK==false) { //Causes500-servererror returnAtlsHttpError(500,ISE_SUBERR_STENCIL_PARSE_FAIL); } } //Allocatememoryforashort *ppDest=(short*)pMemMgr->Allocate(sizeof(short)); //ConvertusingatoibecauseweknowtheparameterisOK **ppDest=atoi(szParams); returnHTTP_SUCCESS; } //Amethodthatusescustomparsing [tag_name(name="PSquare",parse_func="ParseSquareData")] HTTP_CODEOnSquare2(short*pVal) { longresult=(*pVal)*(*pVal); m_HttpResponse<< "(P)Squareof " <<(*pVal)<< " is " <<result; returnHTTP_SUCCESS; } 

The ParseSquareData function takes the three parameters that all parsing functions must take: a pointer to a memory manager object, a string containing the data from the HTTP request, and a pointer to receive the converted value. If any of those values is null, the function cannot proceed and a fail status code is returned.

The input string is checked to see that it contains only digits, with an optional leading plus or minus sign. If any other characters are found, the function returns an error status code. The AtlsHttpError function builds an HTTP status code out of major and minor parts ; in this case, the minor status code shows that parsing a stencil has failed.

If the input string passes the check, enough memory is allocated to hold a short . The atoi function can be used to convert the string because we know that now a return value of zero represents a real value, rather than an error. The parsing function is then associated with the handler method using the parse_func parameter on the tag_name attribute.

Note 

You must allocate memory for the converted argument using the IAtlMemMgr pointer because the memory manager will take care of deallocating the memory after use.

If you edit the SRF to invoke the PSquare tag and pass an invalid argument, you should see a Server error page displayed in the browser.

 
team lib


COM Programming with Microsoft .NET
COM Programming with Microsoft .NET
ISBN: 0735618755
EAN: 2147483647
Year: 2006
Pages: 140

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