如何使用WebAPI,WCF,SignalR和后台任务在MVC Web应用程序中配置简单的注入器容器和lifestylse

简单的注入器文档提供了有关如何为WebRequest,Web API,WCF设置容器的很好示例……但这些示例一次特定于一种技术/生活方式。 我们的Web应用程序大部分使用它们! 我不清楚如何配置容器以适应多种生活方式。


假设我有一个带有Web API的MVC项目。 我有以下对象:

  • MyDbContext:我的实体代码第一个db上下文
  • 由MyDataProvider实现的IMyDataProvider:包含查询逻辑并使用MyDbContext
  • MyController:使用IMyDataProvider的MVC控制器
  • MyApiController:使用IMyDataProvider的WebApi控制器

我应该为每种生活方式创建和配置一个容器吗?

当我使用RegisterPerWebRequest注册所有内容时, RegisterPerWebRequest适用于两种类型的控制器。 这样安全吗? 或者在Web API控制器中使用async / await时会遇到麻烦吗?

当我同时注入相同实例的MVC和Web API控制器时,最佳配置是什么?

我应该使用混合生活方式吗?


现在让事情变得复杂……我们的应用程序也使用后台任务和SignalR。

这些都有时会发生在WebRequest之外,并且需要访问如上所述的相同对象。

最好的解决方案是使用Lifetime范围?

我是否需要为这种生活方式创造一个新的容器? 或者我可以重用/重新配置我的MVC / Web API容器吗?

有三重生活方式吗?

通常你不需要每个生活方式有一个容器; 通常,您希望每个AppDomain都有一个容器实例。 但是,在与MVC相同的项目中混合Web API从架构的角度来看是一个可怕的想法IMO(如此处 , 此处和此处所述 )。 因此,如果您将这些部分分离到自己的架构块中,那么您已经有了更少的问题。

但是如果您在同一个项目中运行MVC和Web API,这基本上意味着您将始终使用Web API。 WebApiRequestLifestyle明确构建为工作:

IIS的内部和外部都很好。 即它可以在没有HttpContext.Current的自托管Web API项目中运行。 ( 来源 )

一般情况下,使用WebRequestLifestyle是安全的,如果您只是在IIS中运行,而您无意使用ConfigureAwait(false) (这应该是非常罕见的IMO)旋转并行操作,如此处所述。

因此,如果您仍然在同一个项目中将Web API与MVC混合使用,则没有理由使用混合生活方式 ; 你可以简单地使用相同的生活方式。 然而,对于后台处理,您可能需要构建混合生活方式,但每种情况都需要不同的混合。 但是,混合物可以堆叠起来,如果需要,您可以轻松创建“三重生活方式”。

由于您希望使用SignalR进行后台处理,因此您需要确定运行这些后台操作的范围生活方式 。 最明显的生活方式是LifetimeScopeLifestyle,这意味着您应该使用以下范围的生活方式进行范围注册:

 var hybridLifestyle = Lifestyle.CreateHybrid( lifestyleSelector: () => HttpContext.Current != null, trueLifestyle: new WebRequestLifestyle(), falseLifestyle: new LifetimeScopeLifestyle()); 

但是,生命周期范围需要显式启动(如果在Web应用程序中包含SimpleInjector.Integration.Web.dll,则会为您隐式启动Web请求范围)。 如何做到这一点取决于你的设计,但这个关于SignalR的q / a可能会指出你正确的方向。

我不得不说,我在前一段时间偶然发现了类似的情况,最后我通过我的web API和signalR分享了我的配置,但是你需要为signalR实现自定义的生活方式,因为它不是基于web请求。

特别是在signalR中,你会发现在Hub中处理每个web请求依赖项的一些问题,其中一些将像httpContext.Current一样是空的。

解决方案:

您需要WebRequestLifestlye与Lifestyle.Transient,Lifestyle.Singleton或LifetimeScopeLifestyle之间的混合生活方式。 我最终完成了使用装饰模式,你可以阅读这篇文章和另一篇文章 。

我的装饰师

 public class CommandLifetimeScopeDecorator : ICommandHandler { private readonly Func> _handlerFactory; private readonly Container _container; public CommandLifetimeScopeDecorator( Func> handlerFactory, Container container) { _handlerFactory = handlerFactory; _container = container; } public void Handle(T command) { using (_container.BeginLifetimeScope()) { var handler = _handlerFactory(); // resolve scoped dependencies handler.Handle(command); } } } public interface ICommandHandler { void Handle(T command); } 

我使用signalR的集线器激活器来管理依赖项

 public class MyHubActivator : IHubActivator { private readonly Container _container; public MyHubActivator(Container container) { _container = container; } public IHub Create(HubDescriptor descriptor) { return _container.GetInstance(descriptor.HubType) as IHub; } } 

复合根文件,您将在其中处理依赖项

 public CompositRoot(Container container) { _container = container; } public container Configure() { // _container.Registerall container dependencies return _container; } 

然后在引导应用程序时共享复合根配置

 var compositRoot = new CompositRoot(simpleInjector.Container); //simple injector instance compositRoot.Configure(); 

对于signalR

 GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => new MyHubActivator(compositRoot)); 

并且您可以在其他项目中重用您的配置!

我的两分钱希望有所帮助!