.NET Core C#系列之SignalR全链路websocket发布订阅B2B模式

问题背景:我有两个系统A和B,WEB客户端调用系统A的API接口,B系统和硬件进行socket连接交互。A系统也可以直接调用B系统的api接口。但是B不能调用A系统。

A系统是主系统,

B系统是子服务,硬件和B系统是一对一socket消息推送。

此时我想让硬件推送的设备状态由B系统再推送到A系统。

通过 B系统做为一个桥梁,最终实现 A<--B<--硬件。

此时你会说,直接用消息队列mq不就可以了吗?是的,这个队列可以解决目前的问题,但是对于小团队项目,研发人员不多的情况下。每增加一个中间件或者应用软件,都会增加维护的成本。况且,AB两个系统都增加了SignalR服务端。所以,用现有的基础设施,增加自己想要的功能,让一个工具发挥到极致,才是用兵之道。

画个图说明一下:

3f6eb43b5b608318cd1092b925993246.png

实现代码很简单:

系统AB的SignalR的服务端写法都是一样的,详细见微软文档:

https://learn.microsoft.com/zh-cn/aspnet/core/tutorials/signalr?view=aspnetcore-7.0&tabs=visual-studio

我写了一个简单的SignalR的服务端demo如下:

using Microsoft.AspNetCore.SignalR;


namespace SignalRChat.Hubs
{
    public class ChatHub : Hub
    {
    /// <summary>
    /// 失去连接
    /// </summary>
    /// <param name="exception"></param>
    /// <returns></returns>
    public override Task OnDisconnectedAsync(Exception exception)
    {       
        return base.OnDisconnectedAsync(exception);
    }
    /// <summary>
    /// 连接上
    /// </summary>
    /// <returns></returns>
    public override Task OnConnectedAsync()
    {
        return base.OnConnectedAsync();
    }
    /// <summary>
    /// 发送消息
    /// </summary>
    /// <returns></returns>
    public async Task SendMessage(string user, string message)
     {
         await Clients.All.SendAsync("ReceiveMessage", user, message);
     }
    }
}

必须将 SignalR 服务器配置为将 SignalR 请求传递给 SignalR。将以下突出显示的代码添加到 Program.cs 文件。

using SignalRChat.Hubs;


var builder = WebApplication.CreateBuilder(args);


// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddSignalR();


var app = builder.Build();


// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}


app.UseHttpsRedirection();
app.UseStaticFiles();


app.UseRouting();


app.UseAuthorization();


app.MapRazorPages();
app.MapHub<ChatHub>("/chatHub");


app.Run();

服务端大致就是这个写法,不写太具体了。具体的去参看微软文档吧。

👆上面核心的代码就这3行:

using SignalRChat.Hubs;
builder.Services.AddSignalR();
app.MapHub<ChatHub>("/chatHub");

重点来了,我在微软文档没有找到 netcore api 的SignalR 客户端的demo。只找到了 wpf 、winfom 这样的客户端demo。很显然,这需要做相关改造工作。

我要实现一个 netcore api 的SignalR 客户端的demo。

在Program.cs里面写上如下代码:

当然,你也可以抽离出来。

//连接的时候传递参数Param
            var param = new Dictionary<string, string> {
                { "SubscribeSIP", "1" }
            };
            HubConnection connection = new HubConnectionBuilder()
              .WithUrl("你的服务端连接地址")
              , option => { option.Headers = param; })
              .WithAutomaticReconnect(new RandomRetryPolicy())
              .Build();
              //连接的函数
             ConnectWithRetryAsync(connection, CancellationToken.None);      
             //监听服务端推来的消息
            connection.On<string, string>("Notification", async (user, message) =>
            {
                await clientCallBack.Notification(user, message);
                Console.WriteLine(message);
            });
            //调用服务端的 SendMessage函数
            connection.InvokeAsync("SendMessage","autoChang","hello");
/// <summary>
        /// SignalR Cline首次连接,如SignalR Server不在线会持续连接
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public static async Task<bool> ConnectWithRetryAsync(HubConnection connection, CancellationToken token)
        {
            while (true)
            {
                try
                {
                    Console.WriteLine(" SignalR 首次连接中....");
                    await connection.StartAsync(token);
                    if (connection.State == HubConnectionState.Connected)
                    {
                        Console.WriteLine(" SignalR 首次连接成功....");
                        return true;
                    }
                }
                catch when (token.IsCancellationRequested)
                {
                    return false;
                }
                catch
                {
                    if (connection.State == HubConnectionState.Disconnected)
                    {
                        Console.WriteLine("SignalR 首次连接失败,5秒之后重试");
                        await Task.Delay(5000);
                    }
                }
            }
        }
/// <summary>
    /// 连接成功之后,再次断开的重试连接策略
    /// </summary>
    public class RandomRetryPolicy : IRetryPolicy
    {
        private readonly Random _random = new Random();


        public TimeSpan? NextRetryDelay(RetryContext retryContext)
        {
            var time = _random.NextDouble() * 10;
            Console.WriteLine($" SignalR 在{time}秒后重试连接");
            return TimeSpan.FromSeconds(time);
        }
    }

客户端可以携带参数,

var param = new Dictionary<string, string> {
                { "SubscribeSIP", "1" }
            };

服务端收到参数后,进行解析

/// <summary>
    /// 连接上
    /// </summary>
    /// <returns></returns>
    public override Task OnConnectedAsync()
    {
        var isSubscribeSIP = Context.GetHttpContext().Request.Headers["SubscribeSIP"].ObjToInt() == 1 ? true : false;
        var identifier = Context.UserIdentifier;
        _logger.LogInformation($"用户:{identifier}->连接服务成功,是否订阅SIP设备信息:{isSubscribeSIP}");        
        return base.OnConnectedAsync();
    }

当消息推送的时候,可以指定给订阅者推送相关信息:

/// <summary>
    /// 消息通知,给订阅sip设备者,发送设备信息
    /// </summary>
    /// <param name="deviceInfoDto"></param>
    public async void AddMessageToSipDeviceInfo(WSsipDeviceInfoDto deviceInfoDto)
    {
        var clients = SignalRClientList.Where(d => d.IsSubscribeSIP).ToList();
        if (clients == null) return;
        foreach (var client in clients)
        {
            deviceInfoDto.SignalrUserId = client.Signalr_userId;
            client.ConnectionIds.ForEach(x => _hubContext.Clients.Client(x).SendAsync(SignalREvent.SipDeviceInfo, deviceInfoDto));
        }
    }

以上是技术要领,学会思想。实践很快的。更多的建议是去看微软文档,文档写的很明白。无非就是wpf  winfom 客户端 如何转换成 netcore api的客户端的思想。更多是生命周期的注册,如何实例化等。

好了,今天的分享就到这里。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值