ASP.NET Core中如何正确装饰ServiceProvider实现属性注入?
解决ASP.NET Core中自定义ServiceProvider包装默认实例并确保自身被解析的问题
问题根源
你的自定义服务提供程序(SP)在解析IServiceProvider时,会委托给内置SP,而内置SP会返回它自身(ServiceProviderEngineScope),而非你的自定义实例。同时,IsService方法的实现逻辑存在性能和准确性问题,直接用GetService判断会额外触发服务解析,不符合内置SP的判断逻辑。
修正方案
1. 调整自定义ServiceProvider实现
直接基于内置SP进行包装,在处理IServiceProvider相关类型请求时返回自身,同时正确委托服务类型判断逻辑:
public class MyCustomServiceProvider : IServiceProvider, ISupportRequiredService, IServiceProviderIsService { private readonly IServiceProvider _innerProvider; private readonly IServiceProviderIsService _innerIsService; // 直接接收内置服务提供程序作为构造参数 public MyCustomServiceProvider(IServiceProvider innerProvider) { _innerProvider = innerProvider; // 获取内置的服务类型判断实现,保证准确性 _innerIsService = innerProvider.GetRequiredService<IServiceProviderIsService>(); } public object GetRequiredService(Type serviceType) { // 请求IServiceProvider或自身相关类型时,返回当前实例 if (serviceType == typeof(IServiceProvider) || serviceType == typeof(MyCustomServiceProvider) || serviceType == typeof(ISupportRequiredService) || serviceType == typeof(IServiceProviderIsService)) { return this; } // 委托内置SP获取服务,此处可插入属性注入逻辑 var service = _innerProvider.GetRequiredService(serviceType); // TODO: 执行属性注入,比如遍历标记了[Inject]的属性并注入依赖 return service; } public object? GetService(Type serviceType) { // 同样处理IServiceProvider相关类型请求 if (serviceType == typeof(IServiceProvider) || serviceType == typeof(MyCustomServiceProvider) || serviceType == typeof(ISupportRequiredService) || serviceType == typeof(IServiceProviderIsService)) { return this; } var service = _innerProvider.GetService(serviceType); if (service != null) { // TODO: 执行属性注入逻辑 } return service; } public bool IsService(Type serviceType) { // 委托内置SP的判断逻辑,避免自行实现的误差 return _innerIsService.IsService(serviceType); } }
2. 修改ServiceProviderFactory实现
先构建内置根SP,再用它创建自定义SP,确保包装的是最终的内置服务提供程序:
public class MyCustomServiceProviderFactory : IServiceProviderFactory<IServiceCollection> { private readonly ServiceProviderOptions _options; public MyCustomServiceProviderFactory(ServiceProviderOptions? options = null) { _options = options ?? new ServiceProviderOptions(); } public IServiceCollection CreateBuilder(IServiceCollection services) { return services; } public IServiceProvider CreateServiceProvider(IServiceCollection services) { // 先构建内置根服务提供程序 var innerProvider = services.BuildServiceProvider(_options); // 基于内置SP创建自定义包装实例 return new MyCustomServiceProvider(innerProvider); } }
3. 处理服务范围(可选)
如果应用使用请求范围服务,需要装饰IServiceScopeFactory,让创建的范围SP也使用自定义包装:
// 自定义服务范围 public class MyCustomServiceScope : IServiceScope { private readonly IServiceScope _innerScope; private readonly MyCustomServiceProvider _serviceProvider; public MyCustomServiceScope(IServiceScope innerScope) { _innerScope = innerScope; _serviceProvider = new MyCustomServiceProvider(innerScope.ServiceProvider); } public IServiceProvider ServiceProvider => _serviceProvider; public void Dispose() { _innerScope.Dispose(); } } // 自定义服务范围工厂 public class MyCustomServiceScopeFactory : IServiceScopeFactory { private readonly IServiceScopeFactory _innerFactory; public MyCustomServiceScopeFactory(IServiceScopeFactory innerFactory) { _innerFactory = innerFactory; } public IServiceScope CreateScope() { var innerScope = _innerFactory.CreateScope(); return new MyCustomServiceScope(innerScope); } }
然后在自定义SP的GetService方法中添加对IServiceScopeFactory的处理:
public object? GetService(Type serviceType) { // 原有逻辑... // 装饰IServiceScopeFactory,确保范围SP也是自定义实例 if (serviceType == typeof(IServiceScopeFactory)) { var innerFactory = _innerProvider.GetRequiredService<IServiceScopeFactory>(); return new MyCustomServiceScopeFactory(innerFactory); } // 原有逻辑... }
验证结果
在Program.cs中注册工厂后,验证解析结果:
var builder = WebApplication.CreateBuilder(args); builder.Host.UseServiceProviderFactory(new MyCustomServiceProviderFactory()); // ... 其他服务注册逻辑 var app = builder.Build(); // 验证根SP是自定义实例 var rootProvider = app.Services.GetRequiredService<IServiceProvider>(); Debug.Assert(rootProvider is MyCustomServiceProvider); // 断言通过 // 验证范围SP是自定义实例 using var scope = app.Services.CreateScope(); var scopeProvider = scope.ServiceProvider; Debug.Assert(scopeProvider is MyCustomServiceProvider); // 断言通过
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

