带有简单注入器的 Legacy .NET 应用程序中的选项模式、配置

Rog*_*lin 1 configuration configurationmanager legacy-code simple-injector .net-core-configuration

这篇文章https://medium.com/@dmitryzaets/legacy-net-applications-configuration-management-net-framework-4-5-1-68220335d9d8描述了如何将选项模式与 Autofac 一起使用。我试图将其翻译为与 Simple Injector 一起使用。但我没有运气。这是我的国际奥委会代码

public class IocBootstrap2
{
    private Container Container { get; }
    public IocBootstrap2()
    {
        Container = new Container();
        var configurationBuilder = new ConfigurationBuilder()
            .SetBasePath(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Configuration"))
            .AddJsonFile("settings.json", optional: false, reloadOnChange: true);
        var configuration = configurationBuilder.Build();
        //Register Options
        Container.Register(typeof(IOptions<>), typeof(OptionsManager<>));
        Container.Register(typeof(IOptionsMonitor<>), typeof(OptionsMonitor<>));
        Container.Register(typeof(IOptionsFactory<>), typeof(OptionsFactory<>));
        Container.Register(typeof(IOptionsMonitorCache<>), typeof(OptionsCache<>));
        // Register ConfigurationOptions
        Container.RegisterConfigurationOptions2<MailingOptions>(configuration.GetSection("mailing"));

    #if DEBUG
        Container.Verify();
    #endif   
 }
}

public static class ConfigurationSetupExtensions2
{
    public static void RegisterConfigurationOptions2<TOptions>(this Container container, IConfiguration config)
        where TOptions : class
    {
        container.Register(typeof(IOptionsChangeTokenSource<TOptions>),
            () => new ConfigurationChangeTokenSource<TOptions>(config), Lifestyle.Transient);
        container.Register(typeof(IConfigureOptions<TOptions>),
            () => new ConfigureFromConfigurationOptions<TOptions>(config), Lifestyle.Transient);
    }
}
 public class MailingOptions
{
    public MailingOptions()
    {
        BatchSize = 1;
    }
    public int BatchSize { get; set; }
    public int BatchDelay { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

设置.json

{
  "mailing": {
    "batchSize": 15, 
    "batchDelay": 1
  }
}
Run Code Online (Sandbox Code Playgroud)

然后我将它注入到 ViewModel:s 构造函数中

{
  "mailing": {
    "batchSize": 15, 
    "batchDelay": 1
  }
}
Run Code Online (Sandbox Code Playgroud)

当我运行它时,我在 Container.Verify 中得到异常。

OptionsFactory<MailingOptions> 类型的构造函数包含名称为“setups”且类型为 IEnumerable<IConfigureOptions<MailingOptions>> 的参数,但未注册。请确保 IEnumerable<IConfigureOptions<MailingOptions>> 已注册,或更改 OptionsFactory<MailingOptions> 的构造函数。然而,有一个 IConfigureOptions<MailingOptions> 的注册;你的意思是依赖 IConfigureOptions<MailingOptions> 吗?

堆栈跟踪:

在 SimpleInjector.Container.ThrowParameterTypeMustBeRegistered(InjectionTargetInfo 目标)

我将如何注册IEnumerable<IConfigureOptions<MailingOptions>>?有人可以告诉我我做错了什么,或者更准确地说,我不明白的是什么?

Ste*_*ven 5

简短的回答是:不要注入IOptions<T>到您的应用程序组件中。正如解释这里,将因为你已经注意到你的组件,它们的单元测试仅复杂,而且,你的配置。

相反,让我们直接BlockViewModel依赖MailingOptions

public class BlockViewModel 
{
    private readonly MailingOptions _options;

    public BlockViewModel(MailingOptions options) 
    {
        _options = options ?? throw new ArgumentNullException(nameof(options));
    }
}
Run Code Online (Sandbox Code Playgroud)

这允许您将配置简化为以下内容:

Container = new Container();
var configutation = new ConfigurationBuilder()
  .SetBasePath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Configuration"))
    .AddJsonFile("settings.json", optional: false);
    .Build();

MailingOptions options = configuration.GetSection("mailing").Get<MailingOptions>();
Container.RegisterInstance<MailingOptions>(options);

// Register View Models
Container.Register<BlockViewModel>();

Container.Verify();
Run Code Online (Sandbox Code Playgroud)