Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Response.End(), HttpModules and ASP.NET 2.0


:P
On this page:

I'm at DevTeach this week and yesterday I ran my Low Level ASP.NET Session here. I like doing this session – it's one of those that I don't get to do often and it's one of those deep topics that are fun to get wrapped up in for an hour or so <g>.

 

Anyway, it talks about low level aspects of ASP.NET up to the HttpHandler level. In discussion of the ASP.NET pipeline firing off the HttpApplication events, I ran into a somewhat embarrassing snag that I apparently hadn't checked out recently in one of my demos. The events off the HttpApplication object are essentially what drives the pipeline with both direct event hookups and HttpModules that hook into these events via Web.Config and the IHttpModule interface.

 

In the past I've always stressed one thing to be aware of in that ASP.NET can shortcircuit the pipeline if HttpApplication.CompleteRequest() and Response.End() (which used to implicitly call HttpApplication.CompleteRequest). So I have one demo that shows some page logic that calls Response.End(), while I have an HTTP Module hooked up that adds a footer to every page. It was supposed to short circuit and NOT show the footer, but in good Murphy's Law tradition it of course showed the footer… Ooops. <g>

 

The trivial code I use for the sample is something like this:

 

protected void Page_Load(object sender, System.EventArgs e)

{

    Response.Write("<h1>Hello Cruel World</h1>");

 

    if (this.chkResponseEnd.Checked)

    {

        Response.End();

 

        Response.Write("<h1>Goodbye Cruel World</h1>");

    }

}

 

There's a checkbox on the form and when checked Response.End() is called.

 

But alas in ASP.NET 2.0 when I call it, the HTML content added by the module that adds a footer to the page continues to display just fine.

 

Now I can still force the pipeline to short-circuit, but I have to explicitly call on the HttpApplicationInstance and CompleteRequest:

 

HttpContext.Current.ApplicationInstance.CompleteRequest();

Response.End();

 

Now the short circuiting does happen as before.

 

It looks like there's a definite (and welcome) behavior change in ASP.NET that causes Response.End() no longer to short circuit the Http Pipeline. This is a good thing because in most situations you don't actually want the short circuiting to happen. As in this scenario I would much prefer to have the pipeline continue processing and put my footer on the page even though I issued a Response.End().  There maybe other things happening too - compression of output, special formatting - who knows what that should still happen even though the Response has effectively been killed. 

 

It looks like this is what Response.End() does now. But, curious person that I am I wanted to check out what ASP.NET is doing differently here so I dug out Reflector and checked out Response.End:

 

public void End()

{

    if (this._context.IsInCancellablePeriod)

    {

        InternalSecurityPermissions.ControlThread.Assert();

        Thread.CurrentThread.Abort(new HttpApplication.CancelModuleException(false));

    }

    else if (!this._flushing)

    {

        this.Flush();

        this._ended = true;

        if (this._context.ApplicationInstance != null)

        {

            this._context.ApplicationInstance.CompleteRequest();

        }

    }

}

 

Looking at this code I'm actually not sure what ASP.NET is doing to keep the processing of the Pipeline alive. In both of the conditional paths it seems like the Pipeline is in fact short circuited – Thread.Abort() certainly will cause an exception in the application (unless the CancelModuleException holds some significance here) and terminate the request. And the second path calls HttpApplication.CompleteRequest() which as shown above does bypass the pipeline (except for the HttpApplication.EndRequest event which is guaranteed to fire). So it seems odd that the Response.End() call is in fact firing the rest of the events.

 

 

Moral of the story for me: I better double check my demos more carefully under 2.0 <g>. Demonstrating this particular demo will have to include the CompleteRequest() call, which is still important to 'warn' about. If you have criticical behavior in a handler that does things like validation or licensing/limiting of some sort the abillity to short circuit with CompleteRequest() puts a crimp in that scenario as pages can potentially bypass this behavior with some strategically placed code.

 


The Voices of Reason


 

bdiaz
May 10, 2006

# re: Response.End(), HttpModules and ASP.NET 2.0

I had a similar encounter when I was working on an IHttpModule that handled transaction management for ASP.NET applications, which I later contributed to the .NetTiers CodeSmith templates project.

My problem, however, resulted from the use of Response.Redirect(url, true), which also calls Response.End() internally. In my situation, I wanted to check HttpContext.Error to see if there were any unhandled exceptions and then determine if I should commit or rollback. It seems that the exceptions would not bubble up to my global exception handler unless I changed my call to Response.Redirect(url, false);

Have you noticed anything like that before?
Regards,
Bobby

Ernesto Roque
May 22, 2006

# re: Response.End(), HttpModules and ASP.NET 2.0

I've been dealing with this problem for a while. I do want to stop the processing of the Pipeline in an httpmodule but no luck. I had tried HttpContext.Current.ApplicationInstance.CompleteRequest() and Response.End()but still all the events are executing. Any idea?


Rick Strahl
May 22, 2006

# re: Response.End(), HttpModules and ASP.NET 2.0

When are you calling this? Obviously if you call CompleteRequest in a handler or post handler operation it isn't going to stop any events that occur beforehand.

EndRequest is also guaranteed to fire even if CompleteRequest() is called.

Ernesto Roque
May 22, 2006

# re: Response.End(), HttpModules and ASP.NET 2.0

Thanks

In the Application_BeginRequest in my httpModule I want to do something like this based on certain conditions?

Response.Clear();
Response.AddHeader("Refresh", "0;URL=MyUrl"));
Response.End();

The problem is Response.End does not kill the pipeline at this time and all the page events are also called. I tried with CompleteRequest() as well but no luck.

This is something happening in 2.0





Richard Atkins
October 24, 2007

# re: Response.End(), HttpModules and ASP.NET 2.0

Regarding Thread.Abort, I think you'll find if you manually insert this after your Response.End you will be able to single step over it! Response.Redirect and Server.Transfer both call Response.End which in turn calls Thread.Abort but don't count on your thread being aborted (at least not immediately).

Sam
October 19, 2009

# re: Response.End(), HttpModules and ASP.NET 2.0

I am using an HTTP Module.
but after the processing of OnPreRequestHandlerExecute it changes the
url in the address bar of the browser

e.g

http://www.101shaadi.com/Home/Default.aspx

changes to

http://www.101shaadi.com/%28S%283jnd25n3gmzkmdar3udbej45%29%29/Home/Default.aspx

am i missing anything ?

Rick Strahl
October 19, 2009

# re: Response.End(), HttpModules and ASP.NET 2.0

@Sam - apparently you are using Cookie-less Sessions. Cookie-less sessions inject the cookie into the url as part of the ASP.NET request processing.

Har
November 29, 2010

# re: Response.End(), HttpModules and ASP.NET 2.0

I am using both HttpContext.Current.ApplicationInstance.CompleteRequest() and Response.End() but there is no difference between then.
Can you tell the what the basic differnce between in both conditons

Rick Strahl
November 30, 2010

# re: Response.End(), HttpModules and ASP.NET 2.0

@Har - Response.End will throw an exception. CompleteRequest() shouldn't.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024