Deadlock when calling an async method inside a non async action - c#

We have a web application which consists of a Web API consumed by our UI. The web application is installed on different servers (tests before installing it by our clients).
On one server, we get a deadlock by the following endpoint:
[HttpGet, Route(Order = 1)]
public IHttpActionResult GetUserDetails(long userKey)
{
var userService = ResolveService<IUserService>();
var nameService = ResolveService<INameService >();
LoggInfo("Start userService.Get()"); //logged in logs
var result = userService.Get(userKey);
this.LoggInfo($"End userService.Get() with id = "{result.Id}); // logged in logs
try
{
LoggInfo($"Start nameService.Get()"); // logged in logs
result.Name = nameService.Get(result.Namekey).Result?.Name;
LoggInfo($"End nameService.Get()"); // not logged in logs
}
catch(Exception ex)
{
LogError("An error occured in NameService"); // not logged in logs
}
return Ok(result);
}
nameService.Get(id) is an async method :
public async Task<NameDTO> GetAsync(long key)
{
LogInfo("start NameService.Get()"); // not logged in logs
var query = GetQuery();
var name = await query.Select(MapName())
.FirstOrDefaultAsync(n => n.Key == key);
return name;
}
When I remove the async signature everything is working as expected, according to this article it is normal to have a deadlock.
Could you please explain me why this works in the other servers ?
Thanks in advance for your help

Could you please explain me why this works in the other servers?
In order for the deadlock to occur, there are three necessary parts:
A one-thread-at-a-time context, which all servers would have (the pre-Core ASP.NET context).
An await (without ConfigureAwait(false)) that acts asynchronously.
Code elsewhere that blocks a thread inside that context, waiting for the async method to finish. All servers also have this.
Most likely, the difference in behavior is due to the second part: an await that acts asynchronously. await first examines its awaitable (e.g., the Task passed to it), and if that awaitable is complete, then it continues executing the async method synchronously.
Specifically, this would happen if the Task<NameDTO> returned from GetAsync completed before the calling code hit the .Result. This would have to be extremely fast, but it's possible depending on caching, how fast your network hop is, how much the code is slowed down by load/neighbors/anti-virus, etc.

Related

REST-Call with async server implementation

In my application I have a server which provides a REST-Api where my UI can communicate with.
Now I have to start a long running Process on the Server but I want the client not to wait for the response of the server.
I know I could just fire and forget the Post-Call and not await the response but I need to know at the client that the Process on the server was startet correctly.
So I thought about the following:
[HttpPost]
[Route("startscan")]
public HttpResponseMessage StartScan()
{
Task.Factory.StartNew( () =>
{
//Do long running things here
});
return Request.CreateResponse(HttpStatusCode.OK);
}
So my question now is: Will the task I started be executed to it's end? Background of the question is, that as far as I knwo a controller-instance is created for each call to it. So will the instance of the controller be terminated when the requested finished or will the Task I started run to it's end. The task can take up to 10 minutes or longer sometimes.
A simple approach would be to just use an asynchronous method without awaiting the Task result like so:
[HttpPost]
[Route("startscan")]
public async HttpResponseMessage StartScan()
{
DoLongRunningThings();
return Request.CreateResponse(HttpStatusCode.OK);
}
public async Task DoLongRunningThings()
{
// Do Stuff here
}
However, if you Processing is more complex and requires more resilience you should look into how to use background jobs. Here is a good collection of what you can use: https://stackoverflow.com/a/36098218/16154479
Will the task I started be executed to it's end?
Probably yes, but also possibly no. Sometimes it won't be executed completely. This is the result of misusing an ASP.NET app (which handles HTTP requests) as a background service (which runs outside of a request context).
There is a best practice that avoids possibly-partial execution: a distributed architecture (as I describe on my blog). The idea is that your controller enqueues a message describing the work to be done into a durable queue and then returns. Then there's a separate background service that reads from the queue and does the actual work.

ASP.NET Web API - difference between Async and Synchronous method in browser's Network Console

