简体   繁体   English

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

[英]How to configure simple injector container and lifestylse in a MVC web app with WebAPI, WCF, SignalR and Background Task

The simple injector documentation provides great examples on how to setup the container for WebRequest, Web API, WCF, ... but the examples are specific to one technology/lifestyle at a time. 简单的注入器文档提供了有关如何为WebRequest,Web API,WCF设置容器的很好示例......但这些示例一次特定于一种技术/生活方式。 Our web application uses most of them together! 我们的Web应用程序大部分使用它们! It is not clear to me how to configure the container to work with several lifestyles. 我不清楚如何配置容器以适应多种生活方式。


Let's say I have a MVC project with Web API. 假设我有一个带有Web API的MVC项目。 I have the following objects: 我有以下对象:

  • MyDbContext : My entity code first db context MyDbContext:我的实体代码第一个db上下文
  • IMyDataProvider implemented by MyDataProvider : Contains query logic and uses MyDbContext 由MyDataProvider实现的IMyDataProvider:包含查询逻辑并使用MyDbContext
  • MyController : MVC controller that uses IMyDataProvider MyController:使用IMyDataProvider的MVC控制器
  • MyApiController : WebApi controller that uses IMyDataProvider MyApiController:使用IMyDataProvider的WebApi控制器

Should I create and configure one container for each type of lifestyle ? 我应该为每种生活方式创建和配置一个容器吗?

When I register everything with RegisterPerWebRequest<T> is works in both types of controllers. 当我使用RegisterPerWebRequest<T>注册所有内容时, RegisterPerWebRequest<T>适用于两种类型的控制器。 Is this safe ? 这样安全吗? Or will I run into trouble when using async/await in a Web API controller? 或者在Web API控制器中使用async / await时会遇到麻烦吗?

What is the best configuration when I have both MVC and Web API controllers who get injected the same instances ? 当我同时注入相同实例的MVC和Web API控制器时,最佳配置是什么?

Should I use a hybrid lifestyle ? 我应该使用混合生活方式吗?


Now to complicate things... our application also uses background tasks and SignalR. 现在让事情变得复杂......我们的应用程序也使用后台任务和SignalR。

Both of these will sometimes occur outside of a WebRequest and need access to the same objects as described above. 这些都有时会发生在WebRequest之外,并且需要访问如上所述的相同对象。

The best solution would be to use a Lifetime scope ? 最好的解决方案是使用Lifetime范围?

Would I need to create a new container for that lifestyle? 我需要为这种生活方式创造一个新的容器吗? or can I reuse/reconfigure my MVC/Web API container ? 或者我可以重用/重新配置我的MVC / Web API容器吗?

Is there a triple lifestyle? 有三重生活方式吗?

I have to say, I stumble on a similar scenario some time ago, I ended up by sharing my configuration over my web API and signalR, but you need to implement a custom lifestyle for signalR since it's not based on web request. 我不得不说,我在前一段时间遇到过类似的情况,最后我通过我的web API和signalR分享了我的配置,但你需要为signalR实现自定义的生活方式,因为它不是基于web请求。

specially in signalR you'll find some issues handling per-web-request dependencies in a Hub some of them are going to be null like httpContext.Current among others. 特别是在signalR中,你会发现在Hub中处理每个web请求依赖项的一些问题,其中一些将像httpContext.Current一样是空的。

The solution: 解决方案:

You need a hybrid lifestyle between WebRequestLifestlye and either Lifestyle.Transient, Lifestyle.Singleton, or LifetimeScopeLifestyle. 您需要WebRequestLifestlye与Lifestyle.Transient,Lifestyle.Singleton或LifetimeScopeLifestyle之间的混合生活方式。 I ended up I finished using the decorator pattern, you may read this post and this other post . 我最终完成了使用装饰模式,你可以阅读这篇文章和另一篇文章

my decorator 我的装饰师

