Calling async method from sync method is ASP .NET web api - issue - c#

I have a ASP .NET web api 2 application, and I'm trying to call asnyc method from sync method and meanwhile I encountered some issues. If I just call the method as a regular method the body after delay doesn't get executed, if I call it with Task.Run() it gets executed
public void CallingMethod(MethodExecutionArgs args)
{
//do something with the args
System.Diagnostics.Debug.WriteLine("BEFORE ");
WriteFileToDiskAsync(args); // If I run only this, I never see "WriteFile() - AFTER delay" in the output
Task.Run(async () => await WriteFileToDiskAsync(args)); // this executes the entire async method
System.Diagnostics.Debug.WriteLine($"Finally written from sync method");
}
private async Task<bool> WriteFileToDiskAsync(dynamic file)
{
System.Diagnostics.Debug.WriteLine("Before delay inside async");
await Task.Delay(3000);
System.Diagnostics.Debug.WriteLine("WriteFile() - AFTER delay");
}
Result: I always see the lines written from CallingMethod, but when I call the async method like a regular method, I only see the "Before delay inside async", If I call it with Task.Run() it see both lines from the async method.
Question1: Can someone explain this behavior, why doesn't the async method execute fully?
Does it have something to do with what Stephen Cleary says: If you lose your AppDomain for any reason, that in-progress work is lost.
I read these articles but can't figure out why is this happening:
How to call asynchronous method from synchronous method in C#?
Fire and forget async method in asp.net mvc
C# async/await with/without awaiting (fire and forget)
https://blog.stephencleary.com/2012/12/returning-early-from-aspnet-requests.html According to most articles what I'm trying to do is not recommended (among other things the exceptions from the async method would get swallowed) but in my case I already have the information that I need to generate the response and what is done in the Async method doesn't concern the client at all...
Context: What I'm trying to achieve is, on a existing API route that creates a X Resource (saves it in a database), after the X resource is created, I want to asynchronously call a method that will Create a json file with some information from that X Resource and save it in a filesystem. But even if the writing of the file fails, I want to return a successful response to the client (because his request was to actually save the X Resource - which succeeded) he doesn't care about Creating external file in XYZ filesystem.
Question2: What would you say is the best practice to achieve what I described above, considering all the existing methods chained in the CreateResource route are sync?

Question1: Can someone explain this behavior, why doesn't the async method execute fully? Does it have something to do with what Stephen Cleary says: If you lose your AppDomain for any reason, that in-progress work is lost.
No. The AppDomain is still there in this case. In ASP.NET (pre-Core), there is an ASP.NET SynchronizationContext that represents the request. await by default captures the current context and uses that to resume executing its async method.
So, when the await completes, it attempts to resume executing on the SynchronizationContext for that request. However, that request has been completed, and so it doesn't make sense to resume on that context. The resulting behavior is undefined.
Question2: What would you say is the best practice to achieve what I described above, considering all the existing methods chained in the CreateResource route are sync?
If you are sure you want to return early, then you should have a background service handle creating the file, not the ASP.NET service. Since you have a database already, you could use the Outbox Pattern, where you place messages in an "outbox" table as part of the same transaction as your resource creation. Then a separate background service reads the "outbox" table and writes the JSON file.

Related

Async Await with Task.Run method for DB call

We have an async/await method GetLoanDataAsync which calls a stored procedurre through entity framework which is being called by a sync method GetData.
GetLoanData takes a good amount of time to execute and probably that was the reason that we wrote as async/await which can be used by multiple places.
I understand that we shouldn't mix async and sync calls but let's say if we have this scenario and we are using Task.Run() to call async method GetLoanDataAsync from sync method GetData which I understand that method - GetLoanDataAsync will run on a background thread.
My question is that what if we had a sync version of async method GetLoanDataAsync and called using Task.Run() from GetData than what difference it would make in this case?
Providing more details regarding the issue-
We have ASP.NET REST Web API which return type is not a Task. This is called from angular app. This api has few methods called GetData() and where we wait for the result from GetLoanDataAsync. As per my understanding GetLoanDataAsync will be called in background thread and will be able to execute GetUserDetails(), once this finish it will give back the result from executed GetLoanDataAsync.
Code -
public List<int> GetData(int id)
{
// Calls GetLoanDataAsync
var result = Task.Run(()=> GetLoanDataAsync(id));
// calls couple other sync methods
GetUserDetails();
return result.GetAwaiter().GetResult();
}
GetLoanDataAsync().Result will result in deadlock which was the earlier issue. To fix this we are temporarily trying to use Task.Run till we make overall api as an async.
If you compare a sync vs async version, then the most obvious difference is that the sync version is tying up a thread for the duration of the DB call, which seems unnecessary if all the work is at the database. Whether this is a problem depends on your throughput.
By using Task.Run, you're allowing that operation to run in parallel with other work. This is fine, as long as you don't have any touch-points that impact thread-safety, or which depend on a single logical execution flow.
If you want to use async effectively, it is best to consider it "sticky" - i.e. if X is async, then everything that calls X (directly or indirectly) needs to be async.

