gpt4 book ai didi

基于SqlSugar的开发框架循序渐进介绍(25)--基于SignalR实现多端的消息通讯

转载 作者:我是一只小鸟 更新时间:2023-04-07 22:31:31 30 4
gpt4 key购买 nike

基于ASP.NET Core SignalR 可以实现客户端和服务器之间进行即时通信。本篇随笔介绍一些SignalR的基础知识,以及结合对SqlSugar的开发框架的支持,实现SignalR的多端处理整合,从而实现Winform客户端,基于Vue3+ElementPlus的BS端整合,后面也可以实现对移动端的SignalR的整合通讯.

适合 SignalR 的应用场景:

  • 需要从服务器进行高频率更新的应用。 示例包括游戏、社交网络、投票、拍卖、地图和 GPS 应用。
  • 仪表板和监视应用。
  • 协作应用。 协作应用的示例包括白板应用和团队会议软件。
  • 需要通知的应用。 社交网络、电子邮件、聊天、游戏、旅行警报和很多其他应用都需使用通知。

SignalR 自动选择服务器和客户端能力范围内的最佳传输方法,如 WebSockets 、Server-Sent Events、长轮询。Hub 是一种高级管道,允许客户端和服务器相互调用方法。 SignalR 自动处理跨计算机边界的调度,并允许客户端调用服务器上的方法,反之亦然。SignalR 提供两个内置中心协议:基于 JSON 的文本协议和基于 MessagePack 的二进制协议.

客户端负责通过  HubConnection  对象建立到服务器终结点的连接。 Hub 连接在每个目标平台中表示:

  • .NET 客户端 : Microsoft.AspNetCore.SignalR.Client.HubConnection
  • JavaScript 客户端 : @microsoft/signalr.HubConnection
  • Java 客户端 : com.microsoft.signalr.HubConnection

当中心连接实例成功启动后,消息可以自由地双向流动。 用户可以自由地将通知发送到服务器,以及从服务器接收通知。 客户端是任何已连接的应用程序,例如(但不限于)Web 浏览器、移动应用或桌面应用.

1、SignalR服务端

在.net core的Web API上,我们首先需要注册SignalR的服务,然后创建对应的Hub进行使用。一般可以在启动类中添加如下代码即可.

                        builder.Services.AddSignalR();
                        
                          //
                        
                        
                           即时通讯
                        
                        
                          
app.UseEndpoints(endpoints 
                        
                        =>
                        
                          
{
    
                        
                        
                          //
                        
                        
                           注册集线器
                        
                        
    endpoints.MapHub<OnlineUserHub>(
                        
                          "
                        
                        
                          /hubs/onlineUser
                        
                        
                          "
                        
                        
                          );
});
                        
                      

定义集线器只需要继承  Hub  或  Hub<TStrongType>  泛型基类即可.

                        
                          public
                        
                        
                          class
                        
                        
                           ChatHub : Hub
{
    
                        
                        
                          public
                        
                        
                          async
                        
                         Task SendMessage(
                        
                          string
                        
                         user, 
                        
                          string
                        
                        
                           message)
        
                        
                        => 
                        
                          await
                        
                         Clients.All.SendAsync(
                        
                          "
                        
                        
                          ReceiveMessage
                        
                        
                          "
                        
                        
                          , user, message);
}
                        
                      

泛型强类型方法是使用  Hub<T> 的强类型 Hub 类。在以下示例中  ChatHub  ,客户端方法已提取到名为 的  IChatClient 接口中:

                        
                          public
                        
                        
                          interface
                        
                        
                           IChatClient
{
    Task 
                            ReceiveMessage  
                          (
                        
                        
                          string
                        
                         user, 
                        
                          string
                        
                        
                           message);
}
                        
                      

