Will this cause a deadlock? I have read where adding .ConfigureAwait(false) is needed if the calling class uses ".Result", but does that apply here with controllers... any help is appreciated. I have a bunch of this type of "stuff" going on and deadlocks seem to be happening. The server actually shows 4 threads in a w3wp dump and a lot of requests "waiting", which causes a freeze where no connections can be made, then it unhangs and resumes. rinse and repeat. I cant figure it out.
This is an MVC controller:
public class DashboardController
{
private readonly IVendorResource _vendorResource;
public DashboardController(IVendorResource vendorResource)
{
_vendorResource = vendorResource;
}
// GET: Dashboard
public async Task<ActionResult> Index()
{
var vendor = await _vendorResource.Get(1);
vendor.ToDashboardViewModel();
vendor.Emails = await _vendorResource.GetVendorEmails(1);
var model = vendor.ToDashboardViewModel();
model.PageTitle = "Dashboard";
var vendorMetrics = await _vendorResource.GetVendorMetrics(1);
model.VendorMetrics = vendorMetrics.ToVewModel();
return View("~/Views/Dashboard/Index.cshtml", model);
}
}
Related
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.
I'm trying to return a list of followed users from the Instagram API. I'm on a sandbox account using the InstaSharp wrapper for .NET.
The action method is being called after user is authenticated.
public ActionResult Following()
{
var oAuthResponse = Session["InstaSharp.AuthInfo"] as OAuthResponse;
if (oAuthResponse == null)
{
return RedirectToAction("Login");
}
var info = new InstaSharp.Endpoints.Relationships(config_, oAuthResponse);
var following = info.Follows("10").Result;
return View(following.Data);
}
Try making the method async all the way through instead of making the blocking call .Result which runs the risk of causing a deadlock
public async Task<ActionResult> Following() {
var oAuthResponse = Session["InstaSharp.AuthInfo"] as OAuthResponse;
if (oAuthResponse == null) {
return RedirectToAction("Login");
}
var info = new InstaSharp.Endpoints.Relationships(config_, oAuthResponse);
var following = await info.Follows("10");
return View(following.Data);
}
depending on how info.Follows was implemented.
Looking at the Github repo, the API internally makes a call to a method defined like this
public static async Task<T> ExecuteAsync<T>(this HttpClient client, HttpRequestMessage request)
Which looks like your smoking gun as calling .Result higher up the call stack on this task would result in your experienced deadlock.
Reference Async/Await - Best Practices in Asynchronous Programming
This question already has answers here:
'await' works, but calling task.Result hangs/deadlocks
(6 answers)
Closed 5 years ago.
There are three layers in ASP.NET MVC application. From first layer, I am calling a method in second layer and the method calls in third layer where I call web service. Below is the code. Both the layers (2 and 3) are added as Class Library in the solution.
namespace Web.Controllers // Layer 1
{
using Web.Services;
// other usings...
public class Controller1
{
[HttpPost]
public JsonResult Search(SomeObject request)
{
Service service = new Service();
var result = service.Search(request).Result;
}
}
}
namespace Web.Service // Layer 2
{
using Web.Library;
// other usings...
public class Service
{
public async Task<SomeType> SearchFlights(SomeObject requestModel)
{
SomeObjectReturn result = new SomeObjectReturn();
Library library = new Library();
var result = await library.Search(requestModel);
return result;
}
}
}
namespace Web.Library // Layer 3
{
public class Library
{
public async Task<SomeObjectReturn> Search(SomeObject request)
{
// here I call Sabre service to get the result...
SomeObjectReturn obj = new SomeObjectReturn();
RestClient restClient = RestClientFactory.Create();
IActivity activity = new InstaFlightsActivity(restClient, requestModel);
Sabre.Library.Workflow.Workflow workflow = new Sabre.Library.Workflow.Workflow(activity);
SharedContext sharedContext = await workflow.RunAsync();
// map sharedContext to SomeObjectReturn
return obj;
}
}
}
Now I don't know why there is deadlock on await workflow.RunAsync. I have also tried .ConfigureAwait(false) on workflow.RunAsync. But the deadlock is being generated anyway. I don't know what's wrong with the code.
BTW, I have made changes as below in Controller and i got the result.
public async Task<JsonResult> Search(SomeObject request) {...
instead of above.
The call of Result produces the deadlock. Once you have an asynchronous API you should go all the way with async/await, otherwise may deadlocks arise. So if you change your controller code as below, the problem would disappear.
[HttpPost]
public async Task<JsonResult> Search(SomeObject request)
{
Service service = new Service();
var result = await service.Search(request);
}
I'm creating an ASP.NET WebAPI 2 controller. It works, but I'm confused why. It seems I'm returning a List<..> and not a Task
Please explain to me why returning a List is correct.
public class AttendeePriceController : ApiController
{
// GET api/<controller>
public async Task<List<AttendeePrice>> Get()
{
List<AttendeePrice> attendeesPriceList;
using (var db = new MyContext())
{
attendeesPriceList = await db.AttendeePrices.ToListAsync();
}
return attendeesPriceList;
}
The async keyword transforms your method into a state machine. Part of that transformation is producing a Task that represents the method. When you "return" a value, the state machine completes that task with the value.
For more information, see my async intro or the MSDN docs.
I'm using Visual Studio 2012 RC with .Net 4.5 and ASP MVC 4 RC. It hangs whenever I use async at all. The controller action method uses async but is not itself an async controller method.
There are no errors logged or exceptions thrown, but the browser shows "Waiting for www.myweb.local" forever.
// Simplest possible async
public class Waiter
{
public async Task<int> GetValue()
{
await Task.Yield();
return await Task.Factory.StartNew(() => 42);
}
}
// simplest possible controller that uses the async
public class HomeController : Controller
public ActionResult Index()
{
var waiter = new Waiter();
var resultTask = waiter.GetValue();
int result = resultTask.Result;
// it never gets here
return View();
}
}
I have done the things that are noted in this answer, and it still does not work.
ie. The web.config contains
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
And the magic words await Task.Yield(); are in the async method.
The .Net framework version is 4.5.50501. I have observed this behaviour on IIS Express and on IIS 6.0.
I tried applying the "July 2012 update" to VS2012, but that did not fix it.
This answer suggests that it may be because the task is already completed when I wait for it, however if that was the case, this should work and it does not:
public class Waiter
{
public async Task<int> GetValue()
{
await Task.Yield();
return await Task.Factory.StartNew(() =>
{
Thread.Sleep(1500);
return 42;
});
}
}
A couple of people have suggested that ConfigureAwait(false) is needed, but this code does not work either:
public async Task<int> GetValue()
{
var task = new Task<int>(() => 42);
return await task.ConfigureAwait(false);
}
The following does work with the razor view engine, but not with spark. Surely there should be a way to get the other scenario working as well? Can one not use the async Tasks inside synchronous code?
public class Waiter
{
public async Task<int> GetValue()
{
return await Task.Factory.StartNew(() => 42);
}
}
public class HomeController : Controller
{
public async Task<ActionResult> IndexAsync()
{
await Task.Yield();
var waiter = new Waiter();
int result = await waiter.GetValue();
return View();
}
}
I know that is this isn't released software, but Microsoft's RCs are usually quite stable, so I'm surprised that it fails, and fails in an unhelpful way.
You are causing a deadlock, just like this question.
James Manning's suggestion is correct, but you have to await the result of ConfigureAwait, like this:
public async Task<int> GetValue()
{
var task = new Task<int> (() => 42);
return await task.ConfigureAwait(false);
}
In general, mixing synchronous and asynchronous code is a Really Bad Idea unless you Really Know what you're doing. Making the controller action asynchronous would be much better.
I have had async working in the beta just fine. I've not tested it, but I'm guessing it's because your controller method is not async. Change it to this:
public async Task<ActionResult> IndexAsync()
{
var waiter = new Waiter();
int result = await waiter.GetValue();
// it never gets here
return View();
}