简单的喷油器每个Web-API请求依赖性SignalR集线器 [英] Simple Injector per-web-api-request dependency in SignalR hub

查看:220
本文介绍了简单的喷油器每个Web-API请求依赖性SignalR集线器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据<一href="http://stackoverflow.com/questions/10555791/using-simpleinjector-with-signalr/18487801">this交的,它应该是可能注入每个网页请求依赖成SignalR毂(虽然与像问题OnDisconnected()方法有一些限制)。在我的情况下,它是ASP的Web API(不MVC),并没有出于某种原因。

According to this post, it should be possible to inject per-web-request dependencies into SignalR hubs (although with some limitations like problem with OnDisconnected() method). In my case it is ASP Web API (not MVC) and it does not work for some reason.

下面是相关的部分:

container.RegisterWebApiControllers(httpConfiguration);

container.RegisterWebApiRequest<DbContext, MyDbContext>();
container.RegisterWebApiRequest<ISampleRepository, SampleRepository>(); //DbContext injected to SampleRepository


//Enable injections to SignalR Hubs
var activator = new SimpleInjectorHubActivator(container);
GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => activator);

本类使得能够注入到集线器:

This class makes possible to inject into hubs:

public class SimpleInjectorHubActivator : IHubActivator
        {
            private readonly Container _container;

            public SimpleInjectorHubActivator(Container container)
            {
                _container = container;
            }

            public IHub Create(HubDescriptor descriptor)
            {
                return (IHub)_container.GetInstance(descriptor.HubType);
            }
}

和轮毂本身:

 [HubName("sample")]
 public class SampleHub : Hub
    {

        public ActiveBetsHub(ISampleRepository repository)
        {
        }

        //Irrelevant methods here. OnDisconnected() NOT implemented!
    }

通过这种设置,我得到异常:

With this setup I get exception:

No registration for type SampleHub could be found and
an implicit registration could not be made. 
The ISampleRepository is registered as 'Web API Request' 
lifestyle, but the instance is requested outside the context of a Web API Request.

预计随着我了解哪些。但是我得到完全相同的异常时,我改变仓库的生活方式瞬态:

Which is expected as I understand. However I get exactly same exception when I change Lifestyle of repository to Transient:

    var transientHybrid = Lifestyle.CreateHybrid(() => HttpContext.Current != null, new WebApiRequestLifestyle(), Lifestyle.Transient);
    container.Register<ISampleRepository, SampleRepository>(transientHybrid);

我怀疑问题可能在于 HttpContext.Current!= NULL 检查工作不用于Web API的方式相同MVC。

I suspect the problem could lie in HttpContext.Current != null check that is not working for Web API the same way as for MVC.

SignalR 2.2

SignalR 2.2

简单的喷油器2.8.3

Simple Injector 2.8.3

我怎么会错过?

更新:

这对SignalR如何创造集线器的堆栈跟踪:

This is stack trace on how SignalR creates Hubs:

at SimpleInjector.InstanceProducer.GetInstance()
   at SimpleInjector.Container.GetInstance(Type serviceType)
   at MyWebAbi.WebApiApplication.SimpleInjectorHubActivator.Create(HubDescriptor descriptor) in Global.asax.cs:line 108
   at Microsoft.AspNet.SignalR.Hubs.DefaultHubManager.ResolveHub(String hubName)
   at Microsoft.AspNet.SignalR.Hubs.HubDispatcher.CreateHub(IRequest request, HubDescriptor descriptor, String connectionId, StateChangeTracker tracker, Boolean throwIfFailedToCreate)

所以,正确的解决办法是使用 ExecutionContextScope 的轮毂,但这个范围,需要明确地关闭,这使得事情更加复杂......

So the proper solution would be to use ExecutionContextScope for a Hubs but this scope needs to be explicitly closed which makes things more complicated...

推荐答案

您的混合生活方式的定义不正确。该 WebApiRequestLifestyle 不依赖以任何方式对的HttpContext 所以,检查是否 HttpContext.Current! = NULL 将无法正常工作。您必须检查是否有一个活动的Web API请求生活方式的范围(或执行上下文的范围,这是基本相同),通过调用 container.GetCurrentExecutionContextScope()

Your definition of your hybrid lifestyle is incorrect. The WebApiRequestLifestyle does not depend in any way on the HttpContext so checking whether HttpContext.Current != null will not work. You will have to check if there is an active Web API request lifestyle scope (or execution context scope, which is basically the same) by calling container.GetCurrentExecutionContextScope():

var transientHybrid = Lifestyle.CreateHybrid(
    () => container.GetCurrentExecutionContextScope() != null, 
    new WebApiRequestLifestyle(), 
    Lifestyle.Transient);

待办事项但是,你应该非常小心撰写范围的生活方式和短暂的混合生活方式,因为这将很容易在错误的结果产生。这实际上是一些DI库的默认行为,但是这是一个<一个href="https://simpleinjector.readthedocs.org/en/latest/decisions.html#dont-allow-resolving-outside-an-active-scope"相对=nofollow>设计缺陷的海事组织。我想你很自觉地注册了 MyDbContext 与范围的生活方式,因为你需要确保同样的实例用于整个请求。使用瞬态生活方式意味着,你可能会得到多个 MyDbContext 的请求过程中。这可能不是一个问题,因为在你的集线器,你可能现在只有一个引用您的 MyDbContext ,但你的code可能会破坏一旦你的对象图的变化和第二次提到 MyDbContext 添加。

Do note however that you should be very careful composing a hybrid lifestyle of a scoped lifestyle and transient, because this will easily yield in wrong results. This is actually the default behavior of some DI libraries, but this is a design flaw IMO. I assume you very consciously registered your MyDbContext with the scoped lifestyle, because you need to make sure that the same instance is used throughout the request. Using the Transient lifestyle means that you might get multiple MyDbContext during the request. This might not be a problem, because in your hubs you might currently only have one reference to your MyDbContext, but your code might break once your object graph changes and a second reference to MyDbContext is added.

所以不是,我会建议不使用生活方式的结合。相反,只请使用 WebApiRequestLifestyle ExecutionContextScopeLifestyle (它们是同一个),并确保这样的执行上下文范围开始之前,你的集线器解决。

So instead, I would advice not using this combination of lifestyles. Instead, just use either the WebApiRequestLifestyle or the ExecutionContextScopeLifestyle (they are the same) and make sure that such a execution context scope is started before your hub is resolved.

顺便说一下,不要忘记在简单的喷油器直接注册您的枢纽。这使得简单的注射器来分析完整的对象图给你,包括你的集线器类。

And by the way, don't forget to register your hubs explicitly in Simple Injector. This allows Simple Injector to analyze the complete object graph for you including your hub classes.

这篇关于简单的喷油器每个Web-API请求依赖性SignalR集线器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