This article, https://medium.com/@dmitryzaets/legacy-net-applications-configuration-management-net-framework-4-5-1-68220335d9d8, describe how to use Options pattern together with Autofac. I have tried to translate this to use with Simple Injector. But I have no luck. Here is my IOC code
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; }
}
settings.json
{
"mailing": {
"batchSize": 15,
"batchDelay": 1
}
}
Then I inject it in a ViewModel:s constructor like this
public class BlockViewModel
{
private readonly MailingOptions _options;
#region Constructor
public BlockViewModel(IOptions<MailingOptions> options)
{
_options = options.Value;
}
#endregion
}
When I run it I get Exceptions in Container.Verify.
The constructor of type OptionsFactory<MailingOptions> contains the parameter with name 'setups' and type IEnumerable<IConfigureOptions<MailingOptions>> that is not registered. Please ensure IEnumerable<IConfigureOptions<MailingOptions>> is registered, or change the constructor of OptionsFactory<MailingOptions>. There is, however, a registration for IConfigureOptions<MailingOptions>; Did you mean to depend on IConfigureOptions<MailingOptions>?
StackTrace:
at SimpleInjector.Container.ThrowParameterTypeMustBeRegistered(InjectionTargetInfo target)
How will I Register an IEnumerable<IConfigureOptions<MailingOptions>>
?
Can someone tell my what I'm doing wrong, or more precise, what is it that I don't understand?
The short answer is: don't inject
IOptions<T>
into your application components. As explained here, that will only complicate your components, their unit tests, and, as you already noticed, your configuration.Instead, let
BlockViewModel
depend onMailingOptions
directly:This allows you to simplify your configuration to the following: