I'm looking at how to create a .net web-api method which is asynchronous i.e:
- It runs the actual task as a background task but returns a status straightaway
- It is also passed callback information which it calls back when background task is complete.
I understand the theory and have noticed articles around Request/Acknowledge however im struggling to find a well document .net version of the pattern which achieves the above and doesn't cause multi-threading issues on my web-api? I don't want to do anything bespoke because surely this is a common .net implementation?
ok seems like there nothing magical in terms of solution:
public HttpResponseMessage SomePostMethod(Request request)
{
Validate(request);
QueueForBackGroundAsync(request);
return HttpStatusCode.Accepted;
}
Related
I am migrating my current project to core, and in my current project I have many synchronous method calls from UserManagerExtension class like Create, FindById, AddToRole etc. But despite thorough searching online I am not able to find the same in core.
Is it deprecated in core 2.0? If not, what is the namespace and how to include it?
As far as I can tell, they are gone. However, their existence was suspect even before. All the extensions did was simply run the async versions "synchronously", which basically means they spun off a task that blocked on the async call until it completed. While this technically satisfies having a "synchronous" method, it's actually really bad for web applications as you're sacrificing threads from your pool to do the work synchronously.
In ASP.NET MVC, it was a necessary evil, though, since there were many aspects that did not support async: child actions, action filters, etc. However, in Core, everything is async, and things happening in a web application space should be async. Therefore, there's simply no good reason to ever use sync methods, so that's probably why they no longer exist.
If you still need to run the async methods as sync, for some reason, you can simply block on them yourself:
var user = UserManager.FindByIdAsync(id).GetAwaiter().GetResult();
Be aware, though, that can deadlock in certain situations, because of the context shift. The two ways to avoid that are:
Use ConfigureAwait(false)
var user = UserManager.FindByIdAsync(id).ConfigureAwait(false).GetAwaiter().GetResult();
However, you cannot use ConfigureAwait(false) in something like an action method, since the context must be maintained in order to complete the response. You can use it in a method called by the action method, though:
private ApplicationUser GetUser(string id)
{
return UserManager.FindByIdAsync(id).ConfigureAwait(false).GetAwaiter().GetResult();
}
...
var user = GetUser(id);
Run it in a different thread
Task.Run(() => {
var user = UserManager.FindByIdAsync(id).GetAwaiter().GetResult();
// code here that needs `user`
});
As you can see, with this method the work you send off must be self-contained, so it's probably not a good fit in most scenarios. Also, again, this is extremely bad for web applications.
Long and short, there's not really a good way to run async as sync, and you should avoid it as much as possible. Async should be async all the way. That did use to be an issue in MVC, but now it's not with Core.
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 a standard, non-async action like:
[HttpPost]
public JsonResult StartGeneratePdf(int id)
{
PdfGenerator.Current.GenerateAsync(id);
return Json(null);
}
The idea being that I know this PDF generation could take a long time, so I just start the task and return, not caring about the result of the async operation.
In a default ASP.Net MVC 4 app this gives me this nice exception:
System.InvalidOperationException: An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%# Page Async="true" %>.
Which is all kinds of irrelevant to my scenario. Looking into it I can set a flag to false to prevent this Exception:
<appSettings>
<!-- Allows throwaway async operations from MVC Controller actions -->
<add key="aspnet:AllowAsyncDuringSyncStages" value="true" />
</appSettings>
https://stackoverflow.com/a/15230973/176877
http://msdn.microsoft.com/en-us/library/hh975440.aspx
But the question is, is there any harm by kicking off this Async operation and forgetting about it from a synchronous MVC Controller Action? Everything I can find recommends making the Controller Async, but that isn't what I'm looking for - there would be no point since it should always return immediately.
Relax, as Microsoft itself says (http://msdn.microsoft.com/en-us/library/system.web.httpcontext.allowasyncduringsyncstages.aspx):
This behavior is meant as a safety net to let you know early on if
you're writing async code that doesn't fit expected patterns and might
have negative side effects.
Just remember a few simple rules:
Never await inside (async or not) void events (as they return immediately). Some WebForms Page events support simple awaits inside them - but RegisterAsyncTask is still the highly preferred approach.
Don't await on async void methods (as they return immediately).
Don't wait synchronously in the GUI or Request thread (.Wait(), .Result(), .WaitAll(), WaitAny()) on async methods that don't have .ConfigureAwait(false) on root await inside them, or their root Task is not started with .Run(), or don't have the TaskScheduler.Default explicitly specified (as the GUI or Request will thus deadlock).
Use .ConfigureAwait(false) or Task.Run or explicitly specify TaskScheduler.Default for every background process, and in every library method, that does not need to continue on the synchronization context - think of it as the "calling thread", but know that it is not one (and not always on the same one), and may not even exist anymore (if the Request already ended). This alone avoids most common async/await errors, and also increases performance as well.
Microsoft just assumed you forgot to wait on your task...
UPDATE: As Stephen clearly (pun not intended) stated in his answer, there is an inherit but hidden danger with all forms of fire-and-forget when working with application pools, not solely specific to just async/await, but Tasks, ThreadPool, and all other such methods as well - they are not guaranteed to finish once the request ends (app pool may recycle at any time for a number of reasons).
You may care about that or not (if it's not business-critical as in the OP's particular case), but you should always be aware of it.
The InvalidOperationException is not a warning. AllowAsyncDuringSyncStages is a dangerous setting and one that I would personally never use.
The correct solution is to store the request to a persistent queue (e.g., an Azure queue) and have a separate application (e.g., an Azure worker role) processing that queue. This is much more work, but it is the correct way to do it. I mean "correct" in the sense that IIS/ASP.NET recycling your application won't mess up your processing.
If you absolutely want to keep your processing in-memory (and, as a corollary, you're OK with occasionally "losing" reqeusts), then at least register the work with ASP.NET. I have source code on my blog that you can drop in your solution to do this. But please don't just grab the code; please read the entire post so it's clear why this is still not the best solution. :)
The answer turns out to be a bit more complicated:
If what you're doing, as in my example, is just setting up a long-running async task and returning, you don't need to do more than what I stated in my question.
But, there is a risk: If someone expanded this Action later where it made sense for the Action to be async, then the fire and forget async method inside it is going to randomly succeed or fail. It goes like this:
The fire and forget method finishes.
Because it was fired from inside an async Task, it will attempt to rejoin that Task's context ("marshal") as it returns.
If the async Controller Action has completed and the Controller instance has since been garbage collected, that Task context will now be null.
Whether it is in fact null will vary, because of the above timings - sometimes it is, sometimes it isn't. That means a developer can test and find everything working correctly, push to Production, and it explodes. Worse, the error this causes is:
A NullReferenceException - very vague.
Thrown inside .Net Framework code you can't even step into inside of Visual Studio - usually System.Web.dll.
Not captured by any try/catch because the part of the Task Parallel Library that lets you marshal back into existing try/catch contexts is the part that's failing.
So, you'll get a mystery error where things just don't occur - Exceptions are being thrown but you're likely not privy to them. Not good.
The clean way to prevent this is:
[HttpPost]
public JsonResult StartGeneratePdf(int id)
{
#pragma warning disable 4014 // Fire and forget.
Task.Run(async () =>
{
await PdfGenerator.Current.GenerateAsync(id);
}).ConfigureAwait(false);
return Json(null);
}
So, here we have a synchronous Controller with no issues - but to ensure it still won't even if we change it to async later, we explicitly start a new Task via Run, which by default puts the Task on the main ThreadPool. If we awaited it, it would attempt to tie it back to this context, which we don't want - so we don't await it, and that gets us a nuisance warning. We disable the warning with the pragma warning disable.
I've been informing myself about the async capabilities of .net 3.5
Ive found a very good article on this : http://msdn.microsoft.com/en-us/magazine/cc163725.aspx
Now, the thing is, all these methods still require the async tasks to be finished BEFORE the Page_Render event, so in practice, the web application will still appear to be 'hanging' for the user.
My question: How can I async launch a heavy task from my aspx page, without having to wait or callback for this task when its finished, and then just render the page. The actual work is being done in a WCF service ( creating document, sending mail )
Pseudo code:
void btn_Click()
{
AsyncCallWcfServiceButDontWaitForIt();
lblFeedback.Text = "Your documents are beging generated and mailed in the background";
}
I'd like to give the user direct feedback while the rest is being handled in the background. I've implemented something like this with executing a console script but I'm looking for a possible better async way.
Please also note I'm looking for a .NET 3.5 solution!
Thanks in advance
What you are looking for is not async here (though you should also be doing that)... what you are looking for is AJAX; you render the page, then load the slow-loading information via Ajax (with async code, just as usual)
I am writing a custom Windows Workflow Foundation activity, that starts some process asynchronously, and then should wake up when an async event arrives.
All the samples I’ve found (e.g. this one by Kirk Evans) involve a custom workflow service, that does most of the work, and then posts an event to the activity-created queue. The main reason for that seems to be that the only method to post an event [that works from a non-WF thread] is WorkflowInstance.EnqueueItem, and the activities don’t have access to workflow instances, so they can't post events (from non-WF thread where I receive the result of async operation).
I don't like this design, as this splits functionality into two pieces, and requires adding a service to a host when a new activity type is added. Ugly.
So I wrote the following generic service that I call from the activity’s async event handler, and that can reused by various async activities (error handling omitted):
class WorkflowEnqueuerService : WorkflowRuntimeService
{
public void EnqueueItem(Guid workflowInstanceId, IComparable queueId, object item)
{
this.Runtime.GetWorkflow(workflowInstanceId).EnqueueItem(queueId, item, null, null);
}
}
Now in the activity code, I can obtain and store a reference to this service, start my async operation, an when it completes, use this service to post an event to my queue. The benefits of this - I keep all the activity-specific code inside activity, and I don't have to add new services for each activity types.
But seeing the official and internet samples doing it will specialized non-reusable services, I would like to check if this approach is OK, or I’m creating some problems here?
There is a potential problem here with regard to workflow persistence.
If you create long running worklfows that are persisted in a database to the runtime will be able to restart these workflows are not reloaded into memory until there is some external event that reloads them. As there they are responsible for triggering the event themselves but cannot until they are reloaded. And we have a catch 22 :-(
The proper way to do this is using an external service. And while this might feel like dividing the code into two places it really isn't. The reason is that the workflow is responsible for the big picture, IE what should be done. And the runtime service is responsible for the actual implementation or how it should be done. That way you can change the how without changing the why and when part.
A followup - regardless of all the reasons, why it "should be done" using a service, this will be directly supported by .NET 4.0, which provides a clean way for an activity to start an asynchronous work, while suspending the persistence of the activity.
See
http://msdn.microsoft.com/en-us/library/system.activities.codeactivitycontext.setupasyncoperationblock(VS.100).aspx
for details.