为何.NET依赖注入控制台程序无报错以退出码0终止?
问题描述
我需要开发一个名为Port的.NET控制台应用程序,它引用了包含数据模型等内容的名为Data的类库项目。
Data项目中用于扩展IServiceCollection的静态类及方法代码如下:
public static class ServiceCollectionsFish { public static IServiceCollection RegisterFishServices(this IServiceCollection services, IConfiguration configuration) { services.AddDbContext<FishContext>(o => { o.UseSqlServer(configuration.GetConnectionString("Legacy")); o.EnableDetailedErrors(); o.EnableSensitiveDataLogging(); }); services.AddTransient<IBrandRepository, BrandRepository>(); services.AddTransient<IBrandGroupRepository, BrandGroupRepository>(); return services; } }
该Data项目同时被一个WEB API项目引用,运行正常。
控制台应用包含Program.cs和appsettings.json,Program.cs中构建配置的静态方法:
static void BuildConfig(IConfigurationBuilder builder) { builder.SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true) .AddEnvironmentVariables(); }
主方法代码:
static void Main(string[] args) { var builder = new ConfigurationBuilder(); BuildConfig(builder); var host = Host.CreateDefaultBuilder() .ConfigureServices((context, services) => { services.RegisterFishServices(builder.Build()); services.AddTransient<IStart, Start>(); }).Build(); var start = ActivatorUtilities.CreateInstance<Start>(host.Services); start.Test(); }
Start类代码:
public class Start : IStart { private readonly IBrandRepository _brandRepository; public Start(IBrandRepository brandRepository) { _brandRepository = brandRepository; // 此处代码正常运行 Brand_ brand = _brandRepository.GetById(new Guid("8D09F3E2-322B-4AFF-A4F2-57BDE98A78B5")).Result; Console.WriteLine("OK"); } public async Task Test() { try { // 程序执行到此处直接退出,后续代码不执行 Brand_? brand = await _brandRepository.GetById(new Guid("8D09F3E2-322B-4AFF-A4F2-57BDE98A78B5")); Console.WriteLine(brand); Console.WriteLine("OK"); } catch(Exception ex) { Console.WriteLine(ex.ToString()); } } }
问题:调用Test()方法时,程序从未执行到Console.WriteLine(brand)就直接以退出码0终止,无异常抛出;但在构造函数中执行相同逻辑却能正常运行,请问原因是什么?
原因分析
核心问题是同步方法调用异步方法未等待:
Main方法是返回void的同步方法,调用start.Test()这个异步方法时,没有等待其执行完成。- 异步方法执行到
await _brandRepository.GetById(...)时,会释放当前线程回到Main方法,此时Main已经执行完所有代码,直接终止程序,导致异步后续的数据库查询、打印逻辑根本没机会执行。 - 构造函数中用
.Result是同步阻塞等待异步方法完成,会一直等到数据库操作结束再继续,所以程序不会提前退出,逻辑能正常执行。
解决方案
有两种常见的修复方式:
方式1:将Main改为异步入口方法
.NET支持异步的Main方法,修改后可以正常等待异步操作完成:
static async Task Main(string[] args) { var builder = new ConfigurationBuilder(); BuildConfig(builder); var host = Host.CreateDefaultBuilder() .ConfigureServices((context, services) => { services.RegisterFishServices(builder.Build()); services.AddTransient<IStart, Start>(); }).Build(); var start = ActivatorUtilities.CreateInstance<Start>(host.Services); await start.Test(); // 等待异步方法执行完成 }
方式2:同步阻塞等待异步方法完成
如果不想修改Main的返回类型,可以调用.Wait()或.GetAwaiter().GetResult()来阻塞等待:
static void Main(string[] args) { var builder = new ConfigurationBuilder(); BuildConfig(builder); var host = Host.CreateDefaultBuilder() .ConfigureServices((context, services) => { services.RegisterFishServices(builder.Build()); services.AddTransient<IStart, Start>(); }).Build(); var start = ActivatorUtilities.CreateInstance<Start>(host.Services); start.Test().Wait(); // 阻塞等待异步方法执行完毕 }
内容的提问来源于stack exchange,提问作者Vladimir99
相关产品推荐
相关产品推荐