I'm trying to understand this code that I just found in this link:
I'm curious of what's the difference when between using the asynchronous and synchronous method in the Web API:
Asynchronous:
[HttpGet("{id}", Name = "GetBook")]
public async Task<IActionResult> GetBookWithBookCovers(Guid id)
{
var bookEntity = await _booksRepository.GetBookAsync(id);
if (bookEntity == null)
{
return NotFound();
}
// get bookcovers
var bookCovers = await _booksRepository.GetBookCoversAsync(id);
// map book & covers into one BookWithCovers
var mappedBook = _mapper.Map<BookWithCovers>(bookEntity);
return Ok(_mapper.Map(bookCovers, mappedBook));
}
Synchronous:
[HttpGet("{id}", Name = "GetBook")]
public IActionResult GetBookWithBookCovers(Guid id)
{
var bookEntity = _booksRepository.GetBook(id);
if (bookEntity == null)
{
return NotFound();
}
// get bookcovers
var bookCovers = _booksRepository.GetBookCovers(id);
// map book & covers into one BookWithCovers
var mappedBook = _mapper.Map<BookWithCovers>(bookEntity);
return Ok(_mapper.Map(bookCovers, mappedBook));
}
If there is a long running query in one of the codes of these two methods, what will be the behavior in the network console of browser?
Is the asynchronous method going to return a status code 202 while the query is running? or it will error out and saying like query timeout?
As Ian Kemp said "async/await ... has no effect on the HTTP protocol".
Client perspective
There is not difference. The same OK status code would return in both cases if no exception would occur during the request processing.
Sync or Async processing should be considered as an implementation detail. If you would have a OpenAPI documentation (a.k.a Swagger) then the two methods would look exactly the same.
Server perspective
Your ASP.NET WebAPI would not return anything to the caller until it reaches the end of the Controller's Action.
The await keyword says:
There is possibly a long-running operation.
The executing Thread can't move on to the next statement, because it relies on the result of the async operation.
Because the Thread can't do anything with this request, it would make sense to return to the ThreadPool and assign a new job to it (for example another request) until the async operation is running.
When that async operation is finished the ThreadPool will be notified and it will schedule the remaining of the Controller's Action to the appropriate Thread.
The async/await was designed (primarily) to support non-blocking async I/O operations. That means while the network driver handles the I/O request until that time the computation executors (Threads) could work on other things.
So in short, async/await gives you scalability (bigger throughput) for server applications.

trying to run a function asynchronously using Async/Await, not working c#?

I want to run a method asynchronously from my web api code but I am not getting the desired behavior.
I am trying to do the LongCallMethod in an asynchronous way. So that I am able to return success to my user before the LongCallMethod completes.
I have tried various combination of calls with await and async but not getting any success still.
I might not be understanding the concept of async/await correctly.
Can you please let me know what's the mistake I am making?
My controller code is below
[HttpGet("{id}")]
public string Get(int id)
{
PracticeAsync p = new PracticeAsync();
p.LongCallMethod();
return "Success";
}
The code for the class PracticeAsync is below:
public class PracticeAsync
{
public async Task LongCallMethod()
{
var x = await CallThis();
}
public async Task<dynamic> CallThis()
{
Thread.Sleep(10000); //DB call
return "done";
}
}
I am trying to do the LongCallMethod in an asynchronous way. So that I am able to return success to my user before the LongCallMethod completes.
That's not how async works.
You'll need to use SignalR or a proper distributed architecture. Specifically, your webapp should place its work into a reliable queue, and have an independent service read from that queue and do the work. ASP.NET was designed to serve web requests, and has severe reliability limitations if you try to force it to do otherwise.

best practice for using async await in webapi

