Developing Your Own Web Service Handler ASP.NET

In this section, you will learn how to develop your own web service handler and overcome the limitation of the ASP.NET AJAX Frame work’s built-in ASMX handler.The first step is to add asynchronous method invocation support to web methods. Then add . NET 2.0 transactions on the synchronous method calls. Un fortunately, I haven’t found a way to make asynchronous functions transactional.

The third step is to set the cache policies after invoking the web method (be careful not to over write the cache policies that the web method has already set for itself).Finally, some minormodifications are needed to generate responses with a proper Content-Length header,which helps browsers optimize a response’s download time by using persisted connections and less strict exception handling to prevent event logs being flooded with errors.

Basics of Asynchronous Web Service Handlers

First you need to create a HTTP handler that will intercept all calls to web services.You need to map that handler to the *.asmx extension in web.config’s <httphandlers> section. By default, ASP.NET AJAX will map its Script Handler,which handles the *.asmx extension, so you will have to replace that with your own HTTP handler.

In the accompanying source code, the AJAXASMXHandler project is the new web service handler.ASMXHttp Handler.cs is the main HTTP handler class. The ASMXHttp Handler class implements IHttp Async Handler. When this handler is invokedduring calls to web services, the ASP.NET Framework first calls Begin Process Request.In this function,the handler parses the requested URL and finds out which web service and web method to invoke(see Example ).

The ASMX Http Handler class Begin Process Request’s function starts the execution of a request asynchronously

WebServiceDef is a class that wraps the Type class and contains information about a web service’s type.It maintains a collection of Web Method Def items where the item contains the definition of a web method.Web Method Def has the name of each method, the attributes associated to the method, whether it supports HTTP GET or not, and a reference to the Begin and End function pair, if there’s any.If there’s no Begin and End pair, the function is executed synchronously, as in Example.Both of these classes are used to cache information about web services and web methods, so there’s no need to repeatedly use reflection to discover the metadata.

BeginProcessRequest: synchronous execution of web methods when there’s no Begin and End pair

Begin Process Request returns immediately when the method is executed synchronously.It returns an Asmx Handler Sync Result instance that indicates the request has executed synchronously and there’s no need to fire End Process Request.Asmx Handler Sync Result implements the IAsync Result interface.It returns true from the Completed Synchronously property (see Example ).

Asmx Handler Sync Result implements IAsync Result and returns true from the Completed Synchronously property. It also returns a Manual Reset event with state set to true indicating that the call has completed.

Going back to BeginProcessRequest, when there is a Begin and End pair, it calls the BeginXXX method of the web method and returns from the function. Execution goes back to the ASP.NET Framework, and it returns the thread to the thread pool.

Dynamically Instantiating a Web Service

Web services inherit from System.Web.Services.Web Service,which implements the IDisposable interface. Activator.Create Instance is a .NET Frame work class that can dynamically instantiate any class from its type and return a reference to the object.In Example, a web service class instance is created, and the IDisposable interface referenc is used.IDisposable interface is used because we need to dispose of it when we are done.

Example show the preparation step for calling the Begin XXX function on the web service.First, all the parameters are properly mapped from the request parameters except for the last two parameters, where one is the AsyncCallback and the other is the object state.

BeginProcessRequest: Preparing to invoke the BeginXXX web method on the web service

Once the preparation is complete,the BeginXXX method is invoked.Now the Begin XXX method can execute synchronously and return immediately. In that case,you need to generate the response right out of Begin XXX and complete execution of the request. But if Begin XXX needs more time to execute asynchronously, then you need to return the execution to the ASP.NET Framework so that it can put the thread back into the thread pool.When the asynchronous operation completes, the End Process Request function will be called back and you resume processing the request (see Example).

BeginProcessRequest:Invoke the BeginXXX function on the web service and return the IAsync Result

BeginProcessRequest: Invoke the BeginXXX function on the web service and return the IAsyncResult (continued)

The End Process Request function is fired when the asynchronous operation completes and the callback is fired.For example, if you call an external web service asynchronously inside the Begin XXX web method, you need to pass an Async Call back reference. This is the same callback that you receive on Begin Process Request.The ASP.NET Frame work creates a call back reference for you that fires the End Process Request on the HTTP handler. During the End Process Request, you just need to call the End XXX method of the web service, get the response, and generate output (see Example ).

EndProcessRequest function of ASMXHttpHandler

EndProcessRequest function of ASMXHttpHandler (continued)

When the EndXXX web method completes, you will get a return value if the function is not a void type function.In that case, you need to convert the return value to a JSON string and return to the browser. However, the method can return an XML string also instead of JSON. So, just write the string to the HttpResponse (see Example ).

TheGenerateResponse function of ASMXHttpHandler prepares the response JSON or the XML string according to the web method definition

TheGenerateResponse function of ASMXHttpHandler prepares the response JSON or the XML string according to the web method definition (continued)

Basically this is how a webmethod is executed synchronously and asyn- chronously and response is prepared.

Although there are more complicated steps in preparing the web service and web method definition, serialization /deserialization of JSON, and mapping deserialized objects to input parameters of web method,I will skip these areas. You can review the code of the HTTP handler and learn in detail how all these work.A lot of code has been reused from ASP.NET AJAX; I also used the JSON serializer that comes with the Framework.

Adding Transaction Capability to Web Methods

Up to this point, the web method execution doesn’t support transaction. The[Transactional Method] attribute defines the scope of transaction to use, as well as the isolation level and time out period (see Example).

An example of implementing a transactional web method

An example of implementing a transactional web method (continued)

