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);
}
Related
I'm trying to store token I get from external api on session.
code snippet concerning this;
[HttpPost]
public async void Post()
{
if (HttpContext.Session.GetValue<User>("Token") == null)
{
HttpContext.Session.SetValue("Token", "test");
var res = await _loginBusiness.GetToken();
HttpContext.Session.SetValue("Token", res);
}
}
HttpContext.Session.SetValue("Token", "test");
in this part, it doesn't occur any error but second the same code line give an error after GetToken().
related error
System.ObjectDisposedException: 'IFeatureCollection has been disposed.
Object name: 'Collection'.'
Also GetToken():
public async Task<User> GetToken()
{
String url = "login/login";
var client = httpClientFactory.CreateClient("VoiceScope");
var postRes = await client.PostAsync<User>(new UserLogin(), url);
return postRes;
}
The problem is that you are using async void. These promises can't be observed and their semantics end up a lot different from a normal Task. Your disposal is happening early because the infrastructure just assumes your Post method has completed (it has no way to tell otherwise).
Change the signature of Post to be:
public async Task Post()
Please note that async void should be limited to event handlers.
I am not sure about using HttpContext. You have IHttpContextAccessor in asp.net core.
I think for store token you can use this
public class UserContext
{
public UserContext(IHttpContextAccessor context)
{
Token = GetAccessToken(context);
}
private static string GetAccessToken(IHttpContextAccessor contextAccessor)
{
var identity = (ClaimsIdentity)contextAccessor?.HttpContext?.User?.Identity;
return identity?.Claims.FirstOrDefault(x => x.Type == "token")?.Value;
}
public string Token { get; }
}
And then, add this staff in your DI like scope object and use it in controllers via ServiceProvider.
I have a simple controller method like this:
public IEnumerable<IEntity> GetEntities(ParamsModel args)
{
//set break point here to examine the args
return null;
}
And here is my ParamsModel:
public class ParamsModel {
public string Test;
}
And here is my client's method to send get request:
//_client here is an instance of RestClient
public async Task<IEnumerable<T>> GetEntitiesAsync()
{
var request = new RestRequest("somePath");
var o = new {
Test = "OK"
};
request.AddJsonBody(o);
return await _client.GetAsync<List<T>>(request);
}
After running the method GetEntitiesAsync, the break point (in the controller's method) is hit. However the args is null, really?
I've also tried the following:
public async Task<IEnumerable<T>> GetEntitiesAsync()
{
var request = new RestRequest("somePath");
request.AddParameter("Test", "OK");
return await _client.GetAsync<List<T>>(request);
}
However that did not work as well (args is null in the controller's method).
If I change the controller's method to something like this (and use the client code as right above), I can see the single simple argument of string has value parsed OK ("OK") inside the controller's method:
public IEnumerable<IEntity> GetEntities(string Test)
{
//here we can see that Test has value of "OK"
return null;
}
Really I don't understand what's wrong with my code.
Actually I worked with RestSharp at least a year ago but now it seems to have some new methods (such as the GetAsync as I used in my code), as before I used the Execute and ExecuteAsync.
Could you spot anything wrong here? Thanks!
PS: I'm using RestSharp 106.6.7
Update action to state explicitly where to look for and bind data using [FromUri]
public IHttpActionResult GetEntities([FromUri]ParamsModel args) {
//...
return Ok(entities);
}
To force Web API to read a complex type from the URI, add the [FromUri] attribute to the parameter.
Reference Parameter Binding in ASP.NET Web API
The example with AddParameter
public async Task<IEnumerable<T>> GetEntitiesAsync() {
var request = new RestRequest("somePath");
request.AddParameter("Test", "OK");
return await _client.GetAsync<List<T>>(request);
}
Should work now.
Note that the model should use properties instead of fields
public class ParamsModel {
public string Test { get; set; }
}
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
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);
}
}
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.