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
Related
I am too much confused the difference between #EnableAsync and AbstractDispatcherServletInitializer#isAsyncSupported().
As per this link,
The isAsyncSupported protected method of AbstractDispatcherServletInitializer provides a single place to enable async support on the DispatcherServlet and all filters mapped to it. By default this flag is set to true
Based on my knowledge #EnableAsync is to enable scan #Async annotations and provide multi-threading support. But still I am unable to understand when to use AbstractDispatcherServletInitializer#isAsyncSupported()
There is a big difference between the two, #EnableAsync with #Async are not concerned with spring-web-mvc, they allow the execution of a method asynchronously using a TaskExecutor. For example, if you had a clean up service that deletes all logs in a server, you can allow its doCleanUp method to run asynchronously without having to write the scheduling code, spring will take care of it for you:
public class CleanUpService {
#Async
public void doCleanUp() {
// This code will be executed using a different thread than the calling thread by a TaskExecuter
}
}
As you can see this is not related to web development in particular. Also note that this method returns void, but if you wanted it to return a result, for instance CleanupStatistics, you can't just write the method like this
#Async
public CleanupStatistics doCleanUp() {
// This code will be executed using a different thread than the calling thread by a TaskExecuter
return new CleanupStatistics("someinformation");
}
You are required to return either void or a Future. A Future represents the result of an asynchronous computation that you can use to obtain the result of the computation when it becomes available. We will get back to Future and see how it can be used in controller methods while isAsyncSupported is true.
isAsyncSupported is a totally different story, this flag enables Servlet 3.0 asynchronous request processing, prior to Servlet 3.0 a servlet container (Tomcat for instance) would have a thread pool that handles the processing of Http requests, each thread would handle the request till the processing is complete, even if the thread had to stay idle, for example, to wait for a database query to finish or for an API call result to come back. This affects the scalability of the servlet container. In Servlet 3.0 requests can be handled asynchronously, the container thread will call your handler method, in its turn the handler method can schedule its work to be done asynchronously and return immediately, freeing the container thread to process other requests, after the result is available any container thread can resume the processing of the request. From the prospective of the client, nothing has changed, the client, all that time, is still waiting for the result to come back, but from the perspective of the server, the container threads are better utilised.
In spring-mvc you can trigger asynchronous request processing for a controller method by returning certain java types, for example
DeferredResult
Callable
ListenableFuture
CompletionStage
CompletableFuture
Reactive types
and streaming types
If you wanted to use #Async with isAsyncSupported you could write a controller method that calls a method annotated with #Async and returns ListenableFuture.
You can learn more about task execution and scheduling here. And more about Servlet 3.0 asynch here.
If we want to experience benefits provided by Spring MVC and don't want to manually register DispatcherServlet it'll be better to use: AbstractDispatcherServletInitializer. It adds two abstract methods: createServletApplicationContext() and getServletMappings().
First method returns WebApplicationContext that will be passed to DispatcherServlet, which will be automatically added into container ServletContext. This context will be established as a child of the context returned by createRootApplicationContext() method. Second method -returns mappings that are used during servlet registration.
The #EnableAsync annotation switches on Spring’s ability to run #Async methods in a background thread pool. For Enabling asynchronous processing with Java configuration got by simply adding the #EnableAsync to a configuration class.
#EnableAsync
#Configuration
public class SpringAsyncConfigurer implements AsyncConfigurer {...}
#Async is applicable only to the public methods.
Calling the #Async method within the same class woould not work.
In Servlet 3.0, an application's ServletContainerInitializer implementation (if any) is called when the application first BEGINS starting and any ServletContextListeners (if any) are called soon after, but still as the context is BEGINNING initialization. Likewise, if you have any Servlets with load-on-startup set, their init methods are called as the Servlets are starting up, but still BEFORE the context completes initialization.
In all of these cases, the context has not completed initialization. That is fine and I understand and agree with the reasons for that. What I'm looking for, however, is a way to be notified immediately AFTER the context has completed initialization and is open for business. As an example, it should be possible (not saying I want to do this) for this listener of sorts to perform a web request to the application it resides in. That wouldn't be possible for any of the above mentioned listeners/initializers, since they are called before the application is listening for requests.
Is it possible to do this? Doesn't have to strictly be a Servlet-spec-provided method. Could be Spring Framework or some other library that performs this task.
You can use JBoss Seam they have servlet lifecycle event #Initialized.
public void observeServletContextInitialized(#Observes #Initialized ServletContext ctx)
{
System.out.println(ctx.getServletContextName() + " initialized");
}
Can an ASP.NET Handler (.ashx) that implements IRequiresSessionState be reusable or will it persist its relationship with the first Session used?
Yes, it can be reusable.
Callers pass session state inside the HttpContext when they invoke the ProcessRequest method. Method parameters are only available within the scope of each method invocation, not across multiple invocations on different threads.
Ultimately, it depends on your ProcessRequest implementation, but unless you do something very unusual (like store the session in a member variable and then use it later during the method call), each request will use the correct session even though they're sharing the handler instance.
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.
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.