HttpContextBase注入Ninject 3和SignalR 2.0

时间:2015-11-22 16:39:10

标签: asp.net dependency-injection signalr ninject

我已将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集线器?

2 个答案:

答案 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());
    }
}