You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 06:15:59