.Net小知识:服务定位器

引言

我印象中记得如果在ASP.NET Core中使用内置的依赖注入,并且后台任务模式下有些情况使用构造函数注入会报错,但是我忘了是什么错误什么原因。然后我在网上找了一句话叫做

使用ASP.NET Core,您可以选择创建和管理自己的范围,通过调用CreateScope()来获取HttpRequest之外的服务。

但是本文不讨论这个东西,我今天突然好奇IServiceScopeFactory和IServiceProvider都可以创建CreateScope,具体有什么区别那?下面来简单看看。.

操作

本文示例环境:vs2022、.Net6

CreateScope将创建一个完全独立于任何当前作用域的新作用域。如果从新作用域解析服务,它将返回该服务的新实例。

IServiceScopeFactory

public class OperationLogHandler : INotificationHandler<AddOperationLogEvent>
{
    private readonly IServiceScopeFactory _serviceScopeFactory;

    public OperationLogHandler(IServiceScopeFactory serviceScopeFactory)
    {
        _serviceScopeFactory = serviceScopeFactory;
    }

    public async Task Handle(AddOperationLogEvent notification, CancellationToken cancellationToken)
    {
        using (var scope = _serviceScopeFactory.CreateScope())
        {
            var _httpContextAccessor = scope.ServiceProvider.GetRequiredService<IHttpContextAccessor>();
            var _operationLogRepository = scope.ServiceProvider.GetRequiredService<IOperationLogRepository>();

            if (notification is null || !notification.IsValidOperation())
                return;
                
            //xxx
        }
    }
}

IServiceScopeFactory的CreateScope方法实现是ServiceProviderEngineScope下面的

public IServiceScope CreateScope() => this.RootProvider.CreateScope();

CreateScope方法实现是

internal IServiceScope CreateScope()
{
  if (this._disposed)
 ThrowHelper.ThrowObjectDisposedException();
  return (IServiceScope) new ServiceProviderEngineScope(this, false);
}

IServiceProvider

public class OperationLogHandler : INotificationHandler<AddOperationLogEvent>
{
    private readonly IServiceProvider _serviceProvider;

    public OperationLogHandler(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public async Task Handle(AddOperationLogEvent notification, CancellationToken cancellationToken)
    {
        using (var scope = _serviceProvider.CreateScope())
        {
            var _httpContextAccessor = scope.ServiceProvider.GetRequiredService<IHttpContextAccessor>();
            var _operationLogRepository = scope.ServiceProvider.GetRequiredService<IOperationLogRepository>();

            if (notification is null || !notification.IsValidOperation())
                return;

            //xxx
        }
    }
}

IServiceProvider的CreateScope方法实现是

public static IServiceScope CreateScope(this IServiceProvider provider) => provider.GetRequiredService<IServiceScopeFactory>().CreateScope();

最后调用的实现类也是ServiceProviderEngineScope里面的CreateScope方法

public IServiceScope CreateScope() => this.RootProvider.CreateScope();

结论

因为IServiceScopeFactory和IServiceProvider最后调用的都是ServiceProviderEngineScope里面的CreateScope方法,所以我认为它俩是一样的。

资料

ServiceProviderEngineScope实现类在Microsoft.AspNetCore.App\6.0.5\Microsoft.Extensions.DependencyInjection.dll下面的Microsoft.Extensions.DependencyInjection.ServiceLookup文件夹下。