在 Startup.ConfigureServices
中使用 services.BuildServiceProvider
的场景之一是在实现基于 IServiceCollection
的扩展方法时,可以不需要调用方传参 IConfiguration
,比如下面的扩展方法实现
public static IServiceCollection AddEnyimMemcached(
this IServiceCollection services,
string sectionKey = "enyimMemcached",
bool asDistributedCache = true)
{
var config = services.BuildServiceProvider().GetRequiredService<IConfiguration>();
return services.AddEnyimMemcached(config.GetSection(sectionKey), asDistributedCache);
}
但在微软官方文档 Dependency injection guidelines 的 recommendations 中有一条
Avoid calls to BuildServiceProvider in ConfigureServices. Calling BuildServiceProvider typically happens when the developer wants to resolve a service in ConfigureServices.
文档中为什么给出这样的建议?如果使用了,有什么副作用?
可以参考类似这样, 然后改造AddEnyimMemcached方法.
services.AddScoped<>(sp=> new xxx(sp.GetService<IConfiguration>()))
副作用情况:
会有多个IConfiguration的单例实例.
services.BuildServiceProvider() 这里会有一个, 在整个程序生命周期内还有一个.
所以: 如果有自定义的单例类要用到, 然后这个单例类里面又有一些不支持多次new的逻辑. 大概就会有冲突......
BUG情况:
如果有用到类似AddJsonStream 添加configuration provider, 那就会有问题, stream只支持读取一次......
如果直接在 Startup.ConfigureServices 中写 services.BuildServiceProvider()
,VS 会出现下面的警告
Calling 'BuildServiceProvider' from application code results in an additional copy of singleton services being created. Consider alternatives such as dependency injecting services as parameters to 'Configure'.
AddEnyimMemcached 是扩展方法,所以没有触发这个警告
@dudu:
改造是针对 可以不需要调用方传参 IConfiguration
, 类似下面的代码.
public static IServiceCollection AddEnyimMemcached(
this IServiceCollection services,
string sectionKey = "enyimMemcached",
bool asDistributedCache = true)
{
services.Add<T>(sp=>new T(sp.GetService<IConfiguration>().GetSection(sectionKey),asDistributedCache ))
}
多次 BuildServiceProvider 是不靠谱的方案😂
@czd890: 我按照这个方法改进一下试试
@dudu: 改进中遇到的问题 https://q.cnblogs.com/q/142503/
@dudu: 又在 stackoverflow 时发展一个参考:Resolving instances with ASP.NET Core DI from within ConfigureServices