在我的ASP.NET 5应用程序中,我想将Azure中的一些数据加载到Startup.Configure方法中的缓存中 . Azure SDK专门公开异步方法 . 通常,调用异步方法是通过等待异步方法来完成的,如下所示:
public async Task Configure(IApplicationBuilder app, IMemoryCache cache)
{
Data dataToCache = await DataSource.LoadDataAsync();
cache.Set("somekey", dataToCache);
// remainder of Configure method omitted for clarity
}
但是,ASP.NET 5要求Configure方法返回void . 我可以使用异步void方法,但我的理解是异步void方法只应该用于事件处理程序(根据https://msdn.microsoft.com/en-us/magazine/jj991977.aspx等) .
我认为更好的方法是在没有等待的情况下调用异步函数,在返回的Task上调用Wait,然后通过Task.Results属性缓存结果,如下所示:
public void Configure(IApplicationBuilder app, IMemoryCache cache)
{
Task<Data> loadDataTask = DataSource.LoadDataAsync();
loadDataTask.Wait();
cache.Set("somekey", loadDataTask.Result);
// remainder of Configure method omitted for clarity
}
今年早些时候,斯蒂芬沃尔特在blog post采用了类似的方法 . 但是,如果这被认为是可以接受的做法,则从该帖子中不清楚 . 是吗?
如果这被认为是可接受的做法,我需要什么 - 如果有的话 - 错误处理?我的理解是Task.Wait()将重新抛出异步操作引发的任何异常,并且我没有提供任何取消异步操作的机制 . 简单地调用Task.Wait()就足够了吗?
3 回答
您链接到的博客中的示例代码仅使用sync-over-async来使用示例数据填充数据库;该调用在 生产环境 应用程序中不存在 .
首先,我要说如果你真的需要
Configure
是异步的,那么你应该向ASP.NET团队提出一个问题,这样就可以了 . 他们在此时(即发布之前)添加对ConfigureAsync
的支持并不太难 .其次,你有几种解决问题的方法 . 您可以使用
task.Wait
(或者更好,task.GetAwaiter().GetResult()
,如果确实发生错误,则会避免使用AggregateException
包装器) . 或者,你可以缓存任务而不是任务的结果(如果IMemoryCache
更像是一个字典而不是一些奇怪的序列化到二进制数组内存中的东西 - 这是有效的 - 我正在看着你,以前的版本ASP.NET) .使用
GetAwaiter().GetResult()
会导致异常(如果有)传播出Configure
. 但是,如果配置应用程序失败,我不确定ASP.NET会如何响应 .我不知道你怎么能设置一个应用程序,所以我不担心它的那一部分 .
您可以执行一些异步工作,但该方法是同步的,您无法更改它 . 这意味着您需要同步等待异步调用完成 .
如果启动尚未完成,您不想从启动方法返回,对吗?你的解决方案似乎没问题 .
至于异常处理:如果's a piece of work that your application can' t没有正常运行,你应该让Startup方法失败(参见Fail-fast) . 如果它不重要,我会将相关部分包含在try catch块中,并记录问题以便以后检查 .
如果您的异步代码进行进一步的异步调用,这里的答案并不总能正常工作,特别是如果这些是回调,那么您可能会发现代码死锁 .
这种情况在很多场合都发生在我身上,并且使用了Nito.AsyncEx效果很好 .