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

问题描述 投票:0回答:2

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

Microsoft 的选项模式文档说:

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

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

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

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

我查看了

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

当我将其添加到

Startup.cs
时,这不起作用:

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

services
    .AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
    .AddIdentityServerAuthentication();

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

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.
    }
}

并将其添加到

Startup.cs
,例如:

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

services
    .AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
    .AddIdentityServerAuthentication();

使其完美运行。

有谁知道为什么会这样?

c# asp.net-core configuration identityserver4
2个回答
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);
                });
                ...                    
            });
}

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

public interface IModelLoader
{
      IEnumerable<ModelConfig> LoadModelConfig(params int[] modelIds);
}

结束

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

0
投票

这几乎肯定是因为命名选项。不带名称参数的 AddOptions() 将委托应用于默认名称 (string.Empty)。您的 IConfigureNamedOptions 实现适用于所有选项名称。

您的解决方案效果很好。或者找出 IS4 在创建选项时使用的名称并将其传递给 AddOptions()。

© www.soinside.com 2019 - 2024. All rights reserved.