zoukankan      html  css  js  c++  java
  • 尝试.NetCore 3.x SignalR

    1、什么是 SignalR?

    ASP.NET Core SignalR 是一个开源库,它简化了向应用程序添加实时 web 功能的功能。 实时 Web 功能使服务器端代码能够即时将内容推送到客户端。
    适用场景:

    • 需要从服务器进行高频率更新的应用。 示例包括游戏、社交网络、投票、拍卖、地图和 GPS 应用。
    • 仪表板和监视应用。 示例包括公司仪表板、即时销售更新或旅行警报。
    • 协作应用。 协作应用的示例包括白板应用和团队会议软件。
    • 需要通知的应用。 社交网络、电子邮件、聊天、游戏、旅行警报和很多其他应用都需使用通知。
      详情介绍详见官网:https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction?view=aspnetcore-3.1

    2、创建Hub中心

    2.1 Hub集线器介绍

    Hub集线器的结构如图所示:
    Hub介绍

    • OnConnectedAsync方法:客户端连接的时候事件方法
    • OnDisconnectedAsync方法:客户端断开连接的时候事件方法
    • Clients对象:服务器和客户端之间的通信对象
    • Context对象:该对象是当前请求的上下文对象,例如包含连接Id、用户身份信息等等

    2.2 创建自定义集线器

    internal class MyCore31Hub : Hub
    {
        static IDictionary<string, ClientInfo> _clients;
        static MyCore31Hub()
        {
            _clients = new Dictionary<string, ClientInfo>();
        }
        public async override Task OnConnectedAsync()
        {
            var connid = Context.ConnectionId;
            var httpContext = Context.GetHttpContext();
            httpContext.Request.Query.TryGetValue("groupId", out StringValues groupid);
            httpContext.Request.Query.TryGetValue("userId", out StringValues userId);
            httpContext.Request.Query.TryGetValue("ip", out StringValues ip);
            if (!userId.Equals(StringValues.Empty))
            {
                if (_clients.ContainsKey(userId))
                {
                    _clients.Remove(userId);
                }
                _clients.Add(userId, new ClientInfo()
                {
                    ConnectionId = connid,
                    GroupId = groupid,
                    UserId = userId,
                    Ip = ip
                });
                await Groups.AddToGroupAsync(connid, groupid);
                await SendConnection(groupid, new ConnectionMessageContent
                {
                    From = userId,
                    TransferCode = "上线",
                    LocalServerCode = "Connection",
                    Content = $"{userId}上线啦!!!"
                });
            }
        }
    
        public async override Task OnDisconnectedAsync(Exception exception)
        {
            var connid = Context.ConnectionId;
            var client = GetClient(connid);
            if (client != default(ClientInfo))
            {
                await Groups.RemoveFromGroupAsync(connid, client.GroupId);
                await SendDisConnection(client.GroupId, new DisConnectionMessageContent
                {
                    From = client.UserId,
                    TransferCode = "下线",
                    LocalServerCode = "DisConnection",
                    Content = $"{client.UserId}下线啦!!!"
                });
            }
        }       
        public async Task SendConnection(string groupName, ConnectionMessageContent msg)
        {
            await Clients.Group(groupName).ReceiveConnection(msg);
        }
    
        public async Task SendDisConnection(string groupName, DisConnectionMessageContent msg)
        {
            await Clients.Group(groupName).ReceiveDisConnection(msg);
        }
        ClientInfo GetClient(string connid)
        {
            var client = _clients.Values.Where(c => c.ConnectionId.Equals(connid)).FirstOrDefault();
            if (client != null)
            {
                return client;
            }
            return default(ClientInfo);
        }        
    }
    
    创建的实例中包含一个客户端对象,该对象用于存储客户端的信息
    
    public class ClientInfo
    {
        public ClientInfo()
        {
            ConnectedTime = DateTime.Now;
        }
        public string ConnectionId { get; set; }
        public string GroupId { get; set; }
        public string UserId { get; set; }
        public string Ip { get; set; }
        DateTime ConnectedTime { get; }
    }
    

    配置 SignalR 中心

    SignalR 中间件需要一些服务,这些服务通过调用 services.AddSignalR进行配置。

    services.AddSignalR(options=>
    {
        options.EnableDetailedErrors = true;
        options.ClientTimeoutInterval = TimeSpan.FromSeconds(30);
    });
    

    将 SignalR 功能添加到 ASP.NET Core 应用时,请通过在 Startup.Configure 方法的 app.UseEndpoints 回调中调用 endpoint.MapHub 来设置 SignalR 路由。

    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHub<MyCore31Hub>(new PathString("/notify"));
    });
    
    这里做一个说明,在3.x以前的版本中使用UseSignalR()
    

    3、 创建客户端

    3.1 .Net客户端

    3.1.1 安装 SignalR .NET 客户端包
    Install-Package Microsoft.AspNetCore.SignalR.Client
    
    3.1.2 连接到自定义Hub中心

    若要建立连接,请创建 HubConnectionBuilder 并调用 Build。 在建立连接时,可以配置中心 URL、协议、传输类型、日志级别、标头和其他选项。 通过在 Build中插入任意 HubConnectionBuilder 方法来配置任何所需的选项。 开始与 StartAsync的连接。
    该示例中使用Winfrom完成

    使用winform必须vs 版本>=16.5.0,我在使用的时候老是创建不了winform就是该原因,微软在3netcore.x版本中就已经支持winform wpf等桌面程序了
    
    public partial class frmMain : Form{
    	static string url = "https://localhost:5001/notify";
    	string groupId = "123456";
    	string userId = "";
    	string ip = "127.0.0.1";
    	HubConnection conn;
    	public frmMain(string uid) : this()
    	{
    	    userId = uid;
    	    this.Text += userId;
    	    url += $"?groupId={groupId}&userId={userId}&ip={ip}";
    	    conn = new HubConnectionBuilder()
    	        .WithUrl(url)
    	        .WithAutomaticReconnect() //自动连接
    	        .Build();
    	    conn.Closed += async (error) =>
    	    {
    	        await Task.Delay(new Random().Next(0, 5) * 1000);
    	        await conn.StartAsync();
    	    };
    	}
    	public frmMain()
    	{
    	    InitializeComponent();
    	}
    	
    	private async void btnConnect_Click(object sender, EventArgs e)
    	{
    	    On();
    	    try
    	    {
    	        await conn.StartAsync();
    	        this.rbxCotent.AppendText("Connection started");
    	        this.btnConnect.Enabled = false;
    	    }
    	    catch (Exception ex)
    	    {
    	        this.rbxCotent.AppendText(ex.Message);
    	    }
    	}
    	
    	private void On()
    	{
    	    // 收到信息
    	    conn.On<UserMessageContent>("ReceiveMessage", (message) =>
    	    {
    	        Invoke(new Action(() =>
    	        {
    	            this.rbxCotent.AppendText(message.Content);
    	        }));
    	    });
    	    // 上线
    	    conn.On<ConnectionMessageContent>("ReceiveConnection", (message) =>
    	    {
    	        Invoke(new Action(() =>
    	        {
    	            this.rbxCotent.AppendText(message.Content);
    	            this.listView1.Items.Add(new ListViewItem()
    	            {
    	                Text=message.From,
    	                Name=message.From                        
    	            });
    	        }));
    	    });
    	    // 下线
    	    conn.On<DisConnectionMessageContent>("ReceiveDisConnection", (message) =>
    	    {
    	        Invoke(new Action(() =>
    	        {
    	            this.rbxCotent.AppendText(message.Content);
    	            this.listView1.Items.Add(message.From);
    	        }));
    	    });
    	}	
    }
    

    4、效果展示

    在这里插入图片描述

    进入主页后点击连接到服务器,连接成功后会收到集线器客户端连接事件发出的消息。通过发送消息给用户组

    在这里插入图片描述
    接下来会讲解下JavaScript客户端
    源码地址:https://github.com/jonny-xhl/Cy.WeChat 若给你带来了帮助请欢迎Star
    参考文献:
    https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction?view=aspnetcore-3.1
    https://blog.csdn.net/xhl_james/article/details/89235081
    Signalr篇文章目录:
    一、尝试.NetCore 3.x SignalR
    二、JavaScript客户端使用
    三、管理 SignalR 中的用户和组
    四、强类型中心详解(Hub< T >)
    五、ASP.NET Core 中的身份验证和授权 SignalR

  • 相关阅读:
    JAVA代码中加了Try...Catch的执行顺序
    Java的注解机制——Spring自动装配的实现原理
    UWP蓝牙的例子
    MIT License
    Windows 运行时组件
    VS 的编译选项 build下的 platform target -- Any CPU和x86有什么影响?
    swfdump——从内存中提取swf的工具
    生成某一文件夹内文件清单(批量处理)
    统一用户认证和单点登录解决方案
    关键路径计算、总时差、自由时差
  • 原文地址:https://www.cnblogs.com/cqxhl/p/12993274.html
Copyright © 2011-2022 走看看