我正在尝试使用强类型配置对象来配置 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();
使其完美运行。
有谁知道为什么会这样?
我也有类似的问题。当我作为 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);
});
这几乎肯定是因为命名选项。不带名称参数的 AddOptions() 将委托应用于默认名称 (string.Empty)。您的 IConfigureNamedOptions 实现适用于所有选项名称。
您的解决方案效果很好。或者找出 IS4 在创建选项时使用的名称并将其传递给 AddOptions()。