当“services.AddTransient<IConfigureOptions<T>, ConfigureTOptions>()”起作用时,“AddOptions<T>.Configure()”不起作用?

pee*_*oop 7 c# configuration options asp.net-core identityserver4

我正在尝试使用强类型配置对象来配置 IdentityServer4 身份验证。

微软选项模式文档说:

您可以通过两种方式配置选项时从依赖注入访问其他服务:

  • 将配置委托传递给 OptionsBuilder 上的 Configure。OptionsBuilder 提供了 Configure 的重载,允许您使用最多五个服务来配置选项:

    services.AddOptions<MyOptions>("optionalName")
        .Configure<Service1, Service2, Service3, Service4, Service5>(
            (o, s, s2, s3, s4, s5) => 
                o.Property = DoSomethingWith(s, s2, s3, s4, s5));
    
    Run Code Online (Sandbox Code Playgroud)
  • 创建您自己的实现 IConfigureOptions 或 IConfigureNamedOptions 的类型并将该类型注册为服务。

我们建议将配置委托传递给 Configure,因为创建服务更复杂。创建您自己的类型相当于当您使用 Configure 时框架为您做的事情。调用 Configure 注册一个瞬态通用 IConfigureNamedOptions,它具有一个接受指定的通用服务类型的构造函数。

我查看了 的源代码,OptionsBuilder看起来文档是准确的,因为这两种方法在功能上是等效的,但是配置委托方法不适用于 IdentityServer4,所以我问这个问题更多是出于好奇.

当我将它添加到时,这不起作用Startup.cs

services
    .AddOptions<IdentityServerAuthenticationOptions>()
    .Configure<IdentityServerConfiguration>((options, configuration)) =>
    {
        options.Audience = configuration.Audience
        // etc.
    });

services
    .AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
    .AddIdentityServerAuthentication();
Run Code Online (Sandbox Code Playgroud)

但是,创建一个如下所示的类:

public sealed class ConfigureOptions : IConfigureNamedOptions<IdentityServerAuthenticationOptions>
{
    private readonly IdentityServerConfiguration _configuration;

    public ConfigureOptions(IdentityServerConfiguration configuration)
    {
        _configuration = configuration;
    }

    public void Configure(string name, IdentityServerAuthenticationOptions options)
    {
        options.ApiName = _configuration.Audience;
        // etc.
    }

    public void Configure(IdentityServerAuthenticationOptions options)
    {
        options.ApiName = _configuration.Audience;
        // etc.
    }
}
Run Code Online (Sandbox Code Playgroud)

并将其添加为Startup.cs喜欢:

services
    .AddTransient<IConfigureOptions<IdentityServerAuthenticationOptions>, ConfigureOptions>();

services
    .AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
    .AddIdentityServerAuthentication();
Run Code Online (Sandbox Code Playgroud)

使其完美运行。

有谁知道它为什么会这样?

Iac*_*hin 0

我有类似的问题。当我作为 ModelConfigOptions 的值注入其他服务时,我得到了 null。我的代码是

public class ModelConfigOptions
{
    public IEnumerable<ModelConfig> ModelConfigs { get; set; }
}

public class ModelConfig
{
    public int Id { get; set; }
    public int ModelId { get; set; }
    public string Name { get; set; }
    public IModelParameter Parameters { get; set; }
}

public interface IModelLoader
{
    ModelConfigOptions LoadModelConfig(params int[] modelIds);
}

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
       Host.CreateDefaultBuilder(args)
            .ConfigureLogging((hostContext, logging) =>
            {
                logging.ClearProviders();
                logging.AddNLog(hostContext.Configuration, new NLogProviderOptions() { LoggingConfigurationSectionName = "NLog" });
            })                
            .ConfigureServices((hostContext, services) =>
            {
                ...
                services.AddOptions<ModelConfigOptions>().Configure<IModelLoader>((o, s) =>
                {
                    o = s.LoadModelConfig(4, 5);
                });
                ...                    
            });
}
Run Code Online (Sandbox Code Playgroud)

然后我按以下方式更改了 IModelLoader 和 Program 以使其工作:

public interface IModelLoader
{
      IEnumerable<ModelConfig> LoadModelConfig(params int[] modelIds);
}
Run Code Online (Sandbox Code Playgroud)

结尾

services.AddOptions<ModelConfigOptions>().Configure<IModelLoader>((o, s) =>
{
     o.ModelConfigs = s.LoadModelConfig(4, 5);
});
            
Run Code Online (Sandbox Code Playgroud)