Asp.net core 具有构造函数依赖关系的AspNetCore选项模式
我有一个选项类,如下所示Asp.net core 具有构造函数依赖关系的AspNetCore选项模式,asp.net-core,asp.net-core-mvc,Asp.net Core,Asp.net Core Mvc,我有一个选项类,如下所示 public class EmailOptions { public EmailOptions(IEmailConfiguration account) { this.Configuration = account; } public string DefaultFromAddress { get; set; } public string DefaultFromDisplayName { get; set; }
public class EmailOptions
{
public EmailOptions(IEmailConfiguration account) {
this.Configuration = account;
}
public string DefaultFromAddress { get; set; }
public string DefaultFromDisplayName { get; set; }
public IEmailConfiguration Configuration { get; }
}
IEmailConfiguration接口之所以存在,是因为在某些情况下,我可以拥有Smtp库,因此我需要基于Smtp的配置,而在其他一些情况下,我可以使用需要不同配置的其他服务。例如:
public class ApiKeyConfiguration : IEmailConfiguration
{
public ApiKeyConfiguration() {
}
public string AccountName { get; set; }
public string AccountKey { get; set; }
}
或
我确信我正在向注册正确的实现
services.AddTransient<IEmailConfiguration, ApiKeyConfiguration>();
services.AddTransient();
但是,当我尝试将IOption注入控制器时,会出现以下错误:
[13:56:26错误]发生未经处理的异常:无法创建“EmailOptions”类型的实例,因为它缺少公共无参数构造函数。
System.InvalidOperationException:无法创建“EmailOptions”类型的实例,因为它缺少公共无参数构造函数。
位于Microsoft.Extensions.Configuration.ConfigurationBinder.CreateInstance(类型)
当然,我可以将无参数构造函数添加到类中,但如何确保DI容器通过使用具有参数依赖性的构造函数来创建我的类的实例?这是说您需要一个公共的无参数构造函数 加
根据ASP.NET核心中配置的工作方式,它将始终使用无参数构造函数。虽然这不是唯一的原因,但一个特别好的原因是配置设置发生在任何DI服务注册之前,这意味着如果它想注入任何东西,它就不能注入任何东西
长话短说,在强类型配置类中无法满足类似于
IEmailConfiguration
的要求。坦白说,这是个坏主意。让您的配置类成为一个简单的实体,并将其注入到处理电子邮件内容的服务或其他东西中,而不是反过来。从技术上讲,您可以尝试创建自己的实现
表示配置Topions类型的内容。注意:这些是在所有IPostConfigureOptions之前运行的
因此,请这样做:
public class ConfigureEmailOptions : IConfigureOptions<EmailOptions>
{
private readonly IEmailConfiguration _account;
public ConfigureMyOptions(IEmailConfiguration account)
{
_account = account;
}
public void Configure(EmailOptions options)
{
options.Configuration = _account;
...
}
}
:这是非常清楚的。但是,我是否确保通过使用带参数的构造函数来创建选项?我知道通常DI容器总是使用具有大多数参数的构造函数,但在我的例子中,这正是必需的。
public EmailOptions() {
}
public class ConfigureEmailOptions : IConfigureOptions<EmailOptions>
{
private readonly IEmailConfiguration _account;
public ConfigureMyOptions(IEmailConfiguration account)
{
_account = account;
}
public void Configure(EmailOptions options)
{
options.Configuration = _account;
...
}
}
services.AddTransient<IConfigureOptions<EmailOptions>, ConfigureEmailOptions>();
public class EmailOptions
{
public string DefaultFromAddress { get; set; }
public string DefaultFromDisplayName { get; set; }
public IEmailConfiguration Configuration { get; set; }
}