Straightforward question is: are Microsoft.Extensions.Options.IOptions meant to be used only within the context of umbrella app (web app in this case) or in class libraries also?
Example:
In a n-layered, asp.net core app we have services layer that is dependant on some settings coming from appsettings.json
file.
What we first started with is something along these lines in Startup.cs:
services.Configure<Services.Options.XOptions>(options =>
{
options.OptionProperty1 = Configuration["OptionXSection:OptionXProperty"];
});
And then in service constructor:
ServiceConstructor(IOptions<XOptions> xOptions){}
But that assumes that in our Service layer we have dependecy on Microsoft.Extensions.Options
.
We're not sure if this is recomended way or is there some better practice?
It just feels a bit awkward our services class library should be aware of DI container implementation.
You can register POCO settings for injection too, but you lose some functionalities related to when the
appsettings.json
gets edited.Now when you inject
XOptions
in constructor, you will get the class. But when your edit yourappsettings.json
, the value won't be updated until the next time it's resolved which for scoped services would be on next request and singleton services never.On other side injecting
IOptionsSnapshot<T>
.Value
will always get you the current settings, even whenappsettings.json
is reloaded (assuming you registered it with.AddJsonFile("appsettings.json", reloadOnSave: true)
).The obvious reason to keep the functionality w/o pulling
Microsoft.Extensions.Options
package into your service/domain layer will be create your own interface and implementation.and implement it on the application side (outside of your services/domain assemblies), i.e.
MyProject.Web
(where ASP.NET Core and the composition root is)and register it as
Now you have removed your dependency on
IOptions<T>
andIOptionsSnapshot<T>
from your services but retain all up advantages of it like updating options when appsettings.json is edited. When you change DI, just replaceOptionsSnapshotWrapper<T>
with your new implementation.