-
-
Save ericsampson/bb37bd6da0748af2e928ee750563452a to your computer and use it in GitHub Desktop.
// I have a service that needs to be initialized with a FooOptions and then added to the DI container. | |
// I also want to have IOptions<FooOptions> in the DI container to allow injection in other methods. | |
// How should I write my AddFoo extension method to support this? | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
services.AddFoo(fooOptions => | |
{ | |
configuration.GetSection("FooOptions").Bind(fooOptions) | |
fooOptions.param = "override"; | |
}); | |
} | |
namespace Microsoft.Extensions.DependencyInjection | |
{ | |
public static class MyFooExtensions | |
{ | |
public static IServiceCollection AddFoo(this IServiceCollection services, | |
Action<FooOptions> setupOptions) | |
{ | |
services.Configure<FooOptions>(setupOptions); | |
services.AddSingleton<IFoo>(sp => | |
{ | |
var options = sp.GetRequiredService<IOptions<FooOptions>>(); | |
return new FooFactory(options.Value); | |
}; | |
return services; | |
} | |
} | |
} |
Yeah, unfortunately, you're kinda screwed in that case 🙁
Basically, requiring concrete IOptions<>
in the AddFoo()
method is not the recommended pattern, for exactly this reason! But if that's what it is, there's not a lot you can do...
In the few cases I've run into this I have just manually bound the configuration instead. It's not ideal, and means you can't use the full options pattern, but it may do:
public void ConfigureServices(IServiceCollection services)
{
var fooOptions = new FooOptions();
Configuration.Bind("FooOptions", fooOptions);
services.AddFoo(fooOptions);
}
Rich Strahl has a nice post about this here: https://weblog.west-wind.com/posts/2017/dec/12/easy-configuration-binding-in-aspnet-core-revisited
@andrewlock, argh I'm an idiot. The signature is FooFactory(FooOptions options)
, not an IOptions<FooOptions>
, if that helps.
I think I've revised the AddFoo()
code in a way that should work now?? Or not...
I found a helpful blog post from @TsuyoshiUshio that gave me the idea:
https://medium.com/@tsuyoshiushio/servicecollection-di-with-optional-settings-fc4ee46984d1
@ericsampson That looks very similar to my suggestion, with a slight tweak. I don't think your suggestion will quite work though. Try this instead:
public void ConfigureServices(IServiceCollection services)
{
services.AddFoo(fooOptions =>
{
configuration.GetSection("FooOptions").Bind(fooOptions)
fooOptions.param = "override";
});
}
Thanks again @andrewlock, I'll give this all a go. Really appreciate the help :)
@andrewlock, I just updated the gist to add line 31 - the motivation for my original question is that an instance of FooOptions is needed inside AddFoo, so I don't think that's going to work.
Sorry if that wasn't clear :) This just seems like a common scenario, so I must be missing something...