ActionNameAsync-ActionNameCompleted vs async-await in Asp.NET MVC - c#

I'm starting with Async MVC and I would like to know which is the main difference between this two implementations of an AsyncController.
The first one is using the ViewNameAsync and ViewNameCompleted implementation:
public class HomeController : AsyncController
{
// ... Manager declaration ...
public void IndexAsync()
{
AsyncManager.OutstandingOperations.Increment();
Manager.ExpensiveOperationCompleted += () =>
{
Debug.WriteLine("Expensive operation completed.");
AsyncManager.OutstandingOperations.Decrement();
};
Manager.ExpensiveOperationAsync();
}
public ActionResult IndexCompleted()
{
return View();
}
}
And the second one is using async-await implementation:
public class HomeController : Controller
{
// ... Manager declaration ...
public async Task<ActionResult> Index()
{
await Manager.ExpensiveOperation();
return View();
}
}

The "main difference" is that the Async/Completed approach is using an outdated and less maintainable way to do asynchronous request handling.

The main reason you do it this way (await the same line) is to tell the thread resource manager that it can balance the thread with other threads. This will allow other threads with higher priority to finish. You can also reference your expensive operation as a variable and then later down the code block, await it there. This will allow your expensive operation to do it's thing while the rest of the code executes. Basically like using Thread.Join.
Using a completed event isn't going to work in this case, considering your IndexAsync will return before your expensive operation completes and may cause undesired results if a recycle happens.

Related

Async/Wait in REST api on IIS Express

I'm building a RESTful web api that is going to fire off several tasks, wait for them to complete then return some data. But I keep having problems with it seeming to hang when waiting. I scaled it down the the most basic:
[Authorize]
public class ValuesController : ApiController
{
public IEnumerable<string> Get([FromUri]bool enableWait)
{
Task t = Silly(enableWait);
t.Wait();
return new string[] { "value1", "value2" };
}
private async Task Silly(bool delay)
{
if (delay)
await Task.Delay(1);
}
}
If I pass false it returns without any issue. If I return true, it should wait for 1 millisecond (plus Task/Asnyc overhead) then return. However it just hangs there.
I'm running this on the IIS Express that comes with VS 2017. Any clues?
When implementing async/await you need to make sure you are implementing it all the way through. Your controller action needs to be async, and it needs to await your Silly() method:
public async Task<IEnumerable<string>> Get()
{
return await Silly();
}
You also have to make sure your Silly() method is calling the proper async methods it needs, making sure you are await-ing them.

Integrating async await into synchronous methods

I've been banging my head against a wall for two days now, and frankly I'm annoyed with myself because I just can't seem to get it.
I'm in a webapi context. During this request I need to send some data to one of our other systems, this system is slow to return, due to heavy calculations and multiple database saves etc etc. I need to log the result of this operation, regardless of whether it is successful or not. But I don't want to wait around for it to finish.
I've read that I should be async await all the way from top to bottom. I would have to convert numerous methods if I decided to do this, as I'm already 3 or 4 methods deep, which I fear would branch out even more.
What are my options here? If I go async await all the way down, what do I do with the methods higher up the stack, like my WebApi controllers?
Here is my code, I've tried to thin it down as much as I can. Right now I'm using Task.Result() in the method PushResult(). Which to my understanding is blocking the async? This code works in that the request gets sent. But the TestLog is always last, not first. Therefore not async.
//I'm in a public service and referenced twice
private void MyEndProcess()
{
// other stuff
_vendorPushService.PushResult(); // This could take a while and I have to wait for it!
_logService.PostLog(LogType.TestLog, "Test");
}
//I'm referenced above and somewhere else in the code base
public void PushResult()
{
ExternalResultModel externalResultModel = _resultService.GetExternalResultModel();
PushedResultModel pushedResult = new PushedResultModel();
try
{
pushedResult = _vendorRequestService.PushResultAsync(externalResultModel).Result;
}
catch (Exception ex)
{
pushedResult.Success = false;
}
if (pushedResult.Success)
{
_logService.PostLog(LogType.SuccessLog, pushedResult.Message);
}
else
{
_logService.PostLog(LogType.FailedLog, pushedResult.Message);
}
}
public async Task<PushedResultModel> PushResultAsync(ExternalResultModel externalResultModel)
{
// setup the requestMessage
HttpResponseMessage responseMessage = await _httpRequestService
.SendRequest(requestMessage)
.ConfigureAwait(false);
return new PushedResultModel
{
Success = responseMessage.IsSuccessStatusCode,
Message = await responseMessage.Content.ReadAsStringAsync()
};
}
public class HttpRequestService : IHttpRequestService
{
private readonly HttpClient _httpClient;
public HttpRequestService(IHttpClientAccessor httpClientAccessor)
{
_httpClient = httpClientAccessor.HttpClient;
}
public async Task<HttpResponseMessage> SendRequest(HttpRequestMessage requestMessage)
{
HttpResponseMessage httpResponseMessage = await _httpClient.SendAsync(requestMessage).ConfigureAwait(false);
return httpResponseMessage;
}
}
You should implement async await all the way from top to bottom.
If I go async await all the way down, what do I do with the methods higher up the stack, like my WebApi controllers?
Just make your controller actions async like this:
[RoutePrefix("api")]
public class PresidentsController : ApiController
{
[Route("presidents")]
public async Task<IHttpActionResult> GetPresidents()
{
await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false);
return Ok();
}
}
It's easiest way to implement async methods. Even if it will add some work to change everything to async it will benefit in future, because You will avoid many problem with async code.
If you absolutly HAVE to use async method in synchronous methods make it block in ONE place, like this:
public void MySyncMethod()
{
try
{
this.MyAsyncMethod().Wait();
}
catch (Exception exception)
{
//omited
}
}
private async Task MyAsyncMethod()
{
await AsyncLogic().ConfigureAwait(false);
}
But i don't recommend it. You should just use async await all the way to controller action.
In your comment you said you want to process a task in the background and not make the client calling your API wait. To do that, you don't really need to use async/await.
Try this:
private void MyEndProcess()
{
// other stuff
Task.Run(_vendorPushService.PushResult()).ConfigureAwait(false); //fire and forget
_logService.PostLog(LogType.TestLog, "Test");
}
The Task.Run will start the task, and the ConfigureAwait(false) tells it that it does not need to resume on the same context that we're currently on (meaning that the context can close before the task is finished - i.e. the response can be sent back without waiting for the task to finish).
You will get a compiler warning that you're not awaiting Task.Run, but that's what you want.
Keep in mind that when you do this, HttpContext.Current will not be available inside PushResult.

