具有构造函数依赖关系的{AspNetCore选项模式

时间:2018-02-28 13:07:58

标签: 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 IEmailConfiguration Configuration { get; }
}

IEmailConfiguration接口在那里是因为在某些情况下我可以有一个Smtp库,所以我需要一个基于Smtp的配置,而在其他一些情况下我可以使用其他需要不同配置的服务。例如:

public class ApiKeyConfiguration : IEmailConfiguration
{
    public ApiKeyConfiguration() {
    }
    public string AccountName { get; set; }
    public string AccountKey { get; set; }
}

public class SmtpConfiguration : IEmailConfiguration
{
    public SmtpConfiguration() {
    }
    public string Host { get; set; }
    public string Port { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public string Domain { get; set; }
    public bool EnableSsl { get; set; }
    public bool UseDefaultCredentials { get; set; }
}

我确信我正在使用

注册正确的实现
services.AddTransient<IEmailConfiguration, ApiKeyConfiguration>();

然而,当我尝试注入IOption&lt;&gt;进入控制器我收到以下错误:

  

[13:56:26 ERR]发生了未处理的异常:无法创建“EmailOptions”类型的实例,因为它缺少公共无参数构造函数。   System.InvalidOperationException:无法创建“EmailOptions”类型的实例,因为它缺少公共无参数构造函数。   在Microsoft.Extensions.Configuration.ConfigurationBinder.CreateInstance(类型类型)

当然我可以在类中添加无参数构造函数但是如何通过使用带参数依赖的构造函数来确保DI容器将创建我的类的实例?

3 个答案:

答案 0 :(得分:1)

基于ASP.NET Core中的配置工作方式,它将始终使用无参数构造函数。虽然这不是唯一的原因,但一个特别好的理由是配置设置在任何DI服务注册之前发生,这意味着如果它想要它就不能注入任何东西。

长而短,在强类型配置类中无法满足IEmailConfiguration之类的内容。无论如何,坦率地说这是一个坏主意。只需让您的配置类成为一个简单的实体,并将 注入服务或处理您的电子邮件的东西,而不是相反。

答案 1 :(得分:1)

从技术上讲,您可以尝试创建自己的IConfigureOptions实现。

  

表示配置TOptions类型的内容。注意:这些在所有IPostConfigureOptions之前运行。

所以做这样的事情:

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

答案 2 :(得分:0)

它说你需要一个公共无参数构造函数。

添加

public EmailOptions() {

}