创建异步Web服务方法

我试图阅读异步方法,现在我正在尝试创建自己的异步方法。 该方法是一个webservice调用,它返回错误日志列表。 我不确定我是否理解正确,所以我想我会分享我的代码,看看我是否应该做任何不同的事情。

我想要的代码就是通过调用方法GetAllErrorLogs()来返回错误日志列表,这是一个同步方法。 因为我可能需要一秒钟来获取所有错误日志,所以当我调用GetAllErrorLogs()方法时,我希望有机会做其他的事情。 这是代码。

[WebMethod] public async Task<List> GetAllErrorLogs() { List errorLogs = new List(); await System.Threading.Tasks.Task.Run(() => { errorLogs = ErrorLogRepository.GetAllErrorLogs(); }); if (errorLogs == null) return new List(); return errorLogs; } 

谢谢!

我最近在服务器端的 Async上发表了关于async讨论 ,我在幻灯片中解决了这个问题。

在服务器端,您希望避免使用Task.Run和其他将队列工作Task.Run线程池的构造。 尽可能保持线程池线程可用于处理请求。

因此,理想情况下,您的存储库将具有异步方法GetAllErrorLogsAsync ,它本身就是异步的。 如果GetAllErrorLogs不能是异步的,那么你也可以直接调用它(删除await Task.Run )。

因为我可能需要一秒钟来获取所有错误日志,所以当我调用GetAllErrorLogs()方法时,我希望有机会做其他的事情。

如果您有GetAllErrorLogsAsync可用,那么可以使用Task.WhenAll轻松完成。 但是,如果GetAllErrorLogs是同步的,那么您只能通过在请求中执行并行工作来执行此操作(例如,多次调用Task.Run然后调用Task.WhenAll )。

必须非常谨慎地处理服务器上的并行代码。 它只能在非常有限的场景中接受。 服务器端async的整个要点是每个请求使用更少的线程,当你开始并行化时,你正在做相反的事情:每个请求多个线程。 这只适用于您知道您的用户群非常小的情况; 否则,你将扼杀你的服务器可扩展性。

我发现这个伟大的代码项目详细文章有关如何实现这一点

http://www.codeproject.com/Articles/600926/Asynchronous-web-services-call-in-ASP-NET

**这可能是错误的,在等待之后在HttpContext.Current上阅读评论或衍生问题

如果ErrorLogRepository.GetAllErrorLogs()不是线程安全的,它将导致奇怪的错误并可能导致exception。 在切换到异步方法之前,确保您的代码已准备好进行multithreading操作,这显然是非常简单的建议,但经常被忽略。 例如,如果在方法中引用HttpContext.Current ,则代码将在异步方法中死亡,有时甚至在await 。 原因是异步块中的代码可能会在一个单独的线程上运行,该线程无法访问相同的HttpContext.Current线程静态属性,并且await会被编译为两个方法。 await之前的所有代码都在一个线程上运行,然后在await关键字之后调用代码作为延续,但可能在另一个线程上调用。 因此,有时您的代码甚至可以在异步块中工作,只是在异步“退出”之后意外地阻塞回您认为是代码的同步部分(但实际上, await关键字之后的所有内容都已经无法保证成为原始线程)。

这是一些生产代码……

 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); } } } 

处理异步exception也非常重要..虽然这适用于Windows控制台应用程序,但应遵循相同的原则。

来源: 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); } } 

}