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?
The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.
The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active.
The behavior of async / await is similar to combining generators and promises. Async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise.
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With