2

I'm trying to use Autofac to have one instance of the ITransportHeartbeat interface for my ASP.NET MVC 5 app to track all connected users. I use the ITransportHeartbeat interface to determine if a user's connection is still active. To do this, I need to have one instance of the SignalR hub for the app by using Autofac.

The challenge: when I run the app, it never hits the overridden OnConnected(), OnReconnected(), or OnDisconnected() in the SignalR hub. However, the client's hub.start() is hit and I see the Hub Started message when the page loads:

$.connection.hub.start().done(function () {
    console.log("Hub Started");
});

If I add a parameterless constructor to the hub, it does hit them, but then the ITransportHeartbeat interface is null and that defeats the point of injecting the interface into the hub.

I've referenced the following for help:

Here is Startup.cs:

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);

        var builder = new ContainerBuilder();
        var config = GlobalConfiguration.Configuration;

        builder.RegisterControllers(typeof(MvcApplication).Assembly)
            .InstancePerRequest();
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly())
            .InstancePerRequest();

        var signalRConfig = new HubConfiguration();
        builder.RegisterType<MonitoringHubBase>().ExternallyOwned();

        builder.RegisterType<Autofac.Integration.SignalR.AutofacDependencyResolver>()
            .As<Microsoft.AspNet.SignalR.IDependencyResolver>()
            .SingleInstance();
        builder.Register(context => 
            context.Resolve<Microsoft.AspNet.SignalR.IDependencyResolver>()
            .Resolve<IConnectionManager>()
            .GetHubContext<MonitoringHubBase, IMonitoringHubBase>())
            .ExternallyOwned();
        builder.RegisterType<Microsoft.AspNet.SignalR.Transports.TransportHeartbeat>()
            .As<Microsoft.AspNet.SignalR.Transports.ITransportHeartbeat>()
            .SingleInstance();

        var container = builder.Build();
        DependencyResolver.SetResolver(
            new Autofac.Integration.Mvc.AutofacDependencyResolver(container));

        signalRConfig.Resolver = container
            .Resolve<Microsoft.AspNet.SignalR.IDependencyResolver>();

        app.UseAutofacMiddleware(container);
        app.MapSignalR("/signalr", signalRConfig);

        config.DependencyResolver = 
            new AutofacWebApiDependencyResolver((IContainer)container);

        AreaRegistration.RegisterAllAreas();
        GlobalConfiguration.Configure(WebApiConfig.Register);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

Here is the hub from which the other hubs derive:

public interface IMonitoringHubBase
{
    Task OnConnected();
    Task OnReconnected();
    Task OnDisconnected(bool stopCalled);
}

public abstract class MonitoringHubBase : Hub<IMonitoringHubBase>
{
    private ITransportHeartbeat Heartbeat { get; }

    public MonitoringHubBase(ITransportHeartbeat heartbeat)
    {
        Heartbeat = heartbeat;
    }

    public MonitoringHubBase()
    {
    }

    public override async Task OnConnected()
    {
        // Add connection to db...
    }

    public override async Task OnReconnected()
    {
        // Ensure connection is on db...
    }

    public override async Task OnDisconnected(bool stopCalled)
    {
        // Remove connection from db...
    }

    public async Task SomeMethod(int id)
    {
        // Heartbeat object used here...
    }
}

And here's one of the hubs that inherits from the base hub:

[HubName("MyHub")]
public class MyHub : MonitoringHubBase
{
    public MyHub(ITransportHeartbeat heartbeat) : base(heartbeat)
    {
    }

    public MyHub()
    {   
    }
}
Alex
  • 34,699
  • 13
  • 75
  • 158

1 Answers1

2

Found a solution! Removed the parameterless c'tor from the hub and modified Startup.cs to this; hope this helps the next person struggling with this:

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);

        var builder = new ContainerBuilder();
        var config = new HttpConfiguration();

        builder.RegisterHubs(Assembly.GetExecutingAssembly());
        builder.RegisterControllers(typeof(MvcApplication).Assembly)
            .InstancePerRequest();
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly())
            .InstancePerRequest();
        builder.RegisterType<Microsoft.AspNet.SignalR.Transports.TransportHeartbeat>()
            .As<Microsoft.AspNet.SignalR.Transports.ITransportHeartbeat>()
            .SingleInstance();
        builder.RegisterType<Autofac.Integration.SignalR.AutofacDependencyResolver>()
            .As<Microsoft.AspNet.SignalR.IDependencyResolver>()
            .SingleInstance();

        var container = builder.Build();

        var signalRConfig = new HubConfiguration();
        signalRConfig.Resolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(container);

        app.UseAutofacMiddleware(container);

        DependencyResolver.SetResolver(new Autofac.Integration.Mvc.AutofacDependencyResolver(container));

        app.Map("/signalr", map =>
        {
            map.UseAutofacMiddleware(container);

            var hubConfiguration = new HubConfiguration
            {
                Resolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(container),
            };

            map.RunSignalR(hubConfiguration);
        });

        config.DependencyResolver = new AutofacWebApiDependencyResolver((IContainer)container);

        AreaRegistration.RegisterAllAreas();
        GlobalConfiguration.Configure(WebApiConfig.Register);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

With help from this article: https://kwilson.io/blog/get-your-web-api-playing-nicely-with-signalr-on-owin-with-autofac/

Alex
  • 34,699
  • 13
  • 75
  • 158