Using modules for classic ASP with II7 Integrated Mode

Published Thursday, January 22, 2009 7:39 PM

Using ASP.NET HttpModules it is very easy to perform additional operations before and after requests. Since this post is not focused entirely on modules I’ll direct you to this very neat link about modules.

One of the things that we can do to show how modules work is to add headers or footers to the Response. However for those of us who have ever attempted to do this with classic ASP, the story is a little less straight forward. If the module adds a custom header and footer to the response, on viewing the page you might find that the response is truncated or incomplete. Let’s see a little bit of this in action.

Make sure you’re using IIS in integrated mode. Create a new ASP.NET website and create a new class. Let’s call it HelloWorldModule.cs.

using System;
using System.Web;
using System.Collections;
using System.Collections.Specialized;


/// <summary>
/// Summary description for HelloWorldModule
/// </summary>
public class HelloWorldModule : IHttpModule
{
    public String ModuleName
    {
        get { return "HelloWorldModule"; }
    }

    // In the Init function, register for HttpApplication 
    // events by adding your handlers.
    public void Init(HttpApplication application)
    {
        application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
        application.EndRequest += (new EventHandler(this.Application_EndRequest));

    }

    // Your BeginRequest event handler.
    private void Application_BeginRequest(Object source, EventArgs e)
    {
        HttpApplication application = (HttpApplication)source;

        HttpContext context = application.Context;

        context.Response.Write(
            "<h1><font color=red>HelloWorldModule: Beginning of Request</font></h1><hr>");

    }

    // Your EndRequest event handler.
    private void Application_EndRequest(Object source, EventArgs e)
    {
        HttpApplication application = (HttpApplication)source;
        HttpContext context = application.Context;
        context.Response.Write(
            "<hr><h1><font color=red>HelloWorldModule: End of Request</font></h1>");


        try
        {
            int cookiesCount = context.Response.Headers["Set-Cookie"].Split(';').Length;
            int count = context.Response.Cookies.Count;
            context.Response.Write("Number of Cookies : " + count + "</hr>");
        }
        catch (Exception ex)
        {
            context.Response.Write("Failed" + "</hr>");
        }

    }

    public void Dispose()
    {
    }

    public HelloWorldModule()
    {
        //
        // TODO: Add constructor logic here
        //
    }
}

You can see that the Application_BeginRequest and Application_EndRequest methods add a header and footer to the Response. The Application_EndRequest method also displays the number of cookies added.

Next we would need to register the module with our web.config. We can do that by adding the following between the <httpModules> and <httpModules/> nodes.

<add name="HelloWorldModule" type="HelloWorldModule"/>

Now let’s create two very simple pages. One using classic ASP and the other using ASP.NET and see the difference in how the response is displayed. Both pages in essence do the same thing i.e. set the values of two cookies.

Here’s how our ASP.NET page would look:

<%@ Page Language="C#"%>

<!DOCTYPE html PUBLIC 
"-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <% 
        Response.Cookies.Set(new HttpCookie("foo", "bar"));
        Response.Cookies.Set(new HttpCookie("foo2", "bar2"));
     %>    
    </div>
    </form>
</body>
</html>

And now our classic ASP page:

<%
Response.Cookies("foo") = "bar"
Response.Cookies("foo2") = "bar2"
 %>

 

Let’s go ahead and browse both these pages now. The ASP.NET page first … which looks exactly how we expected. And then the ASP page which doesn’t quite look like we wanted it to.

The reason? ASP and a lot of other ISAPI extensions are likely to believe that they are the sole content generator for the response. And ASP.NET being a newer programming interface, while modifying the response, needs to be aware of this. Classic ASP sets the “Content-length” equal to the length of the content on the asp page and of course only that number of characters from the response are displayed when the page is browse. The additions made to the response increase the length of content but never inform ASP, since there really isn’t any way ASP.NET could talk to ASP directly. Luckily, there are adjustments so make ASP behave like we would want it to. In this case, that would be adjusting the value of “Content-length” or removing it.

So let’s remove the Content-Length header from the response in the Application_EndRequest method of our module. Now it should look like:

private void Application_EndRequest(Object source, EventArgs e)
    {
        HttpApplication application = (HttpApplication)source;
        HttpContext context = application.Context;
        context.Response.Write(
"<hr><h1><font color=red>HelloWorldModule: End of Request</font></h1>");
        

        try
        {
            int cookiesCount = context.Response.Headers["Set-Cookie"].Split(';').Length;
            int count = context.Response.Cookies.Count;
            context.Response.Write("Number of Cookies : " + count + "</hr>");
        }
        catch (Exception ex)
        {
            context.Response.Write("Failed" + "</hr>");
        }
        context.Response.Headers.Remove("Content-Length");

    }

And browse … Looks better, doesn’t it? Depending upon your application and its use there might be other adjustments that you might need to make. The point to take home is when using classic ASP with newer programming interfaces one needs to be careful of what ASP is aware of and what it isn’t so that adjustments can be made to get the desired results.

Let me know if you have any questions!

Assad Safiullah

Software Development Engineer in Test

ASP.NET QA Team

Comments

# agincu said on Monday, July 20, 2009 10:35 PM

Cound it be done with IIS6?

For classic ASP, I use wildcard mapping on Windows 2003, but it seems not execute the EndRequest event handler.

Is this the limitation under IIS6?

Should I quit using HttpModule?

BTW, your article is great!

Leave a Comment

(required) 
(required) 
(optional)
(required)