.net核心,n层应用程序,服务层应该依赖于Microsoft.Extensions.Options.dll

dee*_* zg 4 configuration .net-core asp.net-core

直截了当的问题是:Microsoft.Extensions.Options.IOptions是否只能在伞形应用程序(在本例中为Web应用程序)或类库中使用?

例:

在一个n层的asp.net核心应用程序中,我们的服务层依赖于来自appsettings.json文件的一些设置.

我们刚开始的是Startup.cs中的这些内容:

  services.Configure<Services.Options.XOptions>(options =>
  {
    options.OptionProperty1 = Configuration["OptionXSection:OptionXProperty"];
  });
Run Code Online (Sandbox Code Playgroud)

然后在服务构造函数中:

ServiceConstructor(IOptions<XOptions> xOptions){}
Run Code Online (Sandbox Code Playgroud)

但这假设在我们的服务层中我们依赖Microsoft.Extensions.Options.

我们不确定这是推荐的还是有更好的做法?

我们的服务类库应该知道DI容器实现,这感觉有点尴尬.

Tse*_*eng 5

您也可以注册POCO设置以进行注射,但是您会丢失与appsettings.json编辑时相关的一些功能.

services.AddTransient<XOptions>(
    provider => provider.GetRequiredService<IOptionsSnapshot<XOptions>>().Value);
Run Code Online (Sandbox Code Playgroud)

现在,当您注入XOptions构造函数时,您将获得该类.但是,当你编辑你的appsettings.json,该值将不会被直到下一次更新,它解决了这对范围的服务将是对未来的要求和辛格尔顿服务永远.

另一方面,注入IOptionsSnapshot<T> .Value将始终为您提供当前设置,即使appsettings.json重新加载(假设您已注册.AddJsonFile("appsettings.json", reloadOnSave: true)).

保持功能不将Microsoft.Extensions.Options包拉入服务/域层的明显原因是创建自己的接口和实现.

// in your shared service/domain assembly
public interface ISettingsSnapshot<T> where T : class
{
    T Value { get; }
}
Run Code Online (Sandbox Code Playgroud)

并在应用程序端(服务/域程序集之外)实现它,即MyProject.Web(ASP.NET核心和组合根目录)

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;
}
Run Code Online (Sandbox Code Playgroud)

并将其注册为

services.AddSingleton(typeof(ISettingsSnapshot<>), typeof(OptionsSnapshotWrapper<T>));
Run Code Online (Sandbox Code Playgroud)

现在你已经取消了对你的依赖IOptions<T>,并IOptionsSnapshot<T>从你的服务,但保留了所有的优点,它像appsettings.json编辑时更新选项.更改DI时,只需更换OptionsSnapshotWrapper<T>新实现即可.