将 SignalR 的 ITransportHeartbeat 添加到 Autofac

Posted

技术标签:

【中文标题】将 SignalR 的 ITransportHeartbeat 添加到 Autofac【英文标题】:Add SignalR's ITransportHeartbeat to Autofac 【发布时间】:2020-09-01 04:05:07 【问题描述】:

我正在尝试使用 Autofac 为我的 ASP.NET MVC 5 应用程序创建一个 ITransportHeartbeat 接口实例,以跟踪所有连接的用户。我使用ITransportHeartbeat 接口来确定用户的连接是否仍处于活动状态。为此,我需要使用 Autofac 为应用程序创建一个 SignalR 集线器实例。

挑战:当我运行应用程序时,它永远不会遇到 SignalR 集线器中被覆盖的 OnConnected()OnReconnected()OnDisconnected()。但是,客户端的hub.start() 被命中,我在页面加载时看到Hub Started 消息:

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

如果我向集线器添加一个无参数构造函数,它确实会命中它们,但是ITransportHeartbeat 接口为空,这破坏了将接口注入集线器的意义。

我参考了以下内容寻求帮助:

https://***.com/a/49214891/177416 https://autofaccn.readthedocs.io/en/latest/integration/signalr.html https://***.com/a/36476106/177416 https://***.com/a/21126852/177416

这里是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);
    

这是其他集线器的派生集线器:

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...
    

这是从基础集线器继承的集线器之一:

[HubName("MyHub")]
public class MyHub : MonitoringHubBase

    public MyHub(ITransportHeartbeat heartbeat) : base(heartbeat)
    
    

    public MyHub()
       
    

【问题讨论】:

【参考方案1】:

找到了解决办法!从集线器中删除了无参数 c'tor 并将Startup.cs 修改为此;希望这可以帮助下一个为此苦苦挣扎的人:

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

在本文的帮助下:https://kwilson.io/blog/get-your-web-api-playing-nicely-with-signalr-on-owin-with-autofac/

【讨论】:

以上是关于将 SignalR 的 ITransportHeartbeat 添加到 Autofac的主要内容,如果未能解决你的问题,请参考以下文章

.net core 3.0 Signalr - 05 使用jwt将用户跟signalr关联

.net core 3.0 Signalr - 05 使用jwt将用户跟signalr关联

SignalR 学习记录-简介

将 Redis 与 SignalR 一起使用

将 REST Web API 应用程序与 SignalR 集成?

Signalr 将 IHubContext 转换为实际的 Hub