【问题标题】:Why we need to call BuildServiceProvider to get dependencies everytime?为什么每次都需要调用 BuildServiceProvider 来获取依赖?
【发布时间】:2018-12-19 16:27:39
【问题描述】:

在我的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&lt;IAutomapperProvider&gt;(aProv =&gt; 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,该方法会随着时间的推移而更改,添加更多元素,最后您指向的是相同的引用

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;
}

【问题讨论】:

  • 这是XY problem。你需要澄清一些事情。这是什么Register?那是一些外部第三方扩展吗?明确你想要达到的目标。
  • @Nkosi 你是对的,我更新了问题

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


【解决方案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 被调用时,所创建的服务提供者将只知道在构建时集合中的类型。它不会知道任何其他类型,这就是为什么它通常在注册所有类型结束时完成。

【讨论】:

  • 这和我暴露的问题一样
  • @NKosi 我不知道为什么有人会反对你的答案,因为它是正确的。
【解决方案2】:

我也注意到了这一点。我需要解决班级中的一项服务,但我可能已经让班级的消费者事先注册了其他服务。我一开始已经打电话给BuildServiceProvider

问题是BuildServiceProvider 被调用为IServiceCollection 的扩展方法,这样做会创建一个新的ServiceProvider

IServiceCollection 实际上是IEnumerable&lt;ServiceDescriptor&gt;,因此无论在创建ServiceProvider 时当前集合是什么,消费者在访问ServiceProvider 的实例时都会看到。

所以你并没有真正访问IServiceCollection 的同一个实例。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多