此接口可用于将前面的  ChatHub  示例重构为强类型:

                        
                          public
                        
                        
                          class
                        
                         ChatHub : Hub<IChatClient>
                        
                          
{
    
                        
                        
                          public
                        
                        
                          async
                        
                         Task 
                        
                           SendMessage 
                        
                        (
                        
                          string
                        
                         user, 
                        
                          string
                        
                        
                           message)
        
                        
                        => 
                        
                          await
                        
                        
                           Clients.All.
                            ReceiveMessage  
                          (user, message);

    
                        
                        
                          public
                        
                        
                          async
                        
                         Task SendMessageToCaller(
                        
                          string
                        
                         user, 
                        
                          string
                        
                        
                           message)
        
                        
                        => 
                        
                          await
                        
                        
                           Clients.Caller.
                            ReceiveMessage  
                          (user, message);

    
                        
                        
                          public
                        
                        
                          async
                        
                         Task SendMessageToGroup(
                        
                          string
                        
                         user, 
                        
                          string
                        
                        
                           message)
        
                        
                        => 
                        
                          await
                        
                         Clients.Group(
                        
                          "
                        
                        
                          SignalR Users
                        
                        
                          "
                        
                        
                          ).
                            ReceiveMessage  
                          (user, message);
}
                        
                      

这样Clients的对象都具备了接口定义的  ReceiveMessage 方法调用,实际这个就是客户端的方法.

使用  Hub<IChatClient>  可以对客户端方法进行编译时检查。 这可以防止使用字符串引起的问题,因为  Hub<T>  只能提供对 接口中定义的方法的访问权限。 使用强类型  Hub<T>  会禁止使用  SendAsync .

Hub服务端中心 。

                        
                          public
                        
                        
                          interface
                        
                        
                           IClient
{
    Task
                        
                        <
                        
                          string
                        
                        >
                        
                            GetMessage  
                          ();
}


                        
                        
                          public
                        
                        
                          class
                        
                         ChatHub : Hub<IClient>
                        
                          
{
    
                        
                        
                          public
                        
                        
                          async
                        
                         Task<
                        
                          string
                        
                        > WaitForMessage(
                        
                          string
                        
                        
                           connectionId)
    {
        
                        
                        
                          string
                        
                         message = 
                        
                          await
                        
                        
                           Clients.Client(connectionId).
                            GetMessage  
                          ();
        
                        
                        
                          return
                        
                        
                           message;
    }
}
                        
                      

.NET 客户端

客户端在其  .On(...)  处理程序中返回结果,如下所示:

                        hubConnection.On(
                        
                          "
                        
                        
                           GetMessage 
                        
                        
                          "
                        
                        , 
                        
                          async
                        
                         () =>
                        
                          
{
    Console.WriteLine(
                        
                        
                          "
                        
                        
                          Enter message:
                        
                        
                          "
                        
                        
                          );
    
                        
                        
                          var
                        
                         message = 
                        
                          await
                        
                        
                           Console.In.ReadLineAsync();
    
                        
                        
                          return
                        
                        
                           message;
});
                        
                      

Typescript 客户端

                        hubConnection.on("
                        
                           GetMessage 
                        
                        ", async () =>
                        
                           {
    let promise 
                        
                        = 
                        
                          new
                        
                         Promise((resolve, reject) =>
                        
                           {
        setTimeout(() 
                        
                        =>
                        
                           {
            resolve(
                        
                        "message"
                        
                          );
        }, 
                        
                        100
                        
                          );
    });
    
                        
                        
                          return
                        
                        
                           promise;
});
                        
                      

Java 客户端

                        hubConnection.onWithResult(
                        
                          "
                        
                        
                          GetMessage
                        
                        
                          "
                        
                        , () ->
                        
                           {
    
                        
                        
                          return
                        
                         Single.just(
                        
                          "
                        
                        
                          message
                        
                        
                          "
                        
                        
                          );
});
                        
                      

在框架中整合SignalR的Hub的时候,我们定义一个接口IOnlineUserHub,以便强类型对客户端接口方法的调用,减少错误.

