我应该如何在启动时在ConfigurationServices ASP.NET Core 2.0中使用appsettings.json配置键/值?

时间:2017-09-08 13:17:03

标签: c# asp.net asp.net-core

我正在尝试为ASP.NET Core 2.0应用程序/网站配置我的服务。

我希望在此方法中引用appsettings.json文件中的一些键/值。

我不确定我的目标是否正常:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvcCore()
            .AddJsonFormatters()
            .AddCors();

    var applicationSettings = Configuration.GetSection("Settings").Get<ApplicationSettings>();
    services.AddSingleton(applicationSettings);

    // ** THIS IS WHAT I ORIGINALLY HAD, BUT IT'S ONLY SETTING
    //    THE VALUE IN DI/IOC.
    //services.Configure<ApplicationSettings>(options => Configuration.GetSection("Settings")
    //                                                                .Bind(options));

    var foo = new Foo(applicationSettings.SomeSetting);
    services.AddSingleton(foo);  
}

了解我如何手动添加单例,然后再引用应用设置实例中的值?

VS

只是配置......

所以,无论哪种方式都好,或者是否存在/或?

的具体原因

记住 - &gt;我需要将我的设置注入控制器等......

2 个答案:

答案 0 :(得分:2)

从技术上讲,你可以做到。在这两种情况下,您都可以通过依赖注入注册和使用配置,因此一切都可以依赖于它并获得配置实例。

您还在那里使用集中设置Configuration,因此您可以从配置堆栈获得所有好处,例如:多个提供者或特定于环境的覆盖。

然而,这种好处肯定转移到消费自定义配置的IOptions方式。它是“最先进的”,并且在整个ASP.NET Core中用于所有内容。它还允许您切换到可在运行时更新的选项。这是非常强大的,最终可能会变得有用(不一定适用于单身人士的特定情况,但可能是其他的)。

设置它也很容易,实际上比你尝试的要短:

services.Configure<ApplicationSettings>(Configuration.GetSection("Settings"));

services.AddSingleton<Foo>();

请注意,即使对于单身人士,也不应该明确地创建它的新实例,而是让DI处理它。如果您的类具有正确的构造函数,则无论如何都将自动注入依赖项:

public class Foo
{
    private readonly ApplicationSettings _settings;

    public Foo (IOptions<ApplicationSettings> settings)
    {
        _settings = settings.Value;
    }
}

当然,Foo在这里也可以有更多的依赖关系。由于它将由DI构建,因此您只需在构造函数中添加更多依赖项,而无需在某处更新某些new调用。

如果您需要使用取决于您的配置的设置来配置某些服务,您仍然不应该直接绑定您的配置。所有配置都是基于DI的,所以你只需注入正确的东西;一个IConfigureOptions<T>。这基本上是稍后为服务提供IOptions<T>的东西。在您的JWT案例中,这可能如下所示:

// instead of passing an option configuration delegate here…
services.AddAuthentication().AddJwtBearer();

// … we register a IConfigureOptions<JwtBearerOptions> instead
services.AddSingleton<IConfigureOptions<JwtBearerOptions>, ConfigureJwtBearerOptions>();

// … ConfigureJwtBearerOptions could look like this:
class ConfigureJwtBearerOptions : IConfigureOptions<JwtBearerOptions>
{
    private readonly ApplicationSettings _settings;

    public ConfigureJwtBearerOptions(IOptions<ApplicationSettings> settings)
    {
        _settings = settings.Value;
    }

    public void Configure(JwtBearerOptions options)
    {
        // configure JwtBearerOptions here, and use your ApplicationSettings
        options.MetadataAddress = _settings.JwtMetadataAddress;
    }
}

与仅将委托传递给AddJwtBearer()相比,这看起来可能显得过于冗长,但请注意,当您传递该委托时,这正是在幕后发生的事情:将创建一个调用您的IConfigureOptions<JwtBearerOptions>对象在Configure()电话中委托。所以这真的是一样的。

请注意,对于身份验证方案,您实际上可能会设置IConfigureNamedOptions<T>,这几乎是相同的,除了它可以根据名称配置选项。对于身份验证方案,即方案名称,所以基本上您在Configure()中检查方案名称,然后决定如何配置选项。

至于创建单例实例,特别是昂贵的实例,我认为ConfigureServices对于这样的事情是错误的。在应用程序启动阶段很早就调用ConfigureServices,此时整个DI基础架构尚不存在。所以在创建实例时你不能依赖任何东西。我还认为创建对象仍然不是你的工作,但你应该DI处理它的创建,因此它也可以控制它的生命周期。

如果您绝对需要来控制创建实例的时间,我建议您使用生命周期事件:基本上,之后应用程序已正确设置但第一个请求进入之前,您请求服务实例并初始化它。这样,您仍然可以完全依赖DI,并且不会在第一次请求时懒得创建。

您可以使用Configure方法注册生命周期处理程序:

public void Configure(IApplicationBuilder app, IApplicationLifetime applicationLifetime)
{
    applicationLifetime.ApplicationStarted.Register(() =>
    {
        // application has started, request the singleton here to trigger DI to
        // create the instance
        app.ApplicationServices.GetService<ExpensiveSingleton>();
    });

    // …
}


}

答案 1 :(得分:0)

这种方法的问题是,通过DI加载多个配置部分是不可能的。 Configuration API具有许多功能,例如可插拔配置提供,快照等。 我建议你至少使用一个类绑定你的配置部分,所以DI可以根据它的类型注入它。如果你需要另外一个配置类,你就不会遇到问题。

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration