.NET Core Singleton Creation被多次调用

时间:2018-02-18 20:56:11

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

我正在将服务注册为.NET Core中的单例。然而,我正在看多次调用单例的构造函数。

services.AddSingleton<DbAuthorizationOptions, ContextAuthorizationOptions>();

我的上下文授权选项只是IValidators的实体类型词典,上下文授权选项被传递到DBContext,以自动运行验证。

在我的服务注册期间,我还注册了在DI中注册的容器的动态验证器。

var useDynamicValidator = serviceOption.ValidatorOptions != null;
if(useDynamicValidator)
{
    //TODO: Extract this to before the register service no sense in building the provider each time
    //TODO: Make this cleaner don't be dependent on Authorization options
    var provider = services.BuildServiceProvider();
    var authOptions = provider.GetService<DbAuthorizationOptions>();
    var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
    authOptions.ValidatorOptions.AddValidatorForSet(validator);
}

我注意到当我在提供者上调用GetService时,我会收到一个新的单例而不是现有的单例。构建提供程序是否会创建一个新容器,以便重新注册所有服务?

如果是这样,我如何调用一个方法来在具有现有IServiceProvider的单例容器中注册我的动态验证器,有没有办法在构建服务容器后调用一次注册?

2 个答案:

答案 0 :(得分:5)

  

构建提供程序是否会创建一个新容器,以便重新注册所有服务?

是。请参阅the source code

  

如果是这样,我如何调用一个方法在现有IServiceProvider的单例容器中注册我的动态验证器,有没有办法在构建servicecontainer之后调用一次注册?

我真的不明白为什么这是一个问题。您应该在Composition Root的应用程序启动时注册一次的所有服务。

DI容器负责解析应用程序的对象图。应用程序本身不应该依赖它,也不需要更新它。

你应该在你需要使用它的地方注射 DbAuthorizationOptions

public class Foo : IFoo
{
    private readonly DbAuthorizationOptions authOptions;

    public Foo(DbAuthorizationOptions authOptions) // <-- Inject parameters
    {
        this.authOptions = authOptions ??
            throw new ArgumentNullException(nameof(authOptions));
    }

    public void DoSomething()
    {
        // TODO: Inject the type that has the BuildDynamicValidatorFactory
        // method and the serviceOption (whatever type that is) here
        // either as a method parameter of this method, or a constructor
        // parameter of this class.
        var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
        // Now we have an instance of authOptions that can be used
        authOptions.ValidatorOptions.AddValidatorForSet(validator);
    }
}

请注意,DI容器自动提供DbAuthorizationOptions,如果注入另一种也通过DI解析的类型(例如控制器或过滤器)。

  

注意:从您的问题中不清楚您需要执行此操作。你提到你希望它发生一次,通常意味着把它放在应用程序启动时。但是用户无法与启动时运行的代码进行交互。所以,也许你可以使用filter。它实际上完全取决于应用程序生命周期中的 where

答案 1 :(得分:1)

您可以声明IServiceProvider的依赖关系 - 不要构建它,注入它。

public class SomeController
{
    DbAuthorizationOptions authOptions;
    public SomeController(IServiceProvider provider)
    {
        authOptions = provider.GetSerivce<DbAuthorizationOptions>();
    }
}

但这是service locator反模式。正如我在提供更多详细信息后对NightOwl888的帖子发表评论时,工厂可能是更好的方法。