.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.

+3


source to share


1 answer


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.

+5


source







All Articles