.net, n-layered app if the service layer depends on Microsoft.Extensions.Options.dll
Simple question : Are Microsoft.Extensions.Options.IOptions intended to be used only in the context of an umbrella application (in this case a web application) or in class libraries?
Example:
In n-layered, the main asp.net application, we have a service layer that depends on some parameters coming from a file appsettings.json
.
What we started with first is something along these lines in Startup.cs:
services.Configure<Services.Options.XOptions>(options =>
{
options.OptionProperty1 = Configuration["OptionXSection:OptionXProperty"];
});
And then in the constructor of the service:
ServiceConstructor(IOptions<XOptions> xOptions){}
But this assumes that on our Service layer we have a dependency on Microsoft.Extensions.Options
.
We're not sure how much this is recommended or is there some better practice?
It just feels a little awkward that our service class library needs to know about the DI container implementation.
source to share
You can also register POCO settings for injection, but you will lose some of the functionality related when edited appsettings.json
.
services.AddTransient<XOptions>( provider => provider.GetRequiredService<IOptionsSnapshot<XOptions>>().Value);
Now when you enter XOptions
into the constructor, you will get the class. But when you edit yours appsettings.json
, the value won't update until next time it allows the next request for scoped services and never oneton services .
On the other hand, injection IOptionsSnapshot<T>
.Value
will always get the current settings, even if a reboot appsettings.json
(if you've registered it with .AddJsonFile("appsettings.json", reloadOnSave: true)
).
The obvious reason to keep functionality without pulling the package Microsoft.Extensions.Options
to your service / domain layer would be to create your own interface and implementation.
// in your shared service/domain assembly
public interface ISettingsSnapshot<T> where T : class
{
T Value { get; }
}
and implement it on the application side (outside your service / domain assemblies), that is MyProject.Web
(where for ASP.NET core and composition root)
public class OptionsSnapshotWrapper<T> : ISettingsSnapshot<T>
{
private readonly IOptionsSnapshot<T> snapshot;
public OptionsSnapshotWrapper(IOptionsSnapshot<T> snapshot)
{
this.snapshot = snapshot ?? throw new ArgumentNullException(nameof(snapshot));
}
public T Value => snapshot.Value;
}
and register it as
services.AddSingleton(typeof(ISettingsSnapshot<>), typeof(OptionsSnapshotWrapper<T>));
You have now removed your dependency on IOptions<T>
and IOptionsSnapshot<T>
from your services, but retain all the benefits, such as updating settings when editing appsettings.json. When you change DI, just replace with OptionsSnapshotWrapper<T>
your new implementation.
source to share