如何在ConfigureServices方法中获取IOptions?

时间:2017-03-21 16:18:34

标签: asp.net-core asp.net-core-mvc .net-core coreclr

我有asp.net核心应用程序。我想使用IOptions模式从appsettings.json注入值。所以我有一个类SecurityHeaderOptions,并且还有目标类SecurityHeadersBuilder,其构造函数将IOptions<SecurityHeaderOptions>作为参数。

我知道.net core可以通过在注册容器后注入SecurityHeadersBuilder来隐式创建IOptions<SecurityHeaderOptions>的实例。

但是我想显式创建SecurityHeadersBuilder的实例,调用其中一个方法,然后使用容器注册实例。

public sealed class SecurityHeaderOptions
{
    public string FrameOption { get; set; }    
    public string XssProtection { get; set; }
}


public class SecurityHeadersBuilder
{
    private readonly SecurityHeaderOptions _options = null;

    public SecurityHeadersBuilder(IOptions<SecurityHeaderOptions> options)
    {
        _options = options.Value;    
    }

    public SecurityHeadersBuilder AddDefaultPolicy()
    {
        AddFrameOptions();
        AddConetntSecurityPolicy();
        return this;
    }
}

配置服务方法

public void ConfigureServices(IServiceCollection services)
{        
    services.Configure<SecurityHeaderOptions>(Configuration.GetSection("SecurityHeaderOptions"));

    services.AddScoped<SecurityHeadersBuilder>(provider => 
           new SecurityHeadersBuilder(?????).AddDefaultPolicy())
}

问题
1 GT;如果我明确地将选项传递给构造函数,我是否需要使用SecurityHeaderOptions方法向容器注册service.Configure

2 - ; Configuration.GetSection("SecurityHeaderOptions")无法返回IOptions<SecurityHeaderOptions>的实例,而是返回IConfigurationSection

3&gt;无论哪种方式,如何检索SecurityHeaderOptions并将SecurityHeadersBuilder传递给gsutil -m rm gs://mybucket/subbucket/* 的构造函数?

6 个答案:

答案 0 :(得分:17)

使用.NET Core 2并在ConfigureServices中没有提供程序(或希望添加它),我选择使用类似这样的东西(以OP代码为例):

public void ConfigureServices(IServiceCollection services)
{
    // secOpts available for use in ConfigureServices
    var secOpts = Configuration
        .GetSection("SecurityHeaderOptions")
        .Get<SecurityHeaderOptions>();

    ...
}

答案 1 :(得分:4)

这是我注册选项并注入SecurityHeadersBuilder

的方式
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<SecurityHeaderOptions>(Configuration.GetSection("SecurityHeaderOptions"));            
    services.AddScoped<SecurityHeadersBuilder>(provider =>
    {
        var option = provider.GetService<IOptions<SecurityHeaderOptions>>();
        return new SecurityHeadersBuilder(option)
        .AddDefaultPolicy();
    });
}

答案 2 :(得分:1)

关于你的问题:

1。是的,您需要注册选项,但我相信您的选择方式是错误的(至少在您的示例中)。你应该注册为:

services.Configure<SecurityHeaderOptions>(options => Configuration.GetSection("SecurityHeaderOptions").Bind(options));

2。我相信上面提到的正确注册会返回您的期望。

3. 只需注册并将其放在SecurityHeaderBuilder构造函数上即可。您不需要(默认的.NET Core IOC容器也不允许)在注册时传递构造函数参数。为此,您需要使用其他IOC,例如Autofac。

但您需要注册SecurityHeadersBuilder才能在其他课程中使用它。 只需使用一个接口即可。

public interface ISecurityHeadersBuilder
{
    SecurityHeadersBuilder AddDefaultPolicy;    
}
public class SecurityHeadersBuilder : ISecurityHeadersBuilder
{
    private readonly SecurityHeaderOptions _options = null;

    public SecurityHeadersBuilder(IOptions<SecurityHeaderOptions> options)
    {
        _options = options.Value;    
    }

    public SecurityHeadersBuilder AddDefaultPolicy()
    {
        AddFrameOptions();
        AddContentSecurityPolicy();
        return this;
    }
}

然后,只需在startup.cs注册它

services.AddScoped<ISecurityHeadersBuilder, SecurityHeadersBuilder>();

答案 3 :(得分:1)

Docs 特别说:

<块引用>

不要在 IOptions<TOptions> 中使用 IOptionsMonitor<TOptions>Startup.ConfigureServices。由于服务注册的顺序,可能存在不一致的选项状态。

因此您必须从 Startup.ConfigureServices 以其他方式访问配置,例如Quinton's answer

答案 4 :(得分:0)

首先,您需要向SecurityHeadersBuilder添加第二个构造函数,该构造函数使用简单的SecurityHeaderOptions

public class SecurityHeadersBuilder
{
    private readonly SecurityHeaderOptions _options;

    public SecurityHeadersBuilder(IOptions<SecurityHeaderOptions> options)
    {
        _options = options.Value;    
    }

    public SecurityHeadersBuilder(SecurityHeaderOptions options)
    {
        _options = options;    
    }

    public SecurityHeadersBuilder AddDefaultPolicy()
    {
        AddFrameOptions();
        AddContentSecurityPolicy();

        return this;
    }
}

然后答案完全取决于您是否需要在Startup类之外使用这些选项。


如果没有,则可以简单地使用Microsoft.Extensions.Configuration.ConfigurationBinder.Get<T>()扩展方法:

services.AddScoped<SecurityHeadersBuilder>(provider =>
{
    var options = Configuration.GetSection("SecurityHeaderOptions")
        .Get<SecurityHeaderOptions>();

    return new SecurityHeadersBuilder(options)
        .AddDefaultPolicy();
});

(然后您可以删除采用SecurityHeadersBuilder的{​​{1}}构造函数)。


如果您需要在其他地方使用这些选项,则可以将以上方法与IOptions<SecurityHeaderOptions>扩展方法结合使用:

Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure()

答案 5 :(得分:0)

您可以这样做

public static class IConfigurationExtensions
{
    public static TypedConfiguration<SecurityHeaderOptions> GetSecurityHeaderOptions(this IConfiguration configuration)
    {
        return new TypedConfiguration<SecurityHeaderOptions>(configuration.GetSection("SecurityHeaderOptions"));
    }
}

public class TypedConfiguration<T> where T : class
{
    public TypedConfiguration(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }
    public T Value => Configuration.Get<T>();

    public void InitializeOptions(IServiceCollection services)
    {
        services.Configure<T>(Configuration);
    }
}

现在您已经从一个地方创建了一个对象,该对象同时具有IConfiguration,类型为SecurityHeaderOptions和用于为该类注册IOptions注入的辅助方法。

像这样使用它

public void ConfigureServices(IServiceCollection services)
{        
    var wrappedOptions = Configuration.GetSecurityHeaderOptions();
    wrappedOptions.InitializeOptions(services);

    var options = Options.Create(wrappedOptions.Value);
    services.AddScoped<SecurityHeadersBuilder>(provider => 
       new SecurityHeadersBuilder(options).AddDefaultPolicy());
}