2014-01-22 109 views
12

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

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中的正确方法是什么?

回答

2

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

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

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?

+0

我尝试将StockTickerHub添加到我的内核,但它有依赖关系,我不知道如何创建......特别是StockTicker类对IHubConnectionContext有依赖关系。本文解决了使用它的自定义SignalRDependencyResolver,但正如我在我的问题中所说的,我不知道如何集成这两个内核。 – Dismissile

+0

Ninject将默认构建未绑定的具体类型,因此似乎手动添加Hub不是必需的:http://stackoverflow.com/questions/12398145/how-to-unbind-a-concrete-self-bound-singleton- bind-in-ninject-3#answer-12398187 – halter73

+0

还是不回答我的问题。我不知道如何把这两块拼在一起。 Stock Ticker样本已经在Startup.cs中创建了一个内核,但我也在NinjectWebCommon中创建了一个内核,并且他们彼此不知道。 – Dismissile

1

没有与单范围问题。我不知道谁应该在这里得到的怪(Ninject,SignalR,MVC,等...),但是如果你使用ToConstant它的工作原理:

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

我有同样的问题,我找到了解决办法:SignalR, WebAPI and MVC sharing the same dependency resolver kernel

我共享完整的解决方案与MVC的WebAPISignalR使用相同Ninject内核:https://drive.google.com/file/d/0B52OsuSSsroNX0I5aWFFb1VrRm8/edit?usp=sharing

这个例子的Web应用程序,包含一个网页,显示了AppDomain,并且应该是在三个框架的唯一对象的GetHashCode,给类似的结果:

Dependency Test 

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

我希望这有助于。

24

目前的答案都不能直接回答你的问题。一旦你确切知道该怎么做,获得结果的过程也非常简单。执行此操作的“正确”方式是在NinjectWebCommon类的CreateKernel方法中设置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类,需要添加任何其他代码。 Importanly的OwinStartup类保持不变,具体如下:

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

上面的例子实现这是你在你的问题提出以下重要成果:

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

希望这可以帮助人们。

+4

这个。请标记为答案。我找不到更好的方法来做到这一点。 我已经创建了这个效果的主旨,这要感谢这篇文章。 https://gist.github.com/darylteo/5a6b3656cedac556c83b –

+1

请问有人能告诉我'resolver'来自'RegisterServices()'方法吗? – Luke

+0

“解析器”引用实际上是从OP的代码示例中复制粘贴的。在'RegisterServices()'方法的上下文中,如果'resolver'被声明为一个局部变量,它就相当于'GlobalHost.DependencyResolver' – dcarson