SignalR 2 Dependency Injection with Ninject

大城市里の小女人 提交于 2019-11-28 06:58:44

None of the current answers directly answer your question. Also achieving the result you are after is very straightforward once you know exactly what to do. The "proper" way to do this is to set SignalR's dependency resolver in the CreateKernel method of the NinjectWebCommon class.

Assuming you have created a NinjectSignalRDependencyResolver class as you mention, no other code needs to be added anywhere except for the line highlighted in the code snippet below:

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;
}

Apart from the above, nothing more needs to be done except declaring your bindings in the RegisterServices method of NinjectWebCommon. In your example this would look like:

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

Except for the NinjectSignalRDependencyResolver class you created, no other code needs to be added. Importanly, the OwinStartup class remains unmodified, as follows:

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

The above example achieves the following important outcomes which were what you asked in your question:

  • You only have a single Ninject Kernel created
  • The kernel and all binding configurations remain confined to NinjectWebCommon
  • The default SignalR resolver is your NinjectSignalRDependencyResolver
  • Dependency Injection into all SignalR hubs is achieved

Hopefully this helps people out.

halter73

Have you tried adding the StockTickerHub itself to your kernel?

By default, SignalR uses Activator.CreateInstance to construct Hubs without any constructor arguments. If you want to inject your own dependencies into a Hub, you can do so by registering the Hub with SignalR's dependency resolver.

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

If you want to get really creative, you can register your own IHubActivator instead of registering all of Hubs individually.

I go into more detail in how Hubs are created by default in this answer: SignalR with IoC (Castle Windsor) - which lifetime for hubs?

vtortola

There is a problem with the singleton scope. I don´t know who should get the blame here (Ninject, SignalR, MVC, etc...), but it works if you use ToConstant:

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

I had the same problem, and I found the solution: SignalR, WebAPI and MVC sharing the same dependency resolver kernel

I shared a complete solution with MVC, WebAPI and SignalR using the same Ninject kernel: https://drive.google.com/file/d/0B52OsuSSsroNX0I5aWFFb1VrRm8/edit?usp=sharing

That example web app, contains a single page that shows the AppDomain and GetHashCode of an object that is supposed to be unique across the three frameworks, giving a result similar to:

Dependency Test

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

I hope this helps.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!