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
。
您也可以在非控制器 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
的实例,将其转换为 IFooSetting
s(因此属性显示为已读-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 服务过滤器部分。
我可以像这样在控制器中设置 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
。
您也可以在非控制器 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
的实例,将其转换为 IFooSetting
s(因此属性显示为已读-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 服务过滤器部分。