Async Pages and HttpContext.Current

While preparing for a talk at Win-Dev this week titled Security Context in Multithreaded Applications, I investigated how much security-related information (CAS demands/denies/permits, call context, thread principal, etc) was propagated from one thread to another using various techniques (ThreadPool.QueueUserWorkItem, async delegates, dedicated threads, etc) on the 1.1 and 2.0 runtimes.  I also explored the new types in Whidbey that let a programmer control context propagation manually.  For the most part, this is great stuff - solving a problem I've long had when trying to implement a custom thread pool on pre-Whidbey CLRs that not only dealt with the mechanics of providing thread pool services, but also tried to allow threads in the pool to temporarily imitate everything about the security-related context of the thread that placed each work request to the queue.

As it turns out, however, if you build async web pages in Whidbey, then you need to be careful about using libraries that depend on dereferencing HttpContext.Current to get their hands on the current HttpContext object.  At least in the Whidbey beta 1 build, it's null, which is a bummer.

It's not catastrophically bad - just really annoying - because most of the time, you're going to be getting a callback from some async technique (delegate, web service call, etc) to an instance method on your Page object.  And the Page instance is still going to be setup just fine.  So if you want to get your hands on the current HttpContext, you can still use this.Context from within an instance method on your page.  But if your page is using any library functions that do stuff like this:

class Widget {
  public static void DoSomething() {
    HttpContext ctx = HttpContext.Current;
    // use ctx...
  }
}

then they won't work if called asynchronously.  You'll need to contrive some means of passing your page's context down to those methods, either explicitly:

void SomePageMethodInvokedAsynchronously() {
  Widget.DoSomething(this.Context);
}

...

class Widget {
  public static void DoSomething( HttpContext ctx ) {
    // use ctx...
  }
}

or implicitly:

void SomePageMethodInvokedAsynchronously() {
  CallContext.SetData(“httpContext“, Context);
  Widget.DoSomething();
}

...

class Widget {
  public static void DoSomething() {
    HttpContext ctx = (HttpContext)CallContext.GetData(“httpContext“);
  }
}

Everything else (principal, CAS perms, etc) propagates fine - just not HttpContext.Current.  So beware.

One last note - I tested this using a simple async delegate, which propagates “everything”.  If another technique is used to get asynchrony (like async web services) then results could be different.  Using a proper async web service is a test for another day...


Posted Oct 27 2004, 12:07 PM by mike-woodring

Comments

Diego wrote re: Async Pages and HttpContext.Current
on 09-05-2005 6:58 AM
Have you checked if this was solved in more recent builds?
Mike wrote re: Async Pages and HttpContext.Current
on 09-06-2005 9:17 AM
HttpContext.Current is still null in the beta 2 release when your callback is invoked. I haven't had a chance to check builds newer than that.
Damon Carr wrote re: Async Pages and HttpContext.Current
on 10-22-2006 4:10 AM
All,

In the production release of course this still happens.

It must be null because you are on a different thread. You loose the HttpContext (and CallContext of course) as soon as the first Delegate returns the IAsyncResult.

As you are immediately returning the original thread to the 'thread-pool' for handling incoming requests, there would need to be some data communicated which would likely not be possible or would be a hack. The new thread you execute on after the first Async delegate would need to get a copy of all the information before the first thread is returned.

I am using the 'Session in View' pattern with NHibernate and Async pages and have run into this. I simply have to close my ISession (and possibly commit any transactions) before the first delegate finishes and returns the IAsyncResult. It's not all that big of a deal as using HttpContext makes your code much harder to test using frameworks like NUnit. CallContext is better but not perfect.

Thanks,
Damon Carr
Mike wrote re: Async Pages and HttpContext.Current
on 10-23-2006 11:03 AM

Actually, it *is* fixed now - so long as you initiate the async processing the correct way. Specifically, any async component/class that uses the async execution context stuff that was added in 2.0.

Check my posts to this blog from October and November of 2005 (on BackgroundWorker, async page/task, and async sql topics).

As long as you use the right async technique from asp.net, HttpContext.Current (and everything else about the original HTTP context) will be correct.

Add a Comment

(required)  
(optional)
(required)  
Remember Me?