web-dev-qa-db-ja.com

毎回依存関係を取得するためにBuildServiceProviderを呼び出す必要があるのはなぜですか?

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が使用され、要素を追加することで時間の経過とともに変化する可能性があります。最後に、同じ参照をポイントします。

_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;
}
_
5
Heinrich

私もこれに気づきました。クラスのサービスを解決する必要がありますが、クラスのコンシューマーに事前に追加のサービスを登録させている可能性があります。最初はすでにBuildServiceProviderに電話しました。

問題は、BuildServiceProviderIServiceCollectionの拡張メソッドとして呼び出されており、そうすると新しいServiceProviderが作成されることです。

IServiceCollectionは実際にはIEnumerable<ServiceDescriptor>したがって、ServiceProviderが作成された時点での現在のコレクションが何であれ、消費者はServiceProviderのそのインスタンスにアクセスしたときに表示されます。

したがって、実際にはIServiceCollectionの同じインスタンスにアクセスしているわけではありません。

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

1
EnderWiggin