然后在定义一个Hub的对象类,如下所示 .

                        
                          public
                        
                        
                          class
                        
                         OnlineUserHub : Hub<IOnlineUserHub>
                        
                          
{
        
                        
                        
                          private
                        
                        
                          readonly
                        
                        
                           IOnlineUserService _onlineUserService;
        
                        
                        
                          private
                        
                        
                          readonly
                        
                        
                           IHubContext<OnlineUserHub, OnlineUserHub> 
                        
                        
                           _chatHubContext;

        
                        
                        
                          public
                        
                        
                           OnlineUserHub(IOnlineUserService onlineUserService,
            IHubContext
                        
                        <OnlineUserHub, IOnlineUserHub>
                        
                           onlineUserHubContext)
        {
            _onlineUserService 
                        
                        =
                        
                           onlineUserService;
            _chatHubContext 
                        
                        =
                        
                           onlineUserHubContext;
        }
}
                        
                      

对象Hub<T>本身可以通过注入一个 IHubContext<OnlineUserHub, OnlineUserHub> 接口来获得对它的调用,如上面构造函数所示。该Hub一般还需要重写连接和断开的处理操作,如下代码所示.

 如对于用户的SignalR连接发起,我们需要判断用户的令牌及相关身份信息,如果成功,则通过给客户端提供在线用户列表.

                        
                          ///
                        
                        
                          <summary>
                        
                        
                          ///
                        
                        
                           连接后处理
        
                        
                        
                          ///
                        
                        
                          </summary>
                        
                        
                          ///
                        
                        
                          <returns></returns>
                        
                        
                          public
                        
                        
                          override
                        
                        
                          async
                        
                        
                           Task OnConnectedAsync()
        {
            
                        
                        
                          var
                        
                         httpContext =
                        
                           Context.GetHttpContext();

            
                        
                        
                          var
                        
                         token = httpContext!.Request.Query[
                        
                          "
                        
                        
                          access_token
                        
                        
                          "
                        
                        
                          ];
            
                        
                        
                          if
                        
                         (
                        
                          string
                        
                        .IsNullOrWhiteSpace(token)) 
                        
                          return
                        
                        
                          ;

            ................

            
                        
                        
                          //
                        
                        
                          向客户端提供在线用户信息
                        
                        
                          await
                        
                         _chatHubContext.Clients.Groups(groupName).OnlineUserList(
                        
                          new
                        
                        
                           OnlineUserList
            {
                ConnectionId 
                        
                        =
                        
                           user.ConnectionId,
                RealName 
                        
                        = user.RealName + $
                        
                          "
                        
                        
                          ({client.UA.Family})
                        
                        
                          "
                        
                        , 
                        
                          //
                        
                        
                          加上实际终端
                        
                        
                Online = 
                        
                          true
                        
                        
                          ,
                UserList 
                        
                        =
                        
                           userList.Items.ToList()
            });

            
                        
                        
                          //
                        
                        
                          更新在线用户缓存
                        
                        
                          await
                        
                        
                           RedisHelper.SetAsync(CacheConst.KeyOnlineUser, userList.Items.ToList());
        }
                        
                      

上下文对象

类  Hub  包含一个  Context  属性,该属性包含以下属性以及有关连接的信息:

属性 说明
ConnectionId 获取连接的唯一 ID(由 SignalR 分配)。 每个连接都有一个连接 ID。
UserIdentifier 获取 用户标识符 。 默认情况下,SignalR 使用与连接关联的  ClaimsPrincipal  中的  ClaimTypes.NameIdentifier  作为用户标识符。
User 获取与当前用户关联的  ClaimsPrincipal 。
Items 获取可用于在此连接范围内共享数据的键/值集合。 数据可以存储在此集合中,会在不同的中心方法调用间为连接持久保存。
Features 获取连接上可用的功能的集合。 目前,在大多数情况下不需要此集合,因此未对其进行详细记录。
ConnectionAborted 获取一个  CancellationToken ,它会在连接中止时发出通知。

Hub.Context  还包含以下方法:

