【问题标题】:DI in Program.cs stopped working after upgrade .NET Core from 2 to 3将 .NET Core 从 2 升级到 3 后 Program.cs 中的 DI 停止工作
【发布时间】:2020-10-27 07:31:20
【问题描述】:

我有 ASP.NET Core 应用程序,我需要从外部 AWS 服务获取数据库凭证。本质上,我需要将 CredentialRetrievalService 注入 Startup.cs。不久前,我发现了一个example,它完美地描述了如何做到这一点:

Program.cs:

public static void Main(string[] args)
{
    BuildWebHost(args).Run();
}

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .ConfigureServices(serviceCollection =>
            serviceCollection.AddScoped<ISomeService, SomeService>())
        .UseStartup<Startup>()
        .Build();
}   

Startup.cs:

private ISomeService _someService;
public Startup(IConfiguration configuration, ISomeService someService)
{
    _someService = someService;
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    // Just to see that everything works - and it does!
    services.AddMvc(options =>
        {
            options.MaxModelValidationErrors = _someService.GetNumber(Configuration.GetValue<int>("MaxModelValidationErrors"));
        });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseMvc();
}

现在我正在尝试将应用程序升级到 ASP.NET Core 3。我可以看到有breaking change,上面的代码不再起作用了。建议的操作是将服务注入Startup.Configure 方法。但是如果需要在ConfigureServices调用注入服务怎么办呢?

【问题讨论】:

  • IWebHost BuildWebHost 切换到IHostBuilder CreateHostBuilder 是否可行? (1)
  • @PeterCsala - 是的,在 Core 3 中我使用的是IHostBuilder。使用 IWebhost 它甚至无法编译。 BuildWebHost / CreateHostBuilder 只是Program 类中的一个局部函数名

标签: c# asp.net-core dependency-injection asp.net-core-3.1


【解决方案1】:

经过更多分析,这似乎是可行的:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddScoped<ISomeService, SomeService>();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IOptions<MvcOptions> options, ISomeService someService)
{
    // ...
    int value = Configuration.GetValue<int>("MaxModelValidationErrors");
    options.Value.MaxModelValidationErrors = someService.GetNumber(value);
    // ...
}

但它不适用于我的 real 应用程序,其中 SomeServiceDbContext

【讨论】:

  • 这是什么意思:在这种特殊情况下“不起作用”?
【解决方案2】:

在配置选项时考虑改变方法并利用依赖注入

参考Use DI services to configure options

public Startup(IConfiguration configuration) {
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services) {

    //...

    services.AddScoped<ISomeService, SomeService>();        

    services.AddMvc(); //options will be configured lower down

    //Use DI services to configure MVC options
    services.AddOptions<MvcOptions>()
        .Configure<ISomeService>((options, someService) => {
            int value = Configuration.GetValue<int>("MaxModelValidationErrors");
            options.MaxModelValidationErrors = someService.GetNumber(value);
        });
        
    //...
}

//...

【讨论】:

  • 谢谢(抱歉,我出去几天了)。首先,我认为您的意思是 Configure(SomeService),而不是 ISomeService,对吧?链接中的文档显示传递服务类型,而不是接口。如果我这样做 - 我会收到以下异常:InvalidOperationException: No service for type SomeService has been registered. 不确定,为什么或如何注册服务。 FWIW,我没有在 SomeService 中有参数化构造函数,因此注册一个瞬态通用 IConfigureNamedOptions (如在文档中)应该可以工作
  • @Felix 我的意思是使用界面。在上面的答案中,我只省略了它的注册,因为它没有在原始帖子中显示。
  • @Felix 您可能需要重新格式化问题,以便我们更好地了解您实际上想要做什么。您似乎遗漏了一些非常相关的细节。
猜你喜欢
  • 2016-04-04
  • 2022-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-12
  • 1970-01-01
相关资源
最近更新 更多