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:
- https://stackoverflow.com/a/49214891/177416
- https://autofaccn.readthedocs.io/en/latest/integration/signalr.html
- https://stackoverflow.com/a/36476106/177416
- https://stackoverflow.com/a/21126852/177416
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()
{
}
}