为什么我们需要每次都调用BuildServiceProvider来获取依赖关系?

时间:2018-07-11 14:59:15

标签: c# asp.net-core dependency-injection ioc-container

在我的IServiceCollection上注册实例后,我需要注册一个IAutomapperProvider,它依赖于在此方法调用之前注册的IAssemblyProvider

public static IServiceCollection RegisterAutomapperConfiguration(this IServiceCollection container, ServiceLifetime lifeTime = ServiceLifetime.Scoped)
{
        //creating the provider to get the IAssemblyProvider for my IAutomapperProvider
        var prov = container.BuildServiceProvider();
        var assemblyProvider = prov.GetService<IAssemblyProvider>();
        container.Register<IAutomapperProvider>(aProv => new AutomapperProvider(assemblyProvider), lifeTime);
        var autoMapperProvider = prov.GetService<IAutomapperProvider>();
        var mapperConfig = autoMapperProvider.GetMapperConfiguration();
        ...
}

如果在致电container.Register<IAutomapperProvider>(aProv => new AutomapperProvider(assemblyProvider), lifeTime);之后  我不会再调用BuildServiceProvider,所以不会获得之前注册的IAutomapperProvider。

public static IServiceCollection RegisterAutomapperConfiguration(this IServiceCollection container, ServiceLifetime lifeTime = ServiceLifetime.Scoped)
{
        //creating the provider to get the IAssemblyProvider for my IAutomapperProvider
        var prov = container.BuildServiceProvider();
        var assemblyProvider = prov.GetService<IAssemblyProvider>();
        container.Register<IAutomapperProvider>(aProv => new AutomapperProvider(assemblyProvider), lifeTime);
        prov = container.BuildServiceProvider();
        var autoMapperProvider = prov.GetService<IAutomapperProvider>();
        var mapperConfig = autoMapperProvider.GetMapperConfiguration();
        ...
}

在AspNetCore代码上,当您调用BuildServiceProvider扩展方法时,它们使用相同的IServiceCollection,随着添加更多元素,该IServiceCollection可能会随着时间的变化而变化,最后您指向的是同一引用

public static ServiceProvider BuildServiceProvider(this IServiceCollection services)
{
    return BuildServiceProvider(services, ServiceProviderOptions.Default);
}

那为什么我需要再次调用它来获得一个知道如何解决我的服务的新实例?

为避免混淆,Register方法是我创建的扩展,但在内部调用AddSinglenton或Add ...

  public static IServiceCollection Register<TService>(this IServiceCollection container, Func<IServiceProvider, TService> implementationFactory, ServiceLifetime lifeTime)
        where TService : class
    {

    if (container == null)
        throw new ArgumentNullException(nameof(container));
    if (implementationFactory == null)
        throw new ArgumentNullException(nameof(implementationFactory));

    switch (lifeTime)
    {
        case ServiceLifetime.Scoped:
            container.AddScoped(typeof(TService), (Func<IServiceProvider, object>)implementationFactory);
            break;
        case ServiceLifetime.Transient:
            container.AddTransient(typeof(TService), (Func<IServiceProvider, object>)implementationFactory);
            break;
        default:// ServiceLifetime.Singleton
            container.AddSingleton(typeof(TService), (Func<IServiceProvider, object>)implementationFactory);
            break;
    }

    return container;
}

2 个答案:

答案 0 :(得分:0)

我也注意到了这一点。我需要在班级中解决一项服务,但是我可能已经让班级的使用者事先注册了其他服务。我最初已经打电话给BuildServiceProvider

问题在于,BuildServiceProvider被称为IServiceCollection的扩展方法,这样做会创建一个新的ServiceProvider

IServiceCollection实际上是IEnumerable<ServiceDescriptor>,因此创建ServiceProvider时的当前集合是消费者访问ServiceProvider实例时看到的内容

因此,您实际上并没有访问IServiceCollection的相同实例。

https://github.com/aspnet/DependencyInjection/blob/master/src/DI/ServiceCollectionContainerBuilderExtensions.cs

答案 1 :(得分:-1)

BuildServiceProvider不必经常调用。

这就是实现工厂委托的目的。他们为此提供访问服务提供商的权限。

仍然不确定为什么必须首先构建提供程序,但是基于当前提供的代码,在注册提供程序时会使用实现工厂委托中的服务提供程序。

public static IServiceCollection RegisterAutomapperConfiguration(this IServiceCollection services, 
    ServiceLifetime lifeTime = ServiceLifetime.Scoped) {

    services.Register<IAutomapperProvider>(p => //<-- p is IServiceProvider
         //use the provider to get the IAssemblyProvider for my IAutomapperProvider
        new AutomapperProvider(p.GetService<IAssemblyProvider>()), lifeTime);
    prov = services.BuildServiceProvider();
    var autoMapperProvider = prov.GetService<IAutomapperProvider>();
    var mapperConfig = autoMapperProvider.GetMapperConfiguration();
    //...
}

调用BuildServiceProvider时,创建的服务提供者将仅知道构建集合时所包含的类型。它不会知道任何其他类型,这就是为什么通常在注册所有类型时完成它。