Dev*_*awk 64 c# async-await asp.net-core
在我的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
}
Run Code Online (Sandbox Code Playgroud)
但是,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
}
Run Code Online (Sandbox Code Playgroud)
Stephen Walther在今年早些时候的博客文章中采用了类似的方法.但是,如果这被认为是可以接受的做法,则从该帖子中不清楚.是吗?
如果这被认为是可接受的做法,我需要什么 - 如果有的话 - 错误处理?我的理解是Task.Wait()将重新抛出异步操作引发的任何异常,并且我没有提供任何取消异步操作的机制.简单地调用Task.Wait()就足够了吗?
Ste*_*ary 33
您链接到的博客中的示例代码仅使用sync-over-async来使用示例数据填充数据库; 该调用在生产应用程序中不存在.
首先,我要说如果你真的需要Configure异步,那么你应该向ASP.NET团队提出一个问题,这样就可以了.他们ConfigureAsync在此时(即发布之前)添加对a的支持并不太难.
其次,你有几种解决问题的方法.您可以使用task.Wait(或者更好的是,如果确实发生错误,则会task.GetAwaiter().GetResult()避免使用AggregateException包装器).或者,您可以缓存任务而不是任务的结果(如果IMemoryCache更多的是字典而不是一些奇怪的序列化到二进制数组内存中的东西 - 我正在看着你,以前版本的ASP .净).
如果这被认为是可接受的做法,我需要什么 - 如果有的话 - 错误处理?
使用GetAwaiter().GetResult()会导致异常(如果有)传播出来Configure.但是,如果配置应用程序失败,我不确定ASP.NET会如何响应.
我没有提供任何取消异步操作的机制.
我不确定你如何"取消" 应用程序的设置,所以我不担心它的那一部分.
jos*_*ode 12
Dotnet Core 3.x 对此提供了更好的支持。
首先,您可以为缓存过程创建一个类。让它实现IHostedService如下。只需实现两个功能:
private readonly IServiceProvider _serviceProvider;
public SetupCacheService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
// Perform your caching logic here.
// In the below example I omit the caching details for clarity and
// instead show how to get a service using the service provider scope.
using (var scope = _serviceProvider.CreateScope())
{
// Example of getting a service you registered in the startup
var sampleService = scope.ServiceProvider.GetRequiredService<IYourService>();
// Perform the caching or database or whatever async work you need to do.
var results = sampleService.DoStuff();
var cacheEntryOptions = new MemoryCacheEntryOptions(){ // cache options };
// finish caching setup..
}
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
Run Code Online (Sandbox Code Playgroud)
现在,在 Starup.cs
public virtual void ConfigureServices(IServiceCollection services)
{
// Normal service registration stuff.
// this is just an example. There are 1000x ways to do this.
services.AddTransient(IYourService, ConcreteService);
// Here you register the async work from above, which will
// then be executed before the app starts running
services.AddHostedService<SetupCacheService>();
}
Run Code Online (Sandbox Code Playgroud)
就是这样。请注意,我对此的解决方案在很大程度上依赖于Andrew Lock 的文章。我非常感谢他花时间写下来。
来自我发布的 Andrew Lock 的链接,
服务将在启动时按照它们添加到 DI 容器的相同顺序执行,即稍后在 ConfigureServices 中添加的服务将在启动时执行。
希望这可以帮助任何寻找 Dotnet 核心 3.x+ 方法的人。
| 归档时间: |
|
| 查看次数: |
9471 次 |
| 最近记录: |