Creating the async webservice method

I tried to read async methods, and now I'm trying to create my own async method. This method is a webservice call that returns a list of error logs. I'm not sure I understood correctly, so I decided that I would share my code to see if I need to distinguish something.

All I want to do is return a list of errors by calling GetAllErrorLogs (), which is a synchronized method. Since it may take a second to get all the error logs, I want to be able to do other things as soon as I call 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; } 

Thank!

+8
c # async-await
Aug 21 '13 at 20:28
source share
5 answers

I recently talked on ThatConference on async on the server side , and I look at this issue in slides.

On the server side, you want to avoid using Task.Run and other constructs that work in line with the thread pool. Whenever possible, support thread pool threads for handling requests.

So, ideally, your repository will have an asynchronous GetAllErrorLogsAsync method, which itself will be asynchronous. If GetAllErrorLogs cannot be asynchronous, you can simply call it directly (removing await Task.Run ).

Since it might take a second to get all the error logs, I want to be able to do other things as soon as I call the GetAllErrorLogs () method.

If you have GetAllErrorLogsAsync , then this can be easily done using Task.WhenAll . However, if GetAllErrorLogs is synchronous, you can do this by doing parallel work in your query (for example, several calls to Task.Run and then Task.WhenAll ).

Parallel code on the server should be greeted with great trepidation. This is acceptable only in a very limited set of scenarios. The whole point of async on the server side is to use fewer threads for each request, and when you start parallelizing, you do the opposite: multiple threads for each request. This is only suitable if you know that your user base is very small; otherwise, you will kill the scalability of your server.

+7
Aug 21 '13 at 20:54 on
source share
+2
Aug 21 '13 at 20:52
source share

** This is potentially incorrect, read the comments or spinoff question on HttpContext.Current after waiting

If ErrorLogRepository.GetAllErrorLogs() not thread safe, this will cause strange errors and a potential exception. Make sure your code is ready for multi-threaded work 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 asynchronization method, and sometimes even AFTER await . The reason is that the code inside the asynchronous block will potentially run in a separate thread that will not have access to the same HttpContext.Current static stream property, and await will be compiled into two methods. All the code before await run in one thread and then calls the code after the wait keyword as a continuation, but potentially in another thread. Therefore, sometimes your code will work even in an asynchronous block, only to choke unexpectedly after it "exits" from async back to what you consider to be the synchronous part of your code (but in fact everything after the await keyword is no longer guaranteed to be original thread).

0
Aug 21 '13 at 20:52
source share

Here is the production code ...

 using System.Web.Http; using AysncTask = System.Threading.Tasks.Task; public class myController : ApiControllerBase { [HttpPut] [Route("api/cleardata/{id}/{requestId}/")] public async AysncTask ClearData(Guid id, Guid requestId) { try { await AysncTask.Run(() => DoClearData(id, requestId)); } catch (Exception ex) { throw new Exception("Exception in myController.ClearData", ex); } } } 
0
Mar 28 '17 at 0:17
source share

Async exception handling is also VERY VERY important .. although this is for a Windows console application, the same principles should apply.

source: https://blogs.msdn.microsoft.com/ptorr/2014/12/10/async-exceptions-in-c/

  using System; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; namespace AsyncAndExceptions { class Program { static void Main(string[] args) { AppDomain.CurrentDomain.UnhandledException += (s, e) => Log("*** Crash! ***", "UnhandledException"); TaskScheduler.UnobservedTaskException += (s, e) => Log("*** Crash! ***", "UnobservedTaskException"); RunTests(); // Let async tasks complete... Thread.Sleep(500); GC.Collect(3, GCCollectionMode.Forced, true); } private static async Task RunTests() { try { // crash // _1_VoidNoWait(); // crash // _2_AsyncVoidAwait(); // OK // _3_AsyncVoidAwaitWithTry(); // crash - no await // _4_TaskNoWait(); // crash - no await // _5_TaskAwait(); // OK // await _4_TaskNoWait(); // OK // await _5_TaskAwait(); } catch (Exception ex) { Log("Exception handled OK"); } // crash - no try // await _4_TaskNoWait(); // crash - no try // await _5_TaskAwait(); } // Unsafe static void _1_VoidNoWait() { ThrowAsync(); } // Unsafe static async void _2_AsyncVoidAwait() { await ThrowAsync(); } // Safe static async void _3_AsyncVoidAwaitWithTry() { try { await ThrowAsync(); } catch (Exception ex) { Log("Exception handled OK"); } } // Safe only if caller uses await (or Result) inside a try static Task _4_TaskNoWait() { return ThrowAsync(); } // Safe only if caller uses await (or Result) inside a try static async Task _5_TaskAwait() { await ThrowAsync(); } // Helper that sets an exception asnychronously static Task ThrowAsync() { TaskCompletionSource tcs = new TaskCompletionSource(); ThreadPool.QueueUserWorkItem(_ => tcs.SetException(new Exception("ThrowAsync"))); return tcs.Task; } internal static void Log(string message, [CallerMemberName] string caller = "") { Console.WriteLine("{0}: {1}", caller, message); } } 

}

0
Mar 29 '17 at 23:12
source share



All Articles