ASP.NET 5 控制器外部 DI 应用程序设置

ASP.NET 5 DI app setting outside controller

我可以像这样在控制器中设置 DI 应用程序

 private IOptions<AppSettings> appSettings;
 public CompanyInfoController(IOptions<AppSettings> appSettings)
 {
     this.appSettings = appSettings;
 }

但是如何在我的自定义 class 中像这样

  private IOptions<AppSettings> appSettings;
  public PermissionFactory(IOptions<AppSettings> appSetting)
  {
      this.appSettings = appSettings;
  }

我在 Startup.cs 中的注册是

services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

"proper" 方式

在DI中注册你的自定义class,方法同你在ConfigureServices方法中注册其他依赖一样,例如:

services.AddTransient<PermissionFactory>();

(而不是 AddTransient,您可以使用 AddScoped,或您需要的任何其他生命周期)

然后将此依赖项添加到控制器的构造函数中:

public CompanyInfoController(IOptions<AppSettings> appSettings, PermissionFactory permFact)

现在,DI 知道 PermissionFactory,可以将其实例化并将其注入到您的控制器中。

如果你想在Configure方法中使用PermissionFactory,只需将它添加到它的参数列表中:

Configure(IApplicationBuilder app, PermissionFactory prov)

Aspnet 会发挥它的魔力并在那里注入 class。

"nasty" 方式

如果你想在你的代码深处的某个地方实例化 PermissionFactory,你也可以用一种有点讨厌的方式来实现 - 在 Startup [=53= 中存储对 IServiceProvider 的引用]:

internal static IServiceProvider ServiceProvider { get;set; }

Configure(IApplicationBuilder app, IServiceProvider prov) {
   ServiceProvider = prov;
   ...
}

现在您可以像这样访问它:

var factory = Startup.ServiceProvider.GetService<PermissionFactory>();

同样,DI 将负责将 IOptions<AppSettings> 注入 PermissionFactory

Asp.Net 5 Docs in Dependency Injection

您也可以在非控制器 class 中进行依赖注入。

在你的 startup class,

public class Startup
{
  public IConfigurationRoot Configuration { get; set; }

  public Startup(IHostingEnvironment env)
  {
        // Set up configuration sources.
     var builder = new ConfigurationBuilder()
             .AddJsonFile("appsettings.json")
             .AddEnvironmentVariables();
     Configuration = builder.Build();
  }
  public void ConfigureServices(IServiceCollection services)
  {
     // register other dependencies also here
     services.AddInstance<IConfiguration>(Configuration);     
  }
}

现在在您的自定义 class 中,让构造函数接受 IConfiguration

的实现
private IConfiguration configuration;
public PermissionFactory(IConfiguration configuration)
{
  this.configuration = configuration;
}
public void SomeMethod()
{
  var someSection = this.configuration.GetSection("SomeSection");
  var someValue= this.configuration.Get<string>("YourItem:SubItem");
}

我建议不要通过 AppSettings。 class 不应该依赖于模糊的东西——它应该完全依赖于它需要什么,或者接近它。 ASP.NET Core 可以更轻松地摆脱依赖 AppSettings 的旧模式。如果您的 class 依赖于 AppSettings 那么您无法从构造函数中真正看出它依赖于什么。它可能取决于任何键。如果它依赖于一个更具体的接口,那么它的依赖性更清晰,更明确,并且您可以在单元测试时模拟该接口。

您可以创建一个界面,其中包含您的 class 需要的特定设置(或不太具体但不太宽泛的设置)和实现它的 class - 例如,

    public interface IFooSettings
    {
        string Name { get; }
        IEnumerable Foos { get; }
    }

    public interface IFoo
    {
        string Color { get;  }
        double BarUnits { get;  }
    }

    public class FooSettings : IFooSettings
    {
        public string Name { get; set; }
        public List<Foo> FooList { get; set; }

        public IEnumerable Foos
        {
            get
            {
                if (FooList == null) FooList = new List<Foo>();
                return FooList.Cast<IFoo>();
            }
        }
    }

    public class Foo : IFoo
    {
        public string Color { get; set; }
        public double BarUnits { get; set; }
    }

然后添加一个.json文件,fooSettings.json:

    {
      "FooSettings": {
        "Name": "MyFooSettings",
        "FooList": [
          {
            "Color": "Red",
            "BarUnits": "1.5"
          },      {
            "Color": "Blue",
            "BarUnits": "3.14159'"
          },      {
            "Color": "Green",
            "BarUnits": "-0.99999"
          }
        ]
      }
    }

然后,在 Startup()(在 Startup.cs 中)我们指定进入 Configuration 的地方,添加 fooSettings.json:

    var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
        .AddJsonFile("config.json")
        .AddJsonFile($"config.{env.EnvironmentName}.json", optional: true)
        .AddJsonFile("fooSettings.json");

最后,在 ConfigureServices() 中(也在 Startup.cs 中)告诉它加载 FooSettings 的实例,将其转换为 IFooSettings(因此属性显示为已读-only) 并为 IFooSettings:

上的所有依赖项提供单个实例
    var fooSettings = (IFooSettings)ConfigurationBinder.Bind<FooSettings>(
        Configuration.GetConfigurationSection("FooSettings"));
    services.AddInstance(typeof (IFooSettings), fooSettings);

现在您的 class - 控制器、过滤器或由 DI 容器创建的任何其他东西 - 可以依赖于 IFooSettings 并且它将由 .json 文件提供.但是你可以模拟 IFooSettings 进行单元测试。

Original blog post - 这是我的,所以我没有抄袭。

如果您想 DI 操作过滤器参考 Action filters, service filters and type filters in ASP.NET 5 and MVC 6 服务过滤器部分。