I've tried to read up on async methods and am now trying to create my own async method. The method is a webservice call that returns a list of error logs. I'm not sure that I've understood correctly so I thought I'd share my code to see if I should do anything different.
All I want the code to do is return a list of errorlogs by calling a method GetAllErrorLogs(), that is a synchronized method. Since it can take a second to fetch all the error logs I want to have the opportunity to do other stuff once I called the GetAllErrorLogs() method. Here is the code.
[WebMethod]
public async Task<List<ErrorLog>> GetAllErrorLogs()
{
List<ErrorLog> errorLogs = new List<ErrorLog>();
await System.Threading.Tasks.Task.Run(() => {
errorLogs = ErrorLogRepository.GetAllErrorLogs();
});
if (errorLogs == null)
return new List<ErrorLog>();
return errorLogs;
}
Thanks!
The asynchronous web services receives the request, sends a confirmation message to the initiating client, and starts process the request. Once processing of the request is complete, the asynchronous web service acts as a client to send the response back to the callback service.
First, you tell the Web service to begin execution by calling the Begin method. The second step, calling the End method, completes the web service call and returns the response. To call a web service asynchronously, a client thread can use a WaitHandle.
In the context of Web API, Asynchronous programming is used to improve the scalability of the application. By applying asynchronous programming using async and await there won't be any direct performance gain in speed instead application will be able to handle more concurrent requests.
I recently gave a talk at ThatConference on async
on the server side, and I address this issue in the slides.
On the server side, you want to avoid the use of Task.Run
and other constructs that queue work to the thread pool. As much as possible, keep thread pool threads available for handling requests.
So, ideally your repository would have an asynchronous method GetAllErrorLogsAsync
, which would itself be asynchronous. If GetAllErrorLogs
cannot be asynchronous, then you may as well just call it directly (removing the await Task.Run
).
Since it can take a second to fetch all the error logs I want to have the opportunity to do other stuff once I called the GetAllErrorLogs() method.
If you have a GetAllErrorLogsAsync
available, then this can easily be done using Task.WhenAll
. However, if GetAllErrorLogs
is synchronous, then you can only do this by doing parallel work in your request (e.g., multiple calls to Task.Run
followed by Task.WhenAll
).
Parallel code on the server must be approached with great trepidation. It is only acceptable in a very limited set of scenarios. The entire point of async
on the server side is to use fewer threads per request, and when you start parallelizing, you're doing the opposite: multiple threads per request. This is only appropriate if you know your user base is very small; otherwise, you'll kill your server scalability.
I found this great codeproject detailed article about how to achieve that
http://www.codeproject.com/Articles/600926/Asynchronous-web-services-call-in-ASP-NET
**This is potentially wrong, read comments or spinoff question at HttpContext.Current after an await
If ErrorLogRepository.GetAllErrorLogs()
is not thread-safe, it will cause weird bugs and potentially exception out. Make sure your code is ready for multi-threaded operation before switching to async methods, this is obviously very trivial advice but often overlooked. For example, if you reference HttpContext.Current
in your methods, your code will die in the async method, and sometimes even AFTER the await
. The reason is that the code within the async block will potentially be run on a separate thread, which will not have access to the same HttpContext.Current
thread-static property, and await
gets compiled into two methods. All code before an await
gets run on one thread, and then calls the code after an await keyword as a continuation, but potentially on yet another thread. So sometimes your code will even work in an async block, only to choke unexpectedly after it gets "out" of the async back to what you think is a synchronous part of your code (but in reality everything after an await
keyword is already not guaranteed to be the original thread).
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