Will BeginInvoke continue to execute if I return immediately from an MVC controller action?

I'm trying to troubleshoot an issue where we believe an Async call may not execute in some instances.
Would doWork() complete executing even after the controller has returned and no call to EndInoke()?
Is there another case where this would not execute, like an exception throw in doWork()?
delegate void TestDelegate();
void doWork()
{
Thread.Sleep(5000);
}
public ActionResult Test()
{
var myAsyncCall = new TestDelegate(doWork);
myAsyncCall.BeginInvoke();
return View();
}
In general, you need to call EndInvoke on the delegate. This will allow you to determine why things are not working (like an exception being raised within doWork, which would explain the described issue).
For details, see Calling Synchronous Methods Asynchronously on MSDN.
That being said, I would recommend reworking this to use the the TPL instead of delegate.BeginInvoke, as it makes some of the checking simpler overall. You could write the above as:
public ActionResult Test()
{
// Start the async work, and attach a continuation which happens if exceptions occur
Task.Run(() => doWork())
.ContinueWith(t =>
{
var ex = t.Exception.InnerException;
LogException(ex);
}, TaskContinuationOptions.OnlyOnFaulted);
return View();
}

Is this the correct way to write asynchronous methods?

I'm currently trying to write async code and I have the feeling that my code is not too correct at all.
I have the following method:
public void Commit()
{
_context.SaveChangesToDatabase();
}
Don't judge the code here as this are only samples. Also, don't say that if I'm using Entity Framework, that they come packaged with Async methods already. I just want to understand the async concept here.
Let's say that the method SaveChangesToDatabase does takes seconds to complete.
Now, I don't want to wait for it so I create an async method:
public async Task CommitAsync()
{
await Task.Run(() => Commit());
}
Does this mean that if I have a method:
public void Method()
{
// Operation One:
CommitAsync();
// Operation Two.
}
Does this mean that my code on Operation two will be executed before CommitAsync() is even completed?
If not, please guide me in the right direction.
Update
Based on the remarks here that I'm ignoring my async method results, is this implementation better?
public Task<TaskResult> CommitAsync()
{
var task = new Task<TaskResult>(() =>
{
try { Commit(); }
catch (Exception ex)
{
return new TaskResult
{
Result = TaskExceutionResult.Failed,
Message = ex.Message
};
}
return new TaskResult { Result = TaskExceutionResult.Succeeded };
});
task.Start();
return task;
}
This does mean that I need to put the async modifier on the method that call this code so that I can await this which means continue with the current execution and return when this method has been completed.
Fire but don't forget
CommitAsync() returns a Task, but Method ignores the return value of CommitAsync completely -- so yes, the code will not wait but simply go on with what's after that. This is bad, because, if Commit() throws an exception, you will never see it. Ideally, every task should be waited on somewhere by someone, so you can at least see if it fails.
Let's say that you have no async alternative to SaveChangesToDatabase, but you'd like to use it in an async context anyway. You can use Task.Run to create a "fake-asynchronous" method, but this is not recommended (see below):
public Task CommitAsync() {
return Task.Run(() => Commit());
}
And then, assuming Method is doing something interesting with async (which the below code does not do since it's the only asynchronous operation in there):
public async Task MethodAsync() {
// Operation One:
await CommitAsync();
// Operation Two.
}
Assuming you do not want to wait, but you do want to do something if the task failed, you can use a separate method:
public void Method() {
// Operation One:
var _ = TryCommitAsync();
// Operation Two.
}
private async Task TryCommitAsync()
{
try
{
await CommitAsync();
}
catch (Exception ex)
{
Console.WriteLine(
"Committing failed in the background: {0}",
ex.Message
);
}
}
Getting back results
Let's suppose .Commit() does return something (like the number of records affected); a similar "fake-asynchronous" wrapper (again, not recommended - see below) would look like this:
public Task<int> CommitAsync() {
return Task.Run(() => Commit());
}
If you want this result, you can await the task immediately:
public async Task MethodAsync() {
// Operation One:
int recordsAffected = await CommitAsync();
// Operation Two.
}
Or, if you don't need it immediately, use await when you do:
public async Task MethodAsync() {
// Operation One:
Task<int> commit = CommitAsync();
// Operation Two.
// At this point I'd really like to know how many records were committed.
int recordsAffected = await commit;
}
Async: don't fake it
In general, you don't want to write wrappers like CommitAsync() because they mislead callers into thinking code will be asynchronous when it isn't really, which brings few benefits other than not blocking (which is still useful in UI code, but not as good as true asynchronous code which doesn't need to use worker threads for everything). In other words, you should use Task.Run in the invocation of a method, not as the implementation of a method.
So don't, as a habit, write wrappers like CommitAsync for every synchronous method you have -- instead you want to make a true CommitAsync that uses the async support of the underlying libraries/frameworks (SqlCommand.ExecuteReaderAsync(), etcetera.)
If you have no choice and must use Task.Run, then the appropriate usage would look more like:
// This method is in the UI layer.
public async Task MethodAsync() {
// Operation One:
// Commit() is a method in the DA layer.
await Task.Run(() => Commit());
// Operation Two.
}
Here
http://channel9.msdn.com/events/TechEd/NorthAmerica/2013/DEV-B318#fbid=
is a good explanation on how to work with async, and why you should avoid "async over sync", which is what you are doing now with
public Task CommitAsync() {
return Task.Run(() => Commit());
}
There are some scenarios where you can benefit from it, but if you are going to provide this as part of a library is NOT a good idea to make this.
If this code is ONLY and ONLY going to be used by your app, and you are sure what you are doing and dont have a wawy to call async methods inside your async method, just do it

async await calling into multiple synchronous methods

I'm wondering how to best handle this async await chain where multiple CPU bound methods need to be called sequentially after the async chain.
I've typed up a small example below.
I'm just trying to find out what the best performing / least side effecting pattern is. I want to make sure I'm not defeating the async benefits. My Filter methods do not access anything that is async and awaitable so to make them async means I would have to return Task.Run(() => Filter1(criterion)) in the calling method or something like await Task.Run(() => { return events; }); in the filter methods themselves. Which way to go for a best practice is the question. This is where most discussions stop so a full example and recommendation would be nice.
Are there any 4.5 async await gurus out there who can give good advice?
namespace test
{
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
public class sampleController : ApiController
{
private Service _service;
public sampleController()
{
_service = new Service();
}
public async Task<HttpResponseMessage> SomeTask(DiagnosesSearchCriterion criterion)
{
return Request.CreateResponse<IEnumerable<Diagnosis>>(HttpStatusCode.OK, await _service.GetDiagnosesByGroup(criterion));
}
}
public class Service
{
private Repository _repository;
public Service()
{
_repository = new Repository();
}
public async Task<IEnumerable<Diagnosis>> GetDiagnosis(DiagnosesSearchCriterion criterion)
{
System.IO.Stream events = await _repository.GetEvents(criterion);
// Will these block? Should they be async? They are CPU bound...
// how to best handle this, they need to be called sequentially in most cases.
events = Filter1(criterion, events);
events = Filter2(criterion, events);
return new Diagnosis[]{};
}
public System.IO.Stream Filter1(DiagnosesSearchCriterion criterion, System.IO.Stream events)
{
// CPU bound PLINQ and Parallel filtering logic here.....
return events;
}
public System.IO.Stream Filter2(DiagnosesSearchCriterion criterion, System.IO.Stream events)
{
// CPU bound PLINQ and Parallel filtering logic here.....
// ....
return events;
}
}
public class Repository
{
public async Task<System.IO.Stream> GetEvents(DiagnosesSearchCriterion criterion)
{
WebClient wc = new WebClient();
return await wc.OpenReadTaskAsync("http://www.blah.com/stuff");
}
}
}
On the server side, your primary benefit from async is scalability - that is, the thread pool thread is freed up from handling a request if the request is just waiting for some I/O to complete.
In this case (where your methods are CPU-bound), there's no benefit from making them async. You'll still be taking up a thread pool thread (and adding a small amount of overhead) by using Task.Run. Since they should be executed sequentially, the easiest way to do this is to invoke them synchronously, just like your code is currently doing.
I think this scenario is addressed in the excellent Async in ASP.NET video. Note that this same situation on the client side would be handled differently. On the client side, your primary benefit from async is responsiveness, so it would make sense to toss CPU work into a thread pool thread (Task.Run), since that would free up the UI thread.
(As a side note, it's usually not a good idea to do parallel processing on a server, unless you're sure your user count will be quite low).

Categories