c# synch and asynch calls on blob upload and wait function

I am trying to understand the difference between these lines of code. I have an object of memorystream called arContents and works fine when its size is small. I see the file upload.
blockBlob.UploadFromStreamAsync(arContents)
But when the memorystream is large, the above code runs without errors but uploads no file. However when I added the WAIT() function call, this worked.
blockBlob.UploadFromStreamAsync(arContents).Wait();
I would like to understand first of all What is wait call doing and why is it an async call. Guess want to know the difference between asynch and synch calls too.
Also, I have seen the await also.. code like this
await blockBlob.UploadFromStreamAsync(arContents)
What is the difference?
Thanks
I see you tagged multithreading on your question, so I think it is important to note that asynchronous and multi-threading are two completely different things. Read through Microsoft's article called The Task asynchronous programming model in C# for a good explanation of how they are different. The example about cooking really helps make this point clear.
When you call an asynchronous method, the task (whatever that is) will start. But you usually also want to either:
Know that it finished successfully, or
Use the returned result from the task (like, if it was retrieving data)
How and when you do that is when things get interesting. The point of asynchronous programming is to allow the thread to go and do something else while waiting for something else to happen (a network request, data from the hard drive, etc) rather than the thread just sitting idle until the task completes.
You have probably experienced some programs that completely lock up and don't let you do anything while it's doing something. That is what asynchronous programming allows you to avoid.
In your first example, you aren't waiting for the result at all. That's often called "fire and forget". You start the task, then code execution immediately moves on to the next line and you will never know if the task completed successfully.
Using .Wait() is not asynchronous at all. It will lock up the thread until the task finishes. Worse than that, when you try to force an asynchronous method to be synchronous, it can sometimes cause a deadlock that your application cannot recover from. Search for c# async wait deadlock and you'll find many examples and explanations.
Ideally, you will want to use await. This is what happens when you use it:
The method (UploadFromStreamAsync) is called.
When an asynchronous operation starts, UploadFromStreamAsync returns a Task.
The await keyword will look at the Task, and if it is not complete, it will put the rest of the current method on the "to do" list for when the Task does finish and return a new Task to the calling method.
As long as you have used async all the way up the call stack, then at that point, the thread can go and do something else it has on its "to do" list. In ASP.NET it could be working on a new request that came in. In a desktop app it could be responding to user input. That would happen on the same thread.
Whenever that task finishes, then await extracts the returned value from the Task. If the method returned just a Task, then that is similar to void (no return value). If it is Task<T>, then it will return the object of type T. Then your code resumes execution after the await line.
That all sounds complicated, but you don't really need to understand completely what it's doing, and that's by design. This feature of C# lets you use asynchronous programming in a way that looks very similar to normal synchronous programming. For example:
public async Task Upload() {
...
await blockBlob.UploadFromStreamAsync(arContents);
}
Will do exactly the same as this:
public void Upload() {
...
blockBlob.UploadFromStream(arContents);
}
They look very similar, except that using async/await will give you the benefits I talked about above and the second will not.

Asynchronous DB-Query to trigger Stored Procedure