public class CommandLifetimeScopeDecorator<T> : ICommandHandler<T>
    {
        private readonly Func<ICommandHandler<T>> _handlerFactory;
        private readonly Container _container;

        public CommandLifetimeScopeDecorator(
        Func<ICommandHandler<T>> 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<in T>
    {
        void Handle(T command);
    }

I managed the dependencies using a hub activator for signalR 我使用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;
        }
    }

a composite root file which is where you are going to handle your dependencies 复合根文件,您将在其中处理依赖项

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

then share your composite root configuration when you are bootstrapping your app 然后在引导应用程序时共享复合根配置

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

For signalR 对于signalR

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

and you may reuse your configuration among other projects! 并且您可以在其他项目中重用您的配置!

my two cents hope that helps! 我的两分钱希望有所帮助!

Usually you don't need to have one container per lifestyle; 通常你不需要每个生活方式有一个容器; In general you want to have one container instance per AppDomain. 通常,您希望每个AppDomain都有一个容器实例。 However, mixing Web API in the same project with MVC is from an architectural point of view a horrible idea IMO (as explained here , here , and here ). 但是,在与MVC相同的项目中混合Web API从架构的角度来看是一个可怕的想法IMO(如此此处此处所述 )。 So in case you are separating those parts into their own architectural blocks, you will already have less problems already. 因此,如果您将这些部分分离到自己的体系结构块中,那么您已经有了更少的问题。

But in case you are running MVC and Web API in the same project, this basically means that you will always be using Web API. 但是如果您在同一个项目中运行MVC和Web API,这基本上意味着您将始终使用Web API。 The WebApiRequestLifestyle was explicitly built to work: WebApiRequestLifestyle明确构建为工作:

well both inside and outside of IIS. 在IIS的内部和外部。 ie It can function in a self-hosted Web API project where there is no HttpContext.Current. 即它可以在没有HttpContext.Current的自托管Web API项目中运行。 ( source ) 来源

In general, it is safe to use the WebRequestLifestyle in case you are only running in IIS when you have no intention to spin of parallel operations using ConfigureAwait(false) (which should be really rare IMO) as explained here . 在一般情况下,它是安全的,当你有没有打算利用旋转并行操作的使用,以防WebRequestLifestyle你只运行在IIS ConfigureAwait(false) (这应该是真是难得IMO)作为解释在这里

So in the case you are still mixing Web API with MVC in the same project, there's no reason to use a hybrid lifestyle ; 因此,如果您仍然在同一个项目中将Web API与MVC混合使用,则没有理由使用混合生活方式 ; you can simply use the same lifestyle. 你可以简单地使用相同的生活方式。 For doing background processing you might however need to build a hybrid lifestyle, but it every scenario needs a different hybrid. 然而,对于进行后台处理,您可能需要构建混合生活方式,但每种情况都需要不同的混合体。 However, hybrids can be stacked up and you can easily create a 'triple lifestyle' if needed. 但是,混合动力车可以堆叠起来,如果需要,您可以轻松创建“三重生活方式”。

Since you want to do background processing with SignalR, you need to decide in what type of scoped lifestyle to run those background operations. 由于您希望使用SignalR进行后台处理,因此您需要确定运行这些后台操作的范围生活方式 The most obvious lifestyle is the LifetimeScopeLifestyle and this means you should make your scoped registrations using the following scoped lifestyle: 最明显的生活方式是LifetimeScopeLifestyle,这意味着您应该使用以下范围的生活方式进行范围注册:

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

A lifetime scope however needs to be started explicitly (as were the web request scope gets started implicitly for you if you include the SimpleInjector.Integration.Web.dll in your web application). 但是,生命周期范围需要显式启动(如果在Web应用程序中包含SimpleInjector.Integration.Web.dll,则会为您隐式启动Web请求范围)。 How to do this depends on your design, but this q/a about SignalR might point you in the right direction. 如何做到这一点取决于你的设计,但这个关于SignalR的q / a可能会指出你正确的方向。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM