Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

use dependency injection in Signalr 2.0 self-host?

With SignalR 2.0 in a self-hosted application, from these instructions you have something like this:

class Startup
{
   public void Configuration(IAppBuilder app)
   {
       app.MapSignalR(new HubConfiguration { Resolver = ... });
   }
}
class Program
{
    static void Main(string[] args)
    {
        using (WebApp.Start("http://localhost:8080")) // constructs Startup instance internally
        {
            Console.WriteLine("Server running on {0}", url);
            Console.ReadLine();
        }
    }
}

You will notice that the Startup class instance is created with some behind-the-scenes magic. I can't figure out how to fill in dependencies on it. Is there some way to override the construction of the Startup class so that I can inject dependencies into it?

like image 829
Brannon Avatar asked Jan 27 '14 18:01

Brannon


1 Answers

Instead of replacing the IAppActivator, you can simply register Startup's constructor arguments with Katana's ServiceProvider.

The default IAppActivator will resolve any services matching the Startup constructor's argument types for you. The only downside is you can't use WebApp.Start, since that doesn't expose the ServiceProvider:

public class MyService : IMyService
{
    private readonly IMyOtherService _myOtherService;

    // Services will be recursively resolved by Katana's ServiceProvider
    public MyService(IMyOtherService myOtherService)
    {
        _myOtherService = myOtherService;
    }

    // Implementation
}

public class Startup
{
   private readonly IMyService _myService;

   // Startup must have exactly one constructor.
   public Startup(IMyService myService)
   {
       _myService = myService
   }

   public void Configuration(IAppBuilder app)
   {
       app.MapSignalR(new HubConfiguration { Resolver = ... });
   }
}

using System;
using Microsoft.Owin.Hosting;
using Microsoft.Owin.Hosting.Services;
using Microsoft.Owin.Hosting.Starter;

public class Program
{
    static void Main(string[] args)
    {
        var url = "http://localhost:8080";

        var services = (ServiceProvider)ServicesFactory.Create();
        var options = new StartOptions(url);

        services.Add<IMyOtherService, MyOtherService>();
        services.Add<IMyService, MyService>();

        var starter = services.GetService<IHostingStarter>();

        using (starter.Start(options)) // constructs Startup instance internally
        {
            Console.WriteLine("Server running on {0}", url);
            Console.ReadLine();
        }
    }
}

I copied the default implementation of WebApp.Start into Program.Main, but instead of calling IHostingStarter.Start immediately, I add custom services first: http://katanaproject.codeplex.com/SourceControl/changeset/view/c726b87e90c05677a256ca1821bac481f402d6bd#src/Microsoft.Owin.Hosting/WebApp.cs

There are a bunch of other overloads for ServiceProvider.Add if you need them: http://msdn.microsoft.com/en-us/library/microsoft.owin.hosting.services.serviceprovider(v=vs.111).aspx

This should be much simpler than replacing Katana's IAppActivator using StartOptions.Settings like I suggest in my previous answer.

I am leaving my previous answer up, however, as it does explain in more detail how the Startup class is constructed and how to replace default service implementations using the Settings dictionary.

like image 122
halter73 Avatar answered Oct 23 '22 09:10

halter73