Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
IServiceProvider.GetSingleton在Asp.Net核心DI中解析null_.net_Dependency Injection_Asp.net Core_Asp.net Core Mvc_.net Core - Fatal编程技术网

IServiceProvider.GetSingleton在Asp.Net核心DI中解析null

IServiceProvider.GetSingleton在Asp.Net核心DI中解析null,.net,dependency-injection,asp.net-core,asp.net-core-mvc,.net-core,.net,Dependency Injection,Asp.net Core,Asp.net Core Mvc,.net Core,在应用程序的ConfigureServices引导过程中,我主要使用.Net Core附带的依赖项注入框架注册瞬态和作用域类型。然而,我确实有一种类型注册为单例,那就是我的InProcessBus,我使用的是CQS样式的体系结构 services.AddSingleton<InProcessBus>(new InProcessBus()); ... services.AddSingleton<ICommandSender>(y => y.GetSe

在应用程序的ConfigureServices引导过程中,我主要使用.Net Core附带的依赖项注入框架注册瞬态和作用域类型。然而,我确实有一种类型注册为单例,那就是我的InProcessBus,我使用的是CQS样式的体系结构

services.AddSingleton<InProcessBus>(new InProcessBus());
...         
services.AddSingleton<ICommandSender>(y => y.GetService<InProcessBus>());
services.AddSingleton<IEventPublisher>(y => y.GetService<InProcessBus>());

为什么针对容器中明显存在的单例的ImplementationFactory方法在运行时无法解决问题?

我发现了问题所在,并认为我将在这里发布它,因为其中有一个重要的教训

简单的回答是:

注册所有单例实例后,请将serviceCollection.BuildServiceProvider延迟到,否则它将无法解析它们

答案很长:

这个问题实际上与asp核心DI容器无关。问题在于调用serviceCollection实例上的BuildServiceProvider以向我提供IServiceProvider的时间

在我的实现中,我实现了一个ServiceLocator模式,它包装了随core一起提供的DI框架,这样我就不会在其他体系结构层中引入额外的依赖关系。当我构造基于IServiceContainer的定位器时,我立即解析ServiceProvider

这就是问题所在。显然,创建服务提供者的时间对于瞬态和作用域实例并不重要。但对于有管理寿命的单身人士来说,确实如此。在所有注册之后,您需要推迟创建服务提供商

从我的问题来看,ServiceLocator是在代码段之前构造的,这意味着当执行implementationFactory函数时,ServiceProvider将无法访问Singleton实例


通过将ServiceProvider的创建推迟到我的应用程序在运行时第一次解析一个自定义类型,解决了这个问题。

这很奇怪。尽管您可能希望避免使用y.GetService,而使用y.GetRequiredService,如果无法解决,它将抛出异常,而不是返回null。虽然这可能无法解决你的问题。还有别的吗?此外,您无法在ConfigureServices内部解决此问题,因为此时容器尚未构建。如果您使用模板附带的标准Startup.cs,您可以解析服务的最早一点是Configure方法您确定要使用内置容器吗?CQRS体系结构风格非常强大,因为它们使使用装饰器应用横切关注点变得非常容易。无法使用内置容器应用泛型装饰器。@Tseng,感谢GetRequiredService提示,显式异常比null好。通常无法解决“是”,但当我遇到问题时,我使用BuildServiceProvider构建了我自己的提供程序以内联测试…@Steven,我使用自定义跨框架容器契约包装容器,这样我就不会对任何特定容器有硬容器依赖性。这个特定的CQRS实现非常简单,因为我实际上主要是在玩.Net内核和标准。@SarelEsterhuizen:您也不会对内置的有任何依赖关系。你唯一需要引用的地方就是你的合成根。在所有其他层中,您只需在类构造函数或IEnumerable中插入所需服务的接口(如果您需要某个类型的所有注册)。ServiceLocator只是一个非常糟糕的模式。另请参见下面我的评论,您将遇到其他问题,因为您现在可能有两个容器实例,其中一个永远不会被处理。因此,如果使用不正确,您的作用域服务可能会成为服务定位器中的单例。您可能会在这种方法中遇到其他问题,忽略服务定位器是反模式的,超出了DI/IoC的全部目的:您的系统中现在有两个容器,一个是ASP.NET Core在调用Configure之前创建的,另一个是您为反模式定位器创建的,这将是作用域服务DbContext的问题,因为使用ASP.NET Core IoC的服务和使用服务定位器的服务将具有不同的实例,例如,调用SaveChanges将无法保护其他上下文中的更改,并且您将失去工作单元的优势。那么,您是否可以精心设计一种模式,包装随core提供的DI框架,这样我就不会在其他体系结构层中引入额外的依赖关系?在Microsoft.Extensions.DependencyInjection的其他层中不需要任何其他依赖项。您只需要在web应用程序中使用它,在该应用程序中,您可以在合成根目录中构建对象图。从架构的角度来看,您的方法似乎非常错误,它创建了一个硬依赖,并且变得难以/不可能进行单元测试
ServiceLocator.GetService<ICommandSender>() // Is Null
public ServiceLocator(
        IServiceCollection serviceCollection)
    {
        _serviceCollection = serviceCollection;
        _serviceProvider = _serviceCollection.BuildServiceProvider();
    }