我已将Ninject设置为与SignalR(在IIS上托管)一起使用,如此问题的答案中所述:SignalR 2 Dependency Injection with Ninject。
这在大多数情况下都有效,除非客户端从集线器断开HttpContext.Current
变量为null
,因此Ninject无法注入值并抛出异常。
我已经了解了这个问题并发现大多数人都建议应该从HttpContext
检索当前IRequest.GetHttpContext()
(可以从集线器上下文访问)。遗憾的是,这在尝试注入值时无效(我可以从集线器传递上下文,但这会破坏依赖注入的目的)。
代码示例(为简洁起见,删除了一些部分):
public class TestHub : Hub
{
public TestHub(ITestService testService)
{
TestService = testService;
}
// When the disconnection request is issued, a ArgumentNullException
// for the HttpContext construction is thrown
public override Task OnDisconnected(bool stopCalled)
{
TestService.DoSomething();
}
}
public class TestService : ITestService
{
public TestService(HttpContextBase httpContext)
{
HttpContext = httpContext;
}
public void DoSomething()
{
// Service uses some data from the httpContext
TestLogger.Log(HttpContext.User.Identity.Name);
}
}
有没有办法将HttpContextBase
注入到服务中,而这些服务又会在不访问HttpContext.Current
的情况下注入SignalR集线器?
答案 0 :(得分:1)
如果HttpContext在构造时实际可用,您可以使用以下绑定:
kernel.Bind<HttpContextBase>()
.ToMethod(ctx => Context.Request.GetHttpContext())
.WhenAnyAncestorMatches(ctx => typeof(Hub).IsAssignableFrom(ctx.Plan.Type));
When
条件检查HttpContextBase
是否被注入Hub
(或派生类)或Hub
的任何依赖项。
如果HttpContextBase
仅在同意Hub
s时被注入,您也可以省略When
条件。
答案 1 :(得分:0)
我现在已经解决了这个问题,因此这不是问题的解决方案,而是一种不干净的方法来缓解它。
由于丢失的HttpContext
仅在客户端断开连接时发生,我首先将所有注入的服务标记为Lazy<T>
,因此它们不会立即得到解决,而只会在访问它们时解析。应用此更改后,仅当触发集线器SignalR OnDisconnected
事件中的代码时才会引发异常。因此,我必须修改在OnDisconnected
方法中执行的代码,以便直接从集线器检索上下文(或作为参数传递)。在我的情况下,没有太多代码在那里执行,但如果将来需要更多代码,它可能会成为一个问题。
从我的问题中应用于示例代码的补丁:
public class TestHub : Hub
{
public TestHub(Lazy<ITestService> testService)
{
TestService = testService;
}
public override Task OnDisconnected(bool stopCalled)
{
DoSomethingThatInvolvesHttpContext(Context.Request.GetHttpContext());
}
}