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.
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.
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.
Related
I am trying to write async code in asp.net 4.8 but and the problem is that HttpContext is null after returning from await. This means that the async code works correctly which is good, but the HttpContext is needed by the original code.
From the comments in below answer by Darin Dimitrov it shows that HttpContext is having this issue since 4.6.1.
Why is HttpContext.Current null after await?
var domains = HttpContext.Current.Cache.Get("domains") as Dictionary<String, Domains>;
if (domains == null)
{
var x = await TrackingMethods.GetTableForCacheAsync().ConfigureAwait(false);
domains = x.domains;
}
/// HttpContext.Current is null here
ConfigureAwait(false) means "don't resume on the captured context". By specifying ConfigureAwait(false), your code is telling the runtime that it doesn't need the ASP.NET request context. But your code does need the ASP.NET request context, since it depends on HttpContext.Current. So using ConfigureAwait(false) here is wrong.
If I don't use ConfigureAwait(false) the code will not run.
This is likely because your code is blocking further up the call stack, causing a deadlock. The ideal solution is to remove the blocking - i.e., use async all the way. Using async all the way is preferable to blocking with ConfigureAwait(false).
However, there are a handful of scenarios where this isn't possible. For example, ASP.NET 4.8 doesn't have proper asynchronous support for MVC action filters or child actions. If you're doing something like this, then you have a couple of options:
Make it synchronous all the way instead of async all the way.
Keep the blocking-over-async-with-ConfigureAwait(false) antipattern but copy out everything your code needs from HttpContext.Current first and pass that data as explicit parameters so the code no longer has a dependency on the ASP.NET request context.
I'm writing web services in C++/CLI (not my choice) using Microsoft's Web API. A lot of functions in Web API are async, but because I'm using C++/CLI, I don't get the async/await support of C# or VB. So the fallback position is to use ContinueWith() to schedule a continuation delegate for reading the async task's result safely.
However, because C++/CLI also doesn't support inline anonymous delegates or managed lambdas, every delegate continuation must be written as a separate function somewhere. That quickly turns into spaghetti with the number of async functions in Web API.
So, to avoid the deadlock issues of Task<T>::Result, I've been trying this:
[HttpGet, Route( "get/some/dto" )]
Task< SomeDTO ^ > ^ MyActionMethod()
{
return Task::Run( gcnew Func< SomeDTO ^ >( this, &MyController::MyActionMethod2 ) );
}
SomeDTO ^ MyActionMethod2()
{
// execute code and use any task->Result calls I need without deadlocking
}
Okay, so I know this isn't great, but how bad is it? I don't yet understand enough of the guts of Web API or ASP.NET to comprehend the performance or scaling ramifications this will have.
Also, what other consequences may this have that aren't necessarily related to performance? For example, exceptions get wrapped in an extra AggregateException, which represents additional complexity and work for handling exceptions.
Your memory usage will increase with your application's parallelism. For every concurrent call to MyActionMethod you will need a separate thread with its own stack. That will cost you about 1 MB of RAM for each concurrent call. If MyActionMethod runs long enough so that 10000 instances run at once, you're looking at 10 GB of RAM. There is also CPU overhead in setting up each thread.
If concurrency is low, dropping async support won't be a problem. In that case, don't bother with Task::Run. Just change MyActionMethod to return SomeDTO^ (no Task wrapper).
Another potential concern is that lose easy use of cancellation tokens. However, for Web API it's usually fine to just let an exception propagate back to Web API, which ends up cancelling the synchronous call anyway.
Finally, if you were planning on performing any operation within your action method in parallel, you'll still need to use ContinueWith to accomplish that. Going non-async by default means you'll always perform one operation at a time. Fortunately, it's often just fine to do so.
Okay, so I know this isn't great, but how bad is it?
It's difficult to answer this without load-testing your specific scenario. But you can walk through the known semantics (taken largely from my blog).
First, when a request comes in, ASP.NET executes your handler on a thread pool thread within that request context. Your request handler calls Task.Run, which takes another thread from the thread pool and executes the actual request logic on it. The handler then returns the task returned from Task.Run; this releases the original request thread back to the thread pool.
Then, the Task.Run delegate will block on any asynchronous parts. So, this pattern has the scaling disadvantages of a regular synchronous handler, plus an extra thread context switch. Also, it uses a thread from the ASP.NET thread pool, which is not necessarily a bad thing, but in some scenarios it may throw off the ASP.NET thread pool heuristics.
Also, what other consequences may this have that aren't necessarily related to performance? For example, exceptions get wrapped in an extra AggregateException, which represents additional complexity and work for handling exceptions.
Yes, the exceptions from any .Result or Wait() calls will be wrapped in AggregateException. You may be able to avoid this by calling .GetAwaiter().GetResult() instead.
Another important consideration is that the code executing within the Task.Run is executing without a request context. So, ambient data like HttpContext.Current, current culture, thread principal, etc. are not going to be set correctly. You'll have to capture any important data before calling Task.Run and pass it down manually.
I have an ASP.NET site and I've been doing some work refactoring code to try to remove some long running processes (in the order of an hour) from the actual http Request by creating a BackgroundWorker and sending the work off to that to process. This was running fine on cutdown tests but when I applied the logic to the real code I found problems accessing Session variables from the code running in the Background Worker. It seems that the HttpContext object that was passed has a null session and if I ask for HttpContext.Current I get null back.
I'm assuming that this is because they are in a different thread and that the session and HttpContext.Current are both reliant on being in the same thread. Is there any way I can get access to the Session from the background worker or am I stuck with finding all the variables I need from session and putting them in an usable data structure and then putting them back in session (if appropriate) afterwards? It obviously complicates the refactor massively if I need to do this so I'd rather not.
Thanks for any thoughts you might have. I'm open to other suggestions on how I might do this other than BackgroundWorker processes (which were suggested to me in another question).
I'm not sure of all of your requirements, but you may be able to get away with using the Application Cache instead of the Session if you're not looking for the long process to be tied to an individual user's request.
If so, I would try swapping out your use of Session to:
HttpRuntime.Cache.Set("CacheKeyName");
HttpRuntime.Cache.Get("CacheKeyName");
Here's an MSDN link that sheds some light on this.
The text in particular is :
If an asynchronous action method calls a service that exposes methods by using the BeginMethod/EndMethod pattern, the callback method (that is, the method that is passed as the asynchronous callback parameter to the Begin method) might execute on a thread that is not under the control of ASP.NET. In that case, HttpContext.Current will be null, and the application might experience race conditions when it accesses members of the AsyncManager class such as Parameters. To make sure that you have access to the HttpContext.Current instance and to avoid the race condition, you can restore HttpContext.Current by calling Sync() from the callback method.
The Working with the BeginMethod/EndMethod Pattern section of Using an Asynchronous Controller in ASP.NET MVC refers to a Sync() method. It is not linked and I am having trouble finding documentation on it through google searches since sync is too common a term. Can someone point me in the write direction?
To make sure that you have access to
the HttpContext.Current instance and
to avoid the race condition, you can
restore HttpContext.Current by calling
Sync() from the callback method.
When you spawn asynchronous operations by calling BeginXyz / EndXyz methods from within your controller action, the threads handling the asynchronous response are not under the control of ASP.NET. As such, you can't touch HttpContext, the controller instance, or any other shared state from within those threads. Calling the Sync() method basically synchronizes access to the request; it restores HttpContext.Current and grants you access to touch HttpContext, the controller, etc., but only for the duration of the Sync() call. The RegisterTask() extension method from MVC Futures attempts to make this a bit easier, as you basically pass it delegates to the target Begin and End methods, and the RegisterTask() helper will ensure that the End thread executes within an appropriate synchronization context.
If you're spawning asynchronous operations by calling XyzAsync / XyzCompleted methods from within your controller action, you don't have to worry about this, as the completed handler automatically runs within a synchronization context.
It's a method of the AsyncManager class. http://msdn.microsoft.com/en-us/library/system.web.mvc.async.asyncmanager.sync.aspx
in this sample, two threads created; a worker thread created by BeginInvoke and an I/O completion thread created by SendAsync method.
but another author in his UnsafeQueueNativeOverlapped example, don't recommend this.
i want to use SendAsync or ...Async in an asp.net page and i want to use PageAsyncTask.
however, its BeginEventHandler requires AsyncResult to be returned which SendAsync does not return.
afaik, event based async pattern is the most recommended way so how could we call SendAsync or any ...Async methods without creating two threads and hurting the performance?
Actually if you used the beginIvoke and endInvoke for delegates or ThreadPool.WorkerItem it will not make any difference in your application because they are using the same thread that asp.net uses throw the iis
so now you have only 2 solution to make async calls first u will write your own threading classes (but be careful )
second use the PageAsyncTasks(recommended) this one much more safe and it's designed to work perfectly with asp.net
it's not about hurting the performance as much as it's about how and when to use asnyc tasks
if your process really take much time until it finish (because IIS will wait until all processes finish even the asnyc ones then start rendering) then you have to go to async solution instead it will make a draw back in performance
Note:
there is a difference between AddOnPreRenderCompleteAsync and RegisterAsyncTask
in there implementation they look the same but in the second one
you have access to the current http
context ,impersonation, culture and
profile data etc
you can run many tasks in parallel
you have timeout event and you can
determine timeout in the page
attribute
you can call RegisterAsyncTask
several times in one request to
register several async operations