方法 说明
GetHttpContext 返回  HttpContext  连接的 ;如果连接未与 HTTP 请求关联,  null  则返回 。 对于 HTTP 连接,请使用此方法获取 HTTP 标头和查询字符串等信息。
Abort 中止连接。

客户端对象

类  Hub  包含一个  Clients  属性,该属性包含以下用于服务器和客户端之间通信的属性:

属性 说明
All 对所有连接的客户端调用方法
Caller 对调用了中心方法的客户端调用方法
Others 对所有连接的客户端调用方法(调用了方法的客户端除外)

Hub.Clients  还包含以下方法:

方法 说明
AllExcept 对所有连接的客户端调用方法(指定连接除外)
Client 对连接的一个特定客户端调用方法
Clients 对连接的多个特定客户端调用方法
Group 对指定组中的所有连接调用方法
GroupExcept 对指定组中的所有连接调用方法(指定连接除外)
Groups 对多个连接组调用方法
OthersInGroup 对一个连接组调用方法(不包括调用了中心方法的客户端)
User 对与一个特定用户关联的所有连接调用方法
Users 对与多个指定用户关联的所有连接调用方法

这样我们Hub里面定义的方法,就可以利用这些对象来处理了.

                        
                          ///
                        
                        
                          <summary>
                        
                        
                          ///
                        
                        
                           前端调用发送方法(发送信息给所有人)
        
                        
                        
                          ///
                        
                        
                          </summary>
                        
                        
                          ///
                        
                        
                          <param name="message"></param>
                        
                        
                          ///
                        
                        
                          <returns></returns>
                        
                        
                          public
                        
                        
                          async
                        
                        
                           Task ClientsSendMessagetoAll(MessageInput message)
        {
            
                        
                        
                          await
                        
                        
                           _chatHubContext.
                            Clients.All  
                          .ReceiveMessage(message);
        }

        
                        
                        
                          ///
                        
                        
                          <summary>
                        
                        
                          ///
                        
                        
                           前端调用发送方法(发送消息给除了发送人的其他人)
        
                        
                        
                          ///
                        
                        
                          </summary>
                        
                        
                          ///
                        
                        
                          <param name="message"></param>
                        
                        
                          ///
                        
                        
                          <returns></returns>
                        
                        
                          public
                        
                        
                          async
                        
                        
                           Task ClientsSendMessagetoOther(MessageInput message)
        {
            
                        
                        
                          var
                        
                         onlineuserlist = RedisHelper.Get<List<OnlineUserInfo>>
                        
                          (CacheConst.KeyOnlineUser);

            
                        
                        
                          var
                        
                         user = onlineuserlist.Where(x => x.UserId ==
                        
                           message.UserId).ToList();
            
                        
                        
                          if
                        
                         (user != 
                        
                          null
                        
                        
                          )
            {
                
                        
                        
                          await
                        
                         _chatHubContext.
                        
                           Clients.AllExcept 
                        
                        (user[
                        
                          0
                        
                        
                          ].ConnectionId).ReceiveMessage(message);
            }
        }
                        
                      

基于IHubContext的接口,我们也可以定义一个常规的接口函数,用于在各个服务类中调用Hub处理函数 。

                        
                          ///
                        
                        
                          <summary>
                        
                        
                          ///
                        
                        
                           封装的SignalR的常规处理实现
    
                        
                        
                          ///
                        
                        
                          </summary>
                        
                        
                          public
                        
                        
                          class
                        
                         HubContextService : BaseService, IHubContextService
                      

这样在服务端,注册服务后,可以使用这个自定义服务类的处理逻辑.

                        
                          //
                        
                        
                          使用HubContextService服务接口
                        
                        
builder.Services.AddSingleton<IHubContextService, 
                        
                           HubContextService 
                        
                        >();
                      