A web method that has the TransactionalMethod attribute will automatically execute inside a transaction.We will use .NET 2.0 transactions here. The transaction management is done entirely in the HTTP handler and thus the web method doesn’t have to do anything. The transaction is automatically rolled back when the web method raises an exception; otherwise,the transaction is committed automatically.

The ExecuteMethod function of the ASMXHttpHandler invokes web methods synchronously and provides transaction support.Currently, transaction support for asynchronous methods has not been implemented because execution switches from one thread to another, so the TransactionScope is lost from the thread local storage (see Example ).

The Execute Method of AS MX Http Handler invokes a web method
synchronously within a transaction scope

The Execute Method of AS MX Http Handler invokes a web method
synchronously within a transaction scope(continued)

Example shows a web method executing properly and generating a response. The web method executes within a transaction scope defined in the Transactional Method attribute. But when the web method raises an exception, it goes to the catch block where a exception message is produced. Finally, the Transaction Scope is disposed and it checks whether it has been already committed.If not, Transaction Scope rolls back the transaction (see Example)

Execute Method: When a web method raises an exception, the transaction is rolled back

The entire transaction management is inside the HTTP handler, so there’s no need to worry about transactions in web services.Just add one attribute, and web methods become transaction enabled.

Adding Cache Headers

The previous section “Modifying the ASP.NET AJAX Framework to Handle Web Service Calls” described how ASP.NET AJAX initializes the cache policy before invoking the web method.

Due to a limitation in Http Cache Policy, once the MaxAge is set to a value, it cannot be increased. Because ASP.NET AJAX sets the Max Age to zero,there’s no way to increase that value from within the web method code. Moreover, if you use Fiddler or any other HTTP inspection tool to see responses returned from web service calls, you will see the responses are missing Content-Length attribute.

Without this attribute, browsers cannot use HTTP pipelining, which greatly improves the HTTP response download time.

Example shows some additions made to the GenerateResponse function to deal with the cache policy. The idea is to confirm that the web method has already set some cache policy in the HttpResponse object so it will not change any cache setting. Other wise, it will look at the WebMethod attribute for cache settings and then set the cache headers.

The Generate Response function handles cache headers properly by
respecting the cache policy set by the web method

The Generate Response function handles cache headers properly by
respecting the cache policy set by the web method(continued)

The IsCacheSet function checks to see whether there’s been any change in some of the common cache settings. If there has been a change, then the web method wants to deal with the cache itself,and GenerateResponse does not make any change to the cache policy (see Example ).

The Is Cache Set function checks whether the cache policy has already been set by the web method

The Is Cache Set function checks whether the cache policy has already been set by the web method (continued)

Exception Handling

Problem:The ASMX handler kept firing exceptions.

Solution:Used the reflection-based maxAge hack in the “Caching Web Service Responses on the Browser” section.

On an earlier portal project I worked on, our web servers’ event logs were being flooded with this error:

Request format is un recognized for URL unexpectedly ending in /Some Web Service Method.

In ASP.NET AJAX 1.0 version,Microsoft added a check for all web service calls to have Content-Type: application/json in the request headers.Unless this request header was present,ASMX handler fired an exception.This exception was raised directly from the Script Handler,which handled all web service calls made via ASP.NET AJAX. This resulted in an Un handled Exception and was written in the event log.

This is done for security reasons; it prevents someone from feeding off your web services.For example, you might have a web service that returns some useful information that others want.So, anyone could just add a <script> tag pointing to that web service URL and get the JSON. If that web service is a very expensive web service in terms of I/O and/or CPU, then other web sites feeding off your web service could easily bog down your server.

Now,this backfires when you have HTTP GET supported web service calls that produce response headers to cache the response in the browser and proxy.For example,you might have a web method that returns stock quotes.You have used response caching so the browser caches the response of that web method, and repeated visits do not produce repeated calls to that costly I/O web service. Because it has a cache header, proxy gate ways or proxy servers will see that their client users are requesting this frequently and it can be cached.So, they will make periodic calls to that web service and try to precache the headers on behalf of their client users.However,during the precache process, the proxy gateways or proxy servers will not send the Content-Type: application/json header. As a result, an exception is thrown and your event log is flooded.

The reason why this went undetected is because there’s no way to make a HTTP GET response cacheable on the browser from web service calls unless you do the reflection-based maxAge hack in the “Caching Web Service Responses on the Browser” .

So, the AS MX Http Handler just returns HTTP 405 saying the call is not allowed if it does not have the application/json content type. This solves the event log flood problem and prevents browsers from getting a valid response when someone uses a <script> tag on your web method.

Using the Attributes

You have seen that the Begin XXX and End XXX functions don’t have the [Web Method] attribute, but instead only have the [Script Method] attribute.If you add Web Methodattribute, the Ajax JavaScript proxy generator will unnecessarily generate function wrappers for those methods in the JavaScript proxy for the web service. So, for the Java Script proxy generator, you need only to put the WebMethod attribute on the XXX web method.Moreover,you cannot have a WebMethod attribute on BeginXXX, EndXXX, and the XXX functions at the same time because the WSDL generator will fail to generate.

So, the idea is to add the Web Method attribute only to the XXX function, and the Java Script proxy generator will generate a Java Script function for the web method and add only the Script Method attribute on the BeginXXX and EndXXX functions.

Handling the State Object

The last parameter passed in the BeginXXX function, the object state parameter,needs to be preserved.It contains a reference to the HttpContext, which is needed by the ASMX handler to call the EndXXX function on proper context.So, if you create a custom state object and pass that to a BeginYYY function of some component, e.g., File.BeginRead,then you need to inherit that custom state object from the Async Web Method State class. You must pass the state parameter in the constructor.This way, your custom state object will carry the original state object that is passed down to your Begin XXX function.

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd Protection Status

ASP.NET Topics