I want to performa an asynchronous DB Query in C# that calls a stored procedure for a Backup. Since we use Azure this takes about 2 minutes and we don't want the user to wait that long.
So the idea is to make it asynchronous, so that the task continues to run, after the request.
[HttpPost]
public ActionResult Create(Snapshot snapshot)
{
db.Database.CommandTimeout = 7200;
Task.Run(() => db.Database.ExecuteSqlCommandAsync("EXEC PerformSnapshot #User = '" + CurrentUser.AccountName + "', #Comment = '" + snapshot.Comment + "';"));
this.ShowUserMessage("Your snapshot has been created.");
return this.RedirectToActionImpl("Index", "Snapshots", new System.Web.Routing.RouteValueDictionary());
}
I'm afraid that I haven't understood the concept of asynchronous taks. The query will not be executed (or aborted?), if I don't use the wait statement. But actually "waiting" is the one thing I espacially don't want to do here.
So... why am I forced to use wait here?
Or will the method be started, but killed if the requst is finished?
We don't want the user to wait that long.
async-await won't help you with that. Odd as it may sound, the basic async-await pattern is about implementing synchronous behavior in a non-blocking fashion. It doesn't re-arrange your logical flow; in fact, it goes to great lengths to preserve it. The only thing you've changed by going async here is that you're no longer tying up a thread during that 2-minute database operation, which is a huge win your app's scalability if you have lots of concurrent users, but doesn't speed up an individual request one bit.
I think what you really want is to run the operation as a background job so you can respond to the user immediately. But be careful - there are bad ways to do that in ASP.NET (i.e. Task.Run) and there are good ways.
Dave, you're not forced to use await here. And you're right - from user perspective it still will take 2 minutes. The only difference is that the thread which processes your request can now process other requests meanwhile database does its job. And when database finishes, the thread will continue process your request.
Say you have limited number of threads capable to process HTTP request. This async code will help you to process more requests per time period, but it won't help user to get the job done faster.
This seems to be down to a misunderstanding as to what async and await do.
async does not mean run this on a new thread, in essence it acts as a signal to the compiler to build a state machine, so a method like this:
Task<int> GetMeAnInt()
{
return await myWebService.GetMeAnInt();
}
sort of (cannot stress this enough), gets turned into this:
Task<int> GetMeAnInt()
{
var awaiter = myWebService.GetMeAnInt().GetAwaiter();
awaiter.OnCompletion(() => goto done);
return Task.InProgress;
done:
return awaiter.Result;
}
MSDN has way more information about this, and there's even some code out there explaining how to build your own awaiters.
async and await at their very core just enable you to write code that uses callbacks under the hood, but in a nice way that tells the compiler to do the heavy lifting for you.
If you really want to run something in the background, then you need to use Task:
Task<int> GetMeAnInt()
{
return Task.Run(() => myWebService.GetMeAnInt());
}
OR
Task<int> GetMeAnInt()
{
return Task.Run(async () => await myWebService.GetMeAnInt());
}
The second example uses async and await in the lambda because in this scenario GetMeAnInt on the web service also happens to return Task<int>.
To recap:
async and await just instruct the compiler to do some jiggerypokery
This uses labels and callbacks with goto
Fun fact, this is valid IL but the C# compiler doesn't allow it for your own code, hence why the compiler can get away with the magic but you can't.
async does not mean "run on a background thread"
Task.Run() can be used to queue a threadpool thread to run an arbitrary function
Task.Factory.Start() can be used to grab a brand new thread to run an arbitrary function
await instructs the compiler that this is the point at which the result of the awaiter for the awaitable (e.g. Task) being awaited is required - this is how it knows how to structure the state machine.
As I describe in my MSDN article on async ASP.NET, async is not a silver bullet; it doesn't change the HTTP protocol:
When some developers learn about async and await, they believe it’s a way for the server code to “yield” to the client (for example, the browser). However, async and await on ASP.NET only “yield” to the ASP.NET runtime; the HTTP protocol remains unchanged, and you still have only one response per request.
In your case, you're trying to use a web request to kick off a backend operation and then return to the browser. ASP.NET was not designed to execute backend operations like this; it is only a web tier framework. Having ASP.NET execute work is dangerous because ASP.NET is only aware of work coming in from its requests.
I have an overview of various solutions on my blog. Note that using a plain Task.Run, Task.Factory.StartNew, or ThreadPool.QueueUserWorkItem is extremely dangerous because ASP.NET doesn't know anything about that work. At the very least you should use HostingEnvironment.QueueBackgroundWorkItem so ASP.NET at least knows about the work. But that doesn't guarantee that the work will actually ever complete.
A proper solution is to place the work in a persistent queue and have an independent background worker process that queue. See the Asynchronous Messaging Primer (specifically, your scenario is "Decoupling workloads").

Async and Await in ApiController Post