I have .NET core Web API which as service layer. Service layer has all EF code.
If have basecontroller with this code
protected Task<IActionResult> NewTask(Func<IActionResult> callback)
{
return Task.Factory.StartNew(() =>
{
try
{
return callback();
}
catch (Exception ex)
{
Logger.LogError(ex.ToString());
throw;
}
});
}
In controller action I wrap all calls to service in above method e.g. :
[HttpGet("something")]
public async Task<IActionResult> GetSomething(int somethingId)
{
return await NewTask(() =>
{
var result = _somethingService.GetSomething(somethingId);
if (result != null)
return Ok(result);
else
return NotFound("Role not found");
});
}
Is this correct pattern considering tomorrow I may have more than one service calls in action or making calls to other webservice. Please advise.
i want my api to benefit from async await thing.does above pattern will serve these needs
No, it does not. Running synchronous work on the thread pool gives you the drawbacks of synchronous and asynchronous code, with the benefits of neither.
something service has some crud operations which use entityframework core
Currently, your action method is what I call "fake asynchronous" - it looks asynchronous (e.g., using await), but in fact is just running blocking code on a background thread. On ASP.NET, you want true asynchrony, whicn means you must be async all the way. For more about why this is bad on ASP.NET, see the first half of my intro to async on ASP.NET article (it mostly deals with ASP.NET non-core, but the first part talking about synchronous vs asynchronous requests is valid for any kind of server).
To make this truly asynchronous, you should start at the lowest level - in this case, your EFCore calls. They all support asynchrony. So, replace API calls like x.FirstOrDefault() with await x.FirstOrDefaultAsync() (and the same for all your creates/updates/deletes, etc).
Then allow async/await to grow naturally from there; the compiler will guide you. You'll end up with asynchronous methods on your somethingService which can be consumed as such:
[HttpGet("something")]
public async Task<IActionResult> GetSomething(int somethingId)
{
var result = await _somethingService.GetSomethingAsync(somethingId);
if (result != null)
return Ok(result);
else
return NotFound("Role not found");
}
Okay, first of all, you should stop using Task.Factory.StartNew and use Task.Run only when you have heavy CPU-bound work that you want to run on a thread pool thread. In you case you don't really need that at all. Also you should remember that you should only use Task.Run when calling a method and not in the implementation of the method. You can read more about that here.
What you really want in your case is to have asynchronous work inside your service (I'm not really sure you even need a service in your case) when you are actually making a call to the database and you want to use async/await and not just run some stuff on a background thread.
Basically your service should look something like this (if you are sure you need a service):
class PeopleService
{
public async Task<Person> GetPersonByIdAsync(int id)
{
Person randomPerson = await DataContext.People.FirstOrDefaultAsync(x => x.Id == id);
return randomPerson;
}
}
As you can see your service now makes async calls to the database and that's basically what your pattern should be. You can apply this to all your operations(add/delete/ etc..)
After making your service asynchronous you should be easily able to consume the data in the action.
Your actions should look something like this:
[HttpGet("something")]
public async Task<IActionResult> GetPerson(int id)
{
var result = await PeopleService.GetPersonByIdAsync(id);
if (result != null)
return Ok(result);
else
return NotFound("Role not found");
}

Problems And Errors While Implementing Async Controller Action

It seems that I have massive problems understanding the topic regarding async-operations in C# and especially ASP.NET MVC in Controller.
I have a Controller for all of my AJAX-Requests from my Webpage. for each I have an action. Now I try to implement like a 'notification-system'. I created a class which handles the notification in a Queue, which are selected through a dictionary using the SessionID.
Because I am using Reverse-AJAX, the Thread working on the AJAX-Response needs to be hold at the Server. Therefore, I used Thread.Sleep in combination with a while to check if the queue has elements or not. Here is the part of the controller:
public class AJAXController : AsyncController
{
public async void polling()
{
if (Session["init"] == null) //so the sessionID is not changing on every request
Session.Add("init", 0);
NotificationQueue queue =
NotificationQueue.getInstance(HttpContext.Session.SessionID);
object responseObj = null;
responseObj = await Task.Run(() =>
{
while (queue.getSize() == 0)
Thread.Sleep(200);
return queue.getNextQueueElement(); //behind this is queue.Dequeue();
});
Response.Write(new JavaScriptSerializer().Serialize(responseObj));
}
}
Basically, I don't now what is incorrect with that code - neither I know with is correct.
The syntax is correct, but when I try to use the website, the Server answers with: 500 (internal Server error), Message: >>An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%# Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it.<<
Do I need an AsyncController? The other methods aren't Asynchronous because these are just simple responses.
I tried to use public async void pollingAsync() in Combination with public async string pollingCompleted(string response), but the parameter was null every time.
My Questions are the above and how I can solve the problem. Is there a better solution, and when yes, how could I implement this?
I appreciate any help!
Don't use async void, use async Task instead. async void operations are generally fire and forget, as you have no way of asynchronously waiting on them. Also, there's no need to use AsyncController when using async-await. You can read more about that here
You need:
public async Task PollingAsync()
{
if (Session["init"] == null) //so the sessionID is not changing on every request
Session.Add("init", 0);
NotificationQueue queue =
NotificationQueue.getInstance(HttpContext.Session.SessionID);
while (queue.GetSize() == 0)
await Task.Delay(200);
var responseObj = queue.getNextQueueElement();
Response.Write(new JavaScriptSerializer().Serialize(responseObj));
}
Generally speaking, as a side note, you can get around the "polling" experience by using websockets, with a technology such as SignalR this is even made quite easy and friendly. I'd recommend looking into that.

Categories