Introduction
In this post, I am going to discuss one of the new features that got enhanced in ASP.NET 4.5. It is Asynchronous HTTP Module and it’s going to be very useful if used meticulously.
First, I would just like to give a brief idea why Asynchronous HTTPModule
s are important?
As we all know, web is stateless
. A Web page is created from scratch every time it is posted back to the server. In traditional web programming, all the information within the page and control gets wiped off on every postback. Every request in ASP.NET goes through a series of events.
Every request is served by an HTTP handler and it goes a series of HTTPModule
s (HTTPPipeline
) which can be read, update the request. A lot of features of ASP.NET like Authentication, Authorization, Session, etc. are implemented as HTTP Module in ASP.NET. Let’s have a view on the Request Processing.
ASP.NET Request Processing : HTTPPipeline and HTTPHandler
Now as you can see, the request is assigned to a thread T1
from the available threads in the thread pool. And the request is passed through several HTTPModule
s and finally served my HTTPHandler
and response is send back with the same thread (T1
).
During the entire processing, the same thread is engaged in serving the same request and cannot be used by any another request till request processing completes. During the request processing, if any HTTPModule
s depends on some entities like I/O based operations, web services, databases queries, etc., then it takes long to complete which makes the thread busy for long which makes ASP.NET thread not do anything during that duration and will be useless. In this kind of scenario, the throughput goes down rapidly.
In the above scenario, synchronous HTTPModule
can degrade the site performance a lot. So if we can make HTTPModule
s as asynchronous, that can increase the throughput a lot. In asynchronous mode, ASP.NET thread gets released as soon as the control gets passed to another component/module, it does not wait. And the thread becomes available in thread pool and can be used to serve another request. When the component completes its assigned task, then it gets assigned to a new ASP.NET thread which completes the request. The flow can be graphically presented as:
Working of an asynchronous HTTPModule
In the above picture, an ASP.NET thread T1
is assigned from threadpool to server the request. When the control gets passed to File System to log message, ASP.NET thread gets released and when message logging gets completed, control passes to ASP.NET and it is assigned to another thread, say T2
from thread pool.
In .NET Framework 4.0, there was some major enhancement made for asynchronous programming model. Any asynchronous operation represents a Task
and it comes under the namespace System.Threading.Tasks.Task
.
In .NET 4.5, there are some new operators and keywords introduced that make life easy for implementing Asynchronous feature. One is async
keyword and await
operator.
These two enable us to write the asynchronous code in a similar fashion as we write for synchronous mode.
And these features can be easily used while writing HTTPModules and HTTPHandlers. We’ll be using these enhancements in writing our custom asynchronous HTTPModule
.
In my sample as depicted in the image, I am creating a module that writes some log messages in a text file for every request made.
So to create a Custom HTTPModule
, create a class library project. And create a class say named LogModule
which implements IHttpModule
. For this, you need to add a reference of Assembly System.Web
.
LogModule
would contain the methods discussed below.
We need to implement two methods Init
and Dispose
that are part of IHTTPModule
interface.
Here first, I have written an asynchronous method that actually reads the information from the request and writes in the log file asynchronously. For this, I have used WriteAsync
of FileStream
.
private async Task WriteLogmessages(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
DateTime time = DateTime.Now;
string line = String.Format(
"{0,10:d} {1,11:T} {2, 32} {3}\r\n",
time, time,
app.Request.UserHostAddress,
app.Request.Url);
using (_file = new FileStream(
HttpContext.Current.Server.MapPath(
"~/App_Data/RequestLog.txt"),
FileMode.OpenOrCreate, FileAccess.Write,
FileShare.Write, 1024, true))
{
line = line + " ," + threaddetails;
byte[] output = Encoding.ASCII.GetBytes(line);
_file.Seek(_position, SeekOrigin.Begin);
_position += output.Length;
await _file.WriteAsync(output, 0, output.Length);
}
}
Here, you can see the await
keyword, what it means...
As per MSDN:
“An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.“
await
is used with some asynchronous method that returns task and is used to suspend the execution of the method until the task completes and control is returned back to the caller to execute further. await
should be used with the last expression of any code block.
And Init
method would be like:
public void Init(HttpApplication context)
{
EventHandlerTaskAsyncHelper asyncHelper =
new EventHandlerTaskAsyncHelper(WriteLogmessages);
context.AddOnPostAuthorizeRequestAsync(
asyncHelper.BeginEventHandler, asyncHelper.EndEventHandler);
}
So apart from the above methods, we need to implement the dispose
method.
Now compile your class library and use the reference in your ASP.NET website. Now as you must be knowing, we need to need to add the entry in the config file. So it’ll be as:
<system.webServer>
<modules>
<add name="MyCustomHTTPModule" type="MyCustomHTTPModule.LogModule, MyCustomHTTPModule"/>
</modules>
</system.webServer>
Now when you run your application, you will see the logs are created in a text file in App_Data folder as mentioned path in the code.
Hope you liked this new feature!
History
- 25th April, 2012: Initial version