使用Ninject进行SignalR 2依赖注入

时间:2014-01-22 14:41:19

标签: asp.net-mvc ninject signalr

我有一个使用Ninject依赖注入的现有MVC应用程序。我安装了Ninject.MVC3 nuget包,它在我的App_Start中创建了一个名为NinjectWebCommon的类,它完全隔离了内核并注册了我的所有绑定:

public static void Start()
{
    DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
    DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
    bootstrapper.Initialize(CreateKernel);
}

private static IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
    kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
    RegisterServices(kernel);
    return kernel;
}

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<IFoo>().To<Foo>();
}

我们有一个新的要求,我们认为SignalR能够满足,所以我们将SignalR 2 nuget包安装到项目中。我创建了一个Hub并对如何在项目中实现依赖注入进行了一些搜索,并找到了一篇建议创建SignalRDependencyResolver的文章。 http://www.asp.net/signalr/overview/signalr-20/extensibility/dependency-injection

本文让您在Startup.cs文件中创建一个内核,用于在OWIN中注册SignalR:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {

        var kernel = new StandardKernel();
        var resolver = new NinjectSignalRDependencyResolver(kernel);

        kernel.Bind<IStockTicker>()
            .To<Microsoft.AspNet.SignalR.StockTicker.StockTicker>()  // Bind to StockTicker.
            .InSingletonScope();  // Make it a singleton object.

        kernel.Bind<IHubConnectionContext>().ToMethod(context =>
            resolver.Resolve<IConnectionManager>().GetHubContext<StockTickerHub>().Clients
            ).WhenInjectedInto<IStockTicker>();

        var config = new HubConfiguration()
        {
            Resolver = resolver
        };

        app.MapSignalR(config);

    }
}

问题是这种方法让我创建了两个不同的内核,他们似乎有自己的一组依赖关系,他们知道如何解决。如果我在NinjectWebCommon中定义了依赖项,则Hub不知道如何解决该依赖项。如果没有在NinjectWebCommon中暴露我的内核,使用Ninject.MVC3包将DI添加到SignalR的正确方法是什么?

3 个答案:

答案 0 :(得分:29)

目前的答案都没有直接回答您的问题。一旦您确切知道该做什么,那么实现您所追求的结果非常简单。 “正确”的方法是在CreateKernel类的NinjectWebCommon方法中设置SignalR的依赖性解析器。

假设您已经创建了NinjectSignalRDependencyResolver类,除了以下代码段中突出显示的行外,不需要添加任何其他代码:

private static IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
    kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

    // THIS LINE DOES IT!!! Set our Ninject-based SignalRDependencyResolver as the SignalR resolver
    GlobalHost.DependencyResolver = new NinjectSignalRDependencyResolver(kernel);

    RegisterServices(kernel);
    return kernel;
}

除了上述内容之外,除了在RegisterServices NinjectWebCommon方法中声明绑定外,不需要做任何其他事情。在您的示例中,这将是:

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<IStockTicker>()
        .To<Microsoft.AspNet.SignalR.StockTicker.StockTicker>()  // Bind to StockTicker.
        .InSingletonScope();  // Make it a singleton object.

    kernel.Bind<IHubConnectionContext>().ToMethod(context =>
        resolver.Resolve<IConnectionManager>().GetHubContext<StockTickerHub>().Clients
        ).WhenInjectedInto<IStockTicker>();
}

除了您创建的NinjectSignalRDependencyResolver类之外,不需要添加其他代码。重要的是,OwinStartup类保持不变,如下所示:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.MapSignalR();
    }
}

以上示例实现了您在问题中提出的以下重要结果:

  • 您只创建了一个Ninject内核
  • 内核和所有绑定配置仍限于NinjectWebCommon
  • 默认的SignalR解析器是您的NinjectSignalRDependencyResolver
  • 实现所有SignalR集线器的依赖注入

希望这可以帮助别人。

答案 1 :(得分:2)

您是否尝试将StockTickerHub本身添加到内核中?

默认情况下,SignalR使用Activator.CreateInstance来构造没有任何构造函数参数的集线器。如果要将自己的依赖项注入Hub,可以通过向SignalR的依赖项解析器注册Hub来实现。

https://github.com/SignalR/SignalR/blob/2.0.1/src/Microsoft.AspNet.SignalR.Core/Hubs/DefaultHubActivator.cs#L28

如果您想要真正有创意,可以注册自己的IHubActivator,而不是单独注册所有的中心。

我将详细介绍如何在此答案中默认创建集线器:SignalR with IoC (Castle Windsor) - which lifetime for hubs?

答案 2 :(得分:1)

单例范围存在问题。我不知道谁应该在这里受到指责(Ninject,SignalR,MVC等等),但是如果你使用ToConstant它会有效:

var binding = Bind<IMustBeSingleton>().ToConstant(new MustBeSingleton());

我遇到了同样的问题,我找到了解决方案:SignalR, WebAPI and MVC sharing the same dependency resolver kernel

我使用相同的 Ninject 内核与{strong> MVC , WebAPI SignalR 共享完整的解决方案:{{ 3}}

该示例Web应用程序包含一个页面,该页面显示对象的AppDomainGetHashCode,该对象在三个框架中应该是唯一的,给出类似于的结果:

Dependency Test

Framework   IMySingletonService instance
MVC         AppDomainId:2 / HashCode:5109846
WebAPI      AppDomainId:2 / HashCode:5109846
SignalR     AppDomainId:2 / HashCode:5109846

我希望这会有所帮助。