可以供一些特殊的控制器来使用Hub服务接口,如登录后台的时候,实现强制多端下线的处理方式.

                        
                          ///
                        
                        
                          <summary>
                        
                        
                          ///
                        
                        
                           登录获取令牌授权的处理
    
                        
                        
                          ///
                        
                        
                          </summary>
                        
                        
    [Route(
                        
                          "
                        
                        
                          api/[controller]
                        
                        
                          "
                        
                        
                          )]
    [ApiController]
    
                        
                        
                          public
                        
                        
                          class
                        
                        
                           LoginController : ControllerBase
    {
        
                        
                        
                          private
                        
                        
                          readonly
                        
                         IHubContextService _hubContextService;
                      
                        
                          ///
                        
                        
                          <summary>
                        
                        
                          ///
                        
                        
                           登录授权处理
        
                        
                        
                          ///
                        
                        
                          </summary>
                        
                        
                          ///
                        
                        
                          <returns></returns>
                        
                        
                                  [AllowAnonymous]
        [HttpPost]
        [Route(
                        
                        
                          "
                        
                        
                          authenticate
                        
                        
                          "
                        
                        
                          )]
        
                        
                        
                          public
                        
                        
                          async
                        
                         Task<AuthenticateResultDto>
                        
                           Authenticate(LoginDto dto)
        {
            
                        
                        
                          var
                        
                         authResult = 
                        
                          new
                        
                        
                           AuthenticateResultDto();
            ................

            
                        
                        
                          var
                        
                         loginResult = 
                        
                          await
                        
                        
                          this
                        
                        
                          ._userService.VerifyUser(dto.LoginName, dto.Password, ip);
            
                        
                        
                          if
                        
                         (loginResult != 
                        
                          null
                        
                         && loginResult.UserInfo != 
                        
                          null
                        
                        
                          )
            {
                
                        
                        
                          var
                        
                         userInfo =
                        
                           loginResult.UserInfo;

                ...............

                
                        
                        
                          //
                        
                        
                          单用户登录
                        
                        
                          await
                        
                        
                           this 
                        
                        
                            ._hubContextService.SignleLogin  
                          (userInfo.Id.ToString());
            }
            
                        
                        
                          else
                        
                        
                          
            {
                authResult.Error 
                        
                        = loginResult?
                        
                          .ErrorMessage;
            }


            
                        
                        
                          return
                        
                        
                           authResult;
        }
                        
                      

  。

2、SignalR客户端

.net客户端在对接Hub中心服务端的时候,需要添加Microsoft.AspNetCore.SignalR.Client的引用.

                        Install-Package Microsoft.AspNetCore.SignalR.Client
                      

若要建立连接,请创建  HubConnectionBuilder  并调用  Build 。 在建立连接期间,可以配置中心 URL、协议、传输类型、日志级别、标头和其他选项。 可通过将任何  HubConnectionBuilder  方法插入  Build  中来配置任何必需选项。 使用  StartAsync  启动连接.

                        
                          using
                        
                        
                           System;

                        
                        
                          using
                        
                        
                           System.Threading.Tasks;

                        
                        
                          using
                        
                        
                           System.Windows;

                        
                        
                          using
                        
                        
                           Microsoft.AspNetCore.SignalR.Client;


                        
                        
                          namespace
                        
                        
                           SignalRChatClient
{
    
                        
                        
                          public
                        
                        
                          partial
                        
                        
                          class
                        
                        
                           MainWindow : Window
    {
        HubConnection connection;
        
                        
                        
                          public
                        
                        
                           MainWindow()
        {
            InitializeComponent();

            connection 
                        
                        = 
                        
                          new
                        
                        
                           HubConnectionBuilder()
                .WithUrl(
                        
                        
                          "
                        
                        
                          http://localhost:53353/ChatHub
                        
                        
                          "
                        
                        
                          )
                .Build();

            connection.Closed 
                        
                        += 
                        
                          async
                        
                         (error) =>
                        
                          
            {
                
                        
                        
                          await
                        
                         Task.Delay(
                        
                          new
                        
                         Random().Next(
                        
                          0
                        
                        ,
                        
                          5
                        
                        ) * 
                        
                          1000
                        
                        
                          );
                
                        
                        
                          await
                        
                        
                           connection.StartAsync();
            };
        }

        
                        
                        
                          private
                        
                        
                          async
                        
                        
                          void
                        
                         connectButton_Click(
                        
                          object
                        
                        
                           sender, RoutedEventArgs e)
        {
            connection.On
                        
                        <
                        
                          string
                        
                        , 
                        
                          string
                        
                        >(
                        
                          "
                        
                        
                          ReceiveMessage
                        
                        
                          "
                        
                        , (user, message) =>
                        
                          
            {
                
                        
                        
                          this
                        
                        .Dispatcher.Invoke(() =>
                        
                          
                {
                   
                        
                        
                          var
                        
                         newMessage = $
                        
                          "
                        
                        
                          {user}: {message}
                        
                        
                          "
                        
                        
                          ;
                   messagesList.Items.Add(newMessage);
                });
            });

            
                        
                        
                          try
                        
                        
                          
            {
                
                        
                        
                          await
                        
                        
                           connection.StartAsync();
                messagesList.Items.Add(
                        
                        
                          "
                        
                        
                          Connection started
                        
                        
                          "
                        
                        
                          );
                connectButton.IsEnabled 
                        
                        = 
                        
                          false
                        
                        
                          ;
                sendButton.IsEnabled 
                        
                        = 
                        
                          true
                        
                        
                          ;
            }
            
                        
                        
                          catch
                        
                        
                           (Exception ex)
            {
                messagesList.Items.Add(ex.Message);
            }
        }

        
                        
                        
                          private
                        
                        
                          async
                        
                        
                          void
                        
                         sendButton_Click(
                        
                          object
                        
                        
                           sender, RoutedEventArgs e)
        {
            
                        
                        
                          try
                        
                        
                          
            {
                
                        
                        
                          await
                        
                         connection.InvokeAsync(
                        
                          "
                        
                        
                          SendMessage
                        
                        
                          "
                        
                        
                          , 
                    userTextBox.Text, messageTextBox.Text);
            }
            
                        
                        
                          catch
                        
                        
                           (Exception ex)
            {                
                messagesList.Items.Add(ex.Message);                
            }
        }
    }
}
                        
                      

可以将  HubConnection  配置为对  HubConnectionBuilder  使用  WithAutomaticReconnect  方法来自动重新连接。 默认情况下,它不会自动重新连接.

                        HubConnection connection= 
                        
                          new
                        
                        
                           HubConnectionBuilder()
    .WithUrl(
                        
                        
                          new
                        
                         Uri(
                        
                          "
                        
                        
                          http://127.0.0.1:5000/chathub
                        
                        
                          "
                        
                        
                          ))
    .WithAutomaticReconnect()
    .Build();
                        
                      

在没有任何参数的情况下, WithAutomaticReconnect()  将客户端配置为在每次尝试重新连接之前分别等待 0、2、10 和 30 秒,在四次尝试失败后停止.

为了测试Winform客户端对服务端的连接,我们可以新建一个小案例Demo,来测试信息处理的效果.

创建一个测试的窗体如下所示(实际测试效果).

 创建连接Hub中心的代码如下所示.

                        
                          ///
                        
                        
                          <summary>
                        
                        
                          ///
                        
                        
                           初始化服务连接
        
                        
                        
                          ///
                        
                        
                          </summary>
                        
                        
                          private
                        
                        
                          async
                        
                        
                           Task InitHub()
        {
........
            
                        
                        
                          //
                        
                        
                          创建连接对象,并实现相关事件
                        
                        
                          var
                        
                         url = serverUrl + $
                        
                          "
                        
                        
                          /hubs/onlineUser?access_token={authenticateResultDto.AccessToken}
                        
                        
                          "
                        
                        
                          ;
            hubConnection 
                        
                        = 
                        
                          new
                        
                        
                           HubConnectionBuilder()
               .WithUrl(url)
               .WithAutomaticReconnect(
                        
                        
                          new
                        
                        [] { TimeSpan.Zero, TimeSpan.Zero, TimeSpan.FromSeconds(
                        
                          10
                        
                        ) }) 
                        
                          //
                        
                        
                          自动连接
                        
                        
                                         .Build();

            
                        
                        
                          //
                        
                        
                          接收实时信息
                        
                        
            hubConnection.On<MessageInput>(
                        
                          "
                        
                        
                          ReceiveMessage
                        
                        
                          "
                        
                        
                          , ReceiveMessage);
            
                        
                        
                          //
                        
                        
                          连接上处理在线用户
                        
                        
            hubConnection.On<OnlineUserList>(
                        
                          "
                        
                        
                          OnlineUserList
                        
                        
                          "
                        
                        
                          , OnlineUserList);
            
                        
                        
                          //
                        
                        
                          客户端收到服务关闭消息
                        
                        
            hubConnection.On(
                        
                          "
                        
                        
                          ForceOffline
                        
                        
                          "
                        
                        , 
                        
                          async
                        
                         (ForceOfflineInput data) =>
                        
                          
            {
                
                        
                        
                          await
                        
                        
                           CloseHub();
            });

            
                        
                        
                          try
                        
                        
                          
            {
                
                        
                        
                          //
                        
                        
                          开始连接
                        
                        
                          await
                        
                        
                           hubConnection.StartAsync();

                
                        
                        
                          var
                        
                         content = $
                        
                          "
                        
                        
                          连接到服务器:{serverUrl}
                        
                        
                          "
                        
                        
                          ;
                AddSystemMessage(content);
            }
            
                        
                        
                          catch
                        
                        
                           (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);

                
                        
                        
                          var
                        
                         content = $
                        
                          "
                        
                        
                          服务器连接失败:{ex.Message}
                        
                        
                          "
                        
                        
                          ;
                AddSystemMessage(content);

                InitControlStatus(
                        
                        
                          false
                        
                        
                          );
                
                        
                        
                          return
                        
                        
                          ;
            }
        }
                        
                      