I'm still not quite clear about async and await in .net 4.5. So far, I think I understand that await:
puts the function (to its right) on a separate thread.
puts the execution back to the current function's caller
but holds the rest of the current function's code "hostage" until the awaiting (async) function is finished.
Please correct me if I'm misunderstanding something. So, if the above is true, I'm stuck with an ApiController's Post function that I want async:
[HttpPost]
public async Task<HttpResponseMessage> Post([FromBody]MyObject obj)
{
myDataContext.MyObjects.InsertOnSubmit(obj);
myDataContext.SubmitChanges();
await SomeReallyLongRunningTaskAsync();
// obj would now have the new Id, which I'm really after.
return Request.CreateResponse(HttpStatusCode.Created, obj);
}
So if I'm understanding this correctly, Post will finish execution and return control to whoever called myApiController.Post(obj). But I don't have the HttpResponseMessage object yet since await held return Request.CreateResponse(HttpStatusCode.Created, obj); "hostage".
In this above simple example, would the call immediately return to the client (that is, client JS website or mobile app)? If so, would it be a 201, 400, 500 (better not), others?
In addition to Stephen's answer I need to point out a few things.
First, async in the controller does not make the user experience async. User will have to wait as long as SomeReallyLongRunningTaskAsync() takes. [So why do we do async? See the next point]
Also, if the SomeReallyLongRunningTaskAsync() is CPU-bound, then you should not call it in async mode. The main reason to use Async in a server scenario is to release the CLR thread back to the pool so that the IO Completion Port (IOCP) can handle the rest - until IO work done which then goes back to the thread pool. This will prevent the problem of Thread Starvation which is common in ASP.NET Scenarios.
IOCPs are used ONLY in IO-bound situations, examples are:
reading from/writing to a file
accessing database or
accessing an external Web Service or WCF service
There are tons of resources available online and explain various aspects. If I may put a plug, Chapter 2 of this book is an excellent resource which gives a cohesive understanding of Async in Web API.
puts the function (to its right) on a separate thread.
No. async does not start a new thread. I have an async intro that you may find helpful.
Post will finish execution and return control to whoever called myApiController.Post(obj). But I don't have the HttpResponseMessage object yet
Correct.
In this above simple example, would the call immediately return to the client (that is, client JS website or mobile app)?
No. ASP.NET MVC 4.5 sees that you're returning Task<HttpResponseMessage> and not HttpResponseMessage, so it will not send the response until your Task is completed (at the end of your async Post method).

MVC4 + async/await + return response before action completes

In my MVC4 app I need to add a controller for uploading and processing large files. Immediately after the file is uploaded I need to start async processing of that file and return response to the browser without waiting for the processing to complete.
Obviously I could start a new thread for processing the file manually, but I'm wondering if I can implement this scenario using async/await mechanism introduced with .net 4.5
To test the concept I've tried something like this:
public async Task<ActionResult> Test()
{
TestAsync();
return View("Test");
}
public async void TestAsync()
{
await LongRunning();
}
private Task<int> LongRunning()
{
return Task<int>.Factory.StartNew(() => Pause());
}
private int Pause()
{
Thread.Sleep(10000);
return 3;
}
The async mechanism seems to work in general: when I debug the code I hit the "return View("Test");" line before the line "return 3". However, the browser receives the response only after the Pause method completes.
This seems to behave like regular async controllers (the ones with Async and Completed methods). Is there a way to use async/await in controllers for my scenario?
Obviously I could start a new thread for processing the file manually, but I'm wondering if I can implement this scenario using async/await mechanism introduced with .net 4.5
No, you cannot, because async doesn't change the HTTP protocol.
Svick and James have already posted the correct answers as comments, which I duplicate below for convenience:
IIS can recycle your application pretty much at any time.
If you have long-running things to do async to the request, do them elsewhere. The 'typical' is a persistent queue (MSMQ, Azure, RabbitMQ, etc) with something else (windows service, exe run by task scheduler, app using Quartz.net, etc) processing them.
To summarize, HTTP gives you one request and one response (async - and anything else - won't change this).
ASP.NET is designed around HTTP requests (and makes assumptions like "if there are no outstanding requests, then it's safe to stop this web site"). You can kick off a new thread and keep your upload in memory (which is the easiest way to do it), but it's strongly not recommended.
For your situation, I recommend you follow James' suggestion:
When your upload completes, save the upload to persistent storage (e.g., an Azure queue), and return a "ticket" to the browser.
Have some other process (e.g., an Azure worker role) process the queue, eventually marking it as complete.
Have the browser poll the server with its "ticket". The server uses the "ticket" to look up the file in persistent storage and return whether or not it's complete.
There are some variations to this (e.g., using SignalR to notify the browser when processing is complete), but the general architecture is the same.
This is complex, but it's the right way to do it.
You have an error in your code.
You must await the call to TestAsync in your action.
If you don't, it simply returns a "Task" object without running anything.
public async Task<ActionResult> Test()
{
await TestAsync();
return View("Test");
}
and the correct way to sleep in an async method is to call
await Task.Delay(10000);
You have to change the signature of TestAsync: you should not mark a method async if it returns void. It must return Task instead. Returning void is reserved for compatibility with .net events.
public async Task TestAsync()
{
await LongRunning();
}
The method body is the same.
Your LongRunning method is synchronously sleeping 10 seconds. Change it so the sleep happens in the task instead.

Categories