.NET Core 3.1应用启动时如何异步加载配置,避免调用.Wait()?
当然有更优雅的异步实现方案啦,完全能避开.Wait()这种容易引发死锁的同步阻塞操作!给你分享两种在.NET Core 3.1里可行的思路:
异步读取配置的两种可行方案
方案一:利用主机的异步启动能力
这是最推荐的做法,因为.NET Core 3.1原生支持主机的异步配置流程,能从根源上避免同步阻塞问题。你只需要把服务配置逻辑放到ConfigureServicesAsync方法里,就能直接使用await处理异步操作:
public static async Task Main(string[] args) { var host = Host.CreateDefaultBuilder(args) .ConfigureServicesAsync(async (context, services) => { services.AddSingleton(context.Configuration); var applicationSettings = new ApplicationSettings(context.Configuration); // 直接await异步读取方法,无需阻塞 await applicationSettings.ReadApplicationSettingsAsync(); services.AddSingleton<IApplicationSettings>(applicationSettings); }) .Build(); await host.RunAsync(); }
这种方式完全贴合ASP.NET Core的异步启动模型,既安全又符合最佳实践,再也不用担心死锁问题。
方案二:使用异步工厂模式注册服务
如果不想改动Main方法的现有结构,也可以通过异步工厂委托来注册IApplicationSettings服务。利用AddSingleton的重载版本,接受一个异步的工厂方法:
public static IServiceCollection AddApplicationSettings(this IServiceCollection services, IConfiguration configuration) { services.AddSingleton<IApplicationSettings>(async _ => { var applicationSettings = new ApplicationSettings(configuration); await applicationSettings.ReadApplicationSettingsAsync(); return applicationSettings; }); return services; }
不过要注意:这种方式下,第一次解析IApplicationSettings的地方必须是异步上下文(比如在控制器的异步Action里、中间件的InvokeAsync方法里)。如果在同步上下文(比如控制器构造函数)里解析,还是会触发同步阻塞,所以这种方案适合特定场景下使用。
为什么要避免.Wait()?
在ASP.NET Core的同步上下文中,调用.Wait()或.Result很容易导致死锁——因为异步操作会试图回到原同步上下文,但该上下文已经被同步阻塞的线程占用,最终造成线程死锁。异步方案能从根本上避免这个问题,同时提升启动阶段的资源利用率。
内容的提问来源于stack exchange,提问作者Angela
相关产品推荐
相关产品推荐