我们可以看到,客户端接收服务端的消息处理,通过下面代码进行处理.

                        
                          //
                        
                        
                          接收实时信息
                        
                        
hubConnection.On<
                        
                          MessageInput
                        
                        >(
                        
                          "
                        
                        
                          ReceiveMessage
                        
                        
                          "
                        
                        
                          , ReceiveMessage);

                        
                        
                          //
                        
                        
                          连接上处理在线用户
                        
                        
hubConnection.On<
                        
                          OnlineUserList
                        
                        >(
                        
                          "
                        
                        
                          OnlineUserList
                        
                        
                          "
                        
                        
                          , OnlineUserList);

                        
                        
                          //
                        
                        
                          客户端收到服务关闭消息
                        
                        
hubConnection.On(
                        
                          "
                        
                        
                           ForceOffline 
                        
                        
                          "
                        
                        , 
                        
                          async
                        
                         (ForceOfflineInput data) =>
                      

对于消息的接收处理,我们把它收到一个本地的集合列表中,然后统一处理即可.

                        
                          ///
                        
                        
                          <summary>
                        
                        
                          ///
                        
                        
                           消息处理

                        
                        
                          ///
                        
                        
                          </summary>
                        
                        
                          ///
                        
                        
                          <param name="data">
                        
                        
                          JSON字符串
                        
                        
                          </param>
                        
                        
                          private
                        
                        
                          void
                        
                        
                           ReceiveMessage(MessageInput data)
{
    
                        
                        
                          if
                        
                         (
                        
                          this
                        
                        .onlineUser != 
                        
                          null
                        
                        
                          )
    {
        
                        
                        
                          var
                        
                         info = 
                        
                          new
                        
                        
                           MessageInfo(data);
         .............
        
                           TryAddMessage 
                          (ownerId, info);
        
                            BindTree  
                          ();
    }
}
                        
                      

发送消息的时候,我们根据指向不同的用户,构造对应的消息体发送(调用服务端Hub接口)即可,调用通过 InvokeAsync 处理,接收相应的对象.

                        
                          private
                        
                        
                          async
                        
                        
                          void
                        
                         BtnSendMessage_Click(
                        
                          object
                        
                        
                           sender, EventArgs e)
{
    
                        
                        
                          if
                        
                         (txtMessage.Text.Length == 
                        
                          0
                        
                        
                          )
        
                        
                        
                          return
                        
                        
                          ;
    
                        
                        
                          var
                        
                         message = 
                        
                          new
                        
                        
                           MessageInput()
    {
        Title 
                        
                        = 
                        
                          "
                        
                        
                          消息
                        
                        
                          "
                        
                        
                          ,
        Message 
                        
                        =
                        
                           txtMessage.Text,
        MessageType 
                        
                        =
                        
                           MessageTypeEnum.Info,
        UserId 
                        
                        = 
                        
                          this
                        
                        
                          .toId,
        UserIds 
                        
                        = 
                        
                          new
                        
                         List<
                        
                          string
                        
                        >
                        
                          ()
    };

    
                        
                        
                          //
                        
                        
                          判断发送人,是单个发送,还是广播发送所有人
                        
                        
                          var
                        
                         methodName = !
                        
                          string
                        
                        .IsNullOrEmpty(
                        
                          this
                        
                        .toId) ? 
                        
                          "
                        
                        
                           ClientsSendMessage 
                        
                        
                          "
                        
                         : 
                        
                          "
                        
                        
                           ClientsSendMessagetoAll 
                        
                        
                          "
                        
                        
                          ;
    
                        
                        
                          await
                        
                        
                           hubConnection.
                            InvokeAsync  
                          (methodName, message);
                        
                        
                          
}
                        
                      

测试功能正常,我们就可以把窗体整合到Winform端的主体界面中了.

在Winform端的登陆处理的时候,我们把SignarR的主要处理逻辑放在全局类GlobalControl 中,方便调用,并定义好几个常用的对象,如连接,在线用户信息,消息列表等.

并通过定义事件的方式,在消息变化的时候,通知界面进行更新处理.

                        
                          public
                        
                        
                          event
                        
                        
                           EventHandler<MessageInfo> 
                        
                         SignalRMessageChanged;
                      

因此我们可以在主界面上提供一个入口,供消息的处理操作.

主窗体在界面初始化的时候,调用一下全局类的初始化SignalR的Hub连接即可.

                        
                          ///
                        
                        
                          <summary>
                        
                        
                          ///
                        
                        
                           初始化SignalR的处理
        
                        
                        
                          ///
                        
                        
                          </summary>
                        
                        
                          private
                        
                        
                          async
                        
                        
                          void
                        
                        
                           InitSignalR()
        {
           
                        
                        
                          await
                        
                        
                           Portal.gc.InitHub();
        }
                        
                      

这样就会根据相应的信息,实现HubConnection的初始化操作了,而且这个连接的生命周期是伴随整个应用的出现而出现的.

打开就可以展示在线用户,并可以和系统相关用户发送实时消息了。如果可以,我们也可以把消息存储在数据库端,然后离线也可以收到存储起来,供下次登录后进行查看.

窗体可以对SignalR消息进行实时的更新相应,通过事件的实现.

                        
                          public
                        
                        
                          partial
                        
                        
                          class
                        
                        
                           FrmSignalClient : BaseDock
    {
        
                        
                        
                          public
                        
                        
                           FrmSignalClient()
        {
            InitializeComponent();

            Portal.gc.SignalRMessageChanged 
                        
                        +=
                        
                           SignalRMessageChanged;
        }
                        
                      

  。

 由于篇幅的原因,后面在介绍在Vue3+Element的BS端中实现对SignalR消息整合的处理操作.

最后此篇关于基于SqlSugar的开发框架循序渐进介绍(25)--基于SignalR实现多端的消息通讯的文章就讲到这里了,如果你想了解更多关于基于SqlSugar的开发框架循序渐进介绍(25)--基于SignalR实现多端的消息通讯的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com