Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asynchronous HttpWebRequests and a null HttpContext.Current.Response/Request object

Tags:

I have a web application the relies heavily on web services. Everything with the services is done asynchronously and with AddOnPreRequestHandlerExecuteAsync. Anyhow, most of my calls work just fine, but some are returning from their asynchronous service calls to find a null HttpContext.Current.Response/Request object in the endprerequest, which of course errors the instant I try to use either. Both objects (Response and Request are available/not null on beginprerequest of failing calls and work in the endprerequest of other calls).

Anyone run into similar, or have a guess as to what might be the problem?

Update: Seem to have found a solution, if I create a variable for the HttpApplication on Init(of the HttpModule this all occurs in) the HttpContext can be accessed from that variable.

Update: Passing either HttpApplication or HttpContext.Current on the begin function has the same issue. When passed as part of the "State" of the asynchronous call, they end up null in the end function, even though they are valid in the begin function.

Update: I've added some logging and found that the Asynchronous call I am making is returning correctly, the results are there, the callback function is invoked properly.

like image 484
aepheus Avatar asked Dec 21 '09 18:12

aepheus


1 Answers

I suspect I know the problem you're running into. The answer, almost certainly, is to replace usage of HttpWebRequest with WebClient, and to use the *Async methods of WebClient.

Here's the long explanation: there are two totally different Async programming models: the IAsyncResult Async Pattern and the Event-based Asynchronous Pattern. The IAsyncResult pattern uses BeginXXX and EndXXX methods, uses IAsyncResult instances, uses delegates for callbacks, and supports waiting for completion. The Event-based pattern uses XXXAsync methods to initiate async actions, uses XXXCompleted events instead of callbacks to handle completion, and (this is important to your case) transfers thread-specific context into every callback event handler.

In other words, if you put your callback code inside a XXXCompleted event handler (like WebClient.DownloadStringCompleted), then HttpContext.Current will be populated correctly.

If, however, you use a BeginXXX method (like HttpWebRequest.BeginGetResponse) and a delegate callback, your callback will be executed in the context of a thread that does not guarantee to have the right ASP.NET context attached.

Generally, .NET Framework library classes either use one async pattern or the other. Typically, the lower-level classes (e.g. HttpWebRequest) will use the IAsyncResult pattern, while the higher-level classes (e.g. WebClient) will use the event-based pattern. Some oddball classes (e.g. auto-generated .NET Remoting proxies) will support both patterns, but that's a rarity.

So if it's easy to do, I'd suggest moving to WebClient and event handlers instead of HttpWebRequest and callback delegates. This should solve your problem. If switching to WebClient is too hard, comment and I can probably suggest some more obscure alternatives.

like image 60
Justin Grant Avatar answered Oct 11 '22 23:10

Justin Grant