在我看来,让域服务需要一个IOptions实例来传递它配置是一个坏主意.现在我已经将额外的(不必要的?)依赖项拉入库中.我已经看到很多在网络上注入IOse的例子,但是我没有看到它带来的额外好处.
为什么不将实际的POCO注入服务?
services.AddTransient<IConnectionResolver>(x =>
{
var appSettings = x.GetService<IOptions<AppSettings>>();
return new ConnectionResolver(appSettings.Value);
});
Run Code Online (Sandbox Code Playgroud)
甚至使用这种机制:
AppSettings appSettings = new AppSettings();
Configuration.GetSection("AppSettings").Bind(appSettings);
services.AddTransient<IConnectionResolver>(x =>
{
return new ConnectionResolver(appSettings.SomeValue);
});
Run Code Online (Sandbox Code Playgroud)
使用设置:
public class MyConnectionResolver
{
// Why this?
public MyConnectionResolver(IOptions<AppSettings> appSettings)
{
...
}
// Why not this?
public MyConnectionResolver(AppSettings appSettings)
{
...
}
// Or this
public MyConnectionResolver(IAppSettings appSettings)
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
为什么附加依赖?IOptions给我带来了什么而不是旧式的注入方式?
Tse*_*eng 17
从技术上讲,没有什么可以阻止您使用ASP.NET Core的依赖注入注册POCO类或创建包装类并IOption<T>.Value
从中返回.
但是,你将失去选件包的高级功能,即让他们自动更新,当源的变化,你可以在源看这里.
正如您在该代码示例中所看到的,如果您通过services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
它注册选项,则会将appsettings.json中的设置读取并绑定到模型中,并另外跟踪它以进行更改.编辑appsettings.json时,将使用此处显示的新值重新绑定模型.
当然,如果您想将一些基础设施泄漏到您的域中或传递该Microsoft.Extension.Options
软件包提供的额外功能,您需要自己决定.它是一个非常小的包,它与ASP.NET Core无关,因此可以独立使用它.
该Microsoft.Extension.Options
包足够小,只包含抽象和具体的services.Configure
重载IConfiguration
(与配置的获取方式,命令行,json,环境,azure密钥库等更紧密相关)是一个单独的包.
总而言之,它对"基础设施"的依赖性非常有限.
Sha*_*ani 15
为了避免构造函数污染IOptions<>
:
startup.cs
通过里面的这两行简单的行,ConfigureServices
您可以注入IOptions
如下值:
public void ConfigureServices(IServiceCollection services)
{
//...
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
services.AddScoped(cfg => cfg.GetService<IOptions<AppSettings>>().Value);
}
Run Code Online (Sandbox Code Playgroud)
然后使用:
public MyService(AppSettings appSettings)
{
...
}
Run Code Online (Sandbox Code Playgroud)
虽然使用IOption
是官方的做事方式,但我似乎无法超越这样一个事实:我们的外部库不需要了解有关 DI 容器或其实现方式的任何信息。IOption
似乎违反了这个概念,因为我们现在告诉我们的类库一些关于 DI 容器注入设置的方式 - 我们应该只注入由该类定义的 POCO 或接口。
这让我非常恼火,以至于我编写了一个实用程序来将 POCO 注入到我的类库中,其中填充了 appSettings.json 部分中的值。将以下类添加到您的应用程序项目中:
public static class ConfigurationHelper
{
public static T GetObjectFromConfigSection<T>(
this IConfigurationRoot configurationRoot,
string configSection) where T : new()
{
var result = new T();
foreach (var propInfo in typeof(T).GetProperties())
{
var propertyType = propInfo.PropertyType;
if (propInfo?.CanWrite ?? false)
{
var value = Convert.ChangeType(configurationRoot.GetValue<string>($"{configSection}:{propInfo.Name}"), propInfo.PropertyType);
propInfo.SetValue(result, value, null);
}
}
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
可能还可以进行一些增强,但是当我使用简单的字符串和整数值对其进行测试时,它效果很好。DataStoreConfiguration
下面是我在应用程序项目的 Startup.cs -> ConfigureServices 方法中对名为的设置类和同名的 appSettings.json 部分使用此方法的示例:
services.AddSingleton<DataStoreConfiguration>((_) =>
Configuration.GetObjectFromConfigSection<DataStoreConfiguration>("DataStoreConfiguration"));
Run Code Online (Sandbox Code Playgroud)
appSettings.json 配置如下所示:
{
"DataStoreConfiguration": {
"ConnectionString": "Server=Server-goes-here;Database=My-database-name;Trusted_Connection=True;MultipleActiveResultSets=true",
"MeaningOfLifeInt" : "42"
},
"AnotherSection" : {
"Prop1" : "etc."
}
}
Run Code Online (Sandbox Code Playgroud)
该类DataStoreConfiguration
是在我的库项目中定义的,如下所示:
namespace MyLibrary.DataAccessors
{
public class DataStoreConfiguration
{
public string ConnectionString { get; set; }
public int MeaningOfLifeInt { get; set; }
}
}
Run Code Online (Sandbox Code Playgroud)
通过此应用程序和库配置,我可以使用构造函数注入将 DataStoreConfiguration 的具体实例直接注入到我的库中,而无需包装IOption
器:
using System.Data.SqlClient;
namespace MyLibrary.DataAccessors
{
public class DatabaseConnectionFactory : IDatabaseConnectionFactory
{
private readonly DataStoreConfiguration dataStoreConfiguration;
public DatabaseConnectionFactory(
DataStoreConfiguration dataStoreConfiguration)
{
// Here we inject a concrete instance of DataStoreConfiguration
// without the `IOption` wrapper.
this.dataStoreConfiguration = dataStoreConfiguration;
}
public SqlConnection NewConnection()
{
return new SqlConnection(dataStoreConfiguration.ConnectionString);
}
}
}
Run Code Online (Sandbox Code Playgroud)
解耦是 DI 的一个重要考虑因素,因此我不确定为什么 Microsoft 会引导用户将其类库耦合到外部依赖项(例如 )IOptions
,无论它看起来多么微不足道或它应该提供什么好处。我还认为,某些好处IOptions
似乎是过度设计的。例如,它允许我动态更改配置并跟踪更改 - 我已经使用了其他三个包含此功能的 DI 容器,但我从未使用过它一次...同时,我几乎可以向您保证团队会想要将 POCO 类或接口注入到库中以替换其设置ConfigurationManager
,经验丰富的开发人员不会对无关的包装器接口感到高兴。我希望 ASP.NET Core 的未来版本中包含与我在此描述的类似的实用程序,或者有人为我提供令人信服的论据来说明为什么我错了。
归档时间: |
|
查看次数: |
11290 次 |
最近记录: |