Ilj*_* S. 7 .net c# simple-injector signalr asp.net-web-api
根据这篇文章,应该可以将每个Web请求依赖项注入SignalR集线器(尽管有一些限制,如OnDisconnected()方法的问题).在我的例子中,它是ASP Web API(而不是MVC),并且由于某种原因它不起作用.
以下是相关部分:
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);
Run Code Online (Sandbox Code Playgroud)
这个类可以注入集线器:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
和Hub本身:
[HubName("sample")]
public class SampleHub : Hub
{
public ActiveBetsHub(ISampleRepository repository)
{
}
//Irrelevant methods here. OnDisconnected() NOT implemented!
}
Run Code Online (Sandbox Code Playgroud)
通过此设置,我得到例外:
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.
Run Code Online (Sandbox Code Playgroud)
据我所知,这是预期的.但是当我将存储库的生活方式更改为Transient时,我得到完全相同的异常:
var transientHybrid = Lifestyle.CreateHybrid(() => HttpContext.Current != null, new WebApiRequestLifestyle(), Lifestyle.Transient);
container.Register<ISampleRepository, SampleRepository>(transientHybrid);
Run Code Online (Sandbox Code Playgroud)
我怀疑问题可能在于HttpContext.Current != null
检查不适用于Web API的方式与MVC相同.
SignalR 2.2
简单的注射器2.8.3
我错过了什么?
更新:
这是关于SignalR如何创建Hub的堆栈跟踪:
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)
Run Code Online (Sandbox Code Playgroud)
因此,适当的解决方案是ExecutionContextScope
用于集线器,但这个范围需要明确关闭,这使事情变得更复杂......
您对混合生活方式的定义不正确.这WebApiRequestLifestyle
并不依赖于HttpContext
如此检查是否HttpContext.Current != null
不起作用.您必须通过调用container.GetCurrentExecutionContextScope()
以下方法检查是否存在活动的Web API请求生活方式范围(或执行上下文范围,基本相同):
var transientHybrid = Lifestyle.CreateHybrid(
() => container.GetCurrentExecutionContextScope() != null,
new WebApiRequestLifestyle(),
Lifestyle.Transient);
Run Code Online (Sandbox Code Playgroud)
但请注意,你应该非常小心地构成一个混乱的生活方式和短暂的生活方式,因为这很容易产生错误的结果.这实际上是一些DI库的默认行为,但这是一个设计缺陷 IMO.我假设您非常有意识地MyDbContext
使用范围生活方式注册您,因为您需要确保在整个请求中使用相同的实例.使用Transient
生活方式意味着您可以MyDbContext
在请求期间获得多个.这可能不是问题,因为在您的集线器中,您当前可能只有一个引用MyDbContext
,但是一旦对象图更改并MyDbContext
添加了第二个引用,您的代码可能会中断.
相反,我建议不要使用这种生活方式的组合.所以,应该使用无论是WebApiRequestLifestyle
或ExecutionContextScopeLifestyle
(它们是相同的),并确保在你的集线器解决这样的执行上下文范围开始.
顺便说一句,不要忘记在Simple Injector中明确注册您的集线器.这允许Simple Injector为您分析完整的对象图,包括您的集线器类.