51core

       最近在公司开发一个小程序时,需要使用到实时通信,然后在网上找了相关资料进行改进和封装,现在把整个DEMO分享出来.

组件版本信息:

Asp.Net Core SignalR 1.1.0版本

微信小程序使用腾讯默认的测试APPID,调试基础库基于2.7.1版本

Asp.Net Core SignalR服务端:

1.创建一个项目名为Mango.SignalR.WeChat空模板项目(这里不使用WEBAPI和MVC),这里同时创建一个Chat目录用来存放SignalR的封装类文件

2.使用Nuget引入Microsoft.AspNetCore.SignalR组件包

3.创建好一些基础处理类

说明:

ChatCore类:负责处理消息发送等业务逻辑

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading.Tasks;
 5 using Microsoft.AspNetCore.SignalR;
 6 using Newtonsoft.Json;
 7 namespace Mango.SignalR.WeChat.Chat
 8 {
 9     public class ChatCore
10     {
11 
12         ///
13         /// 发送聊天室消息
14         /// 
15         ///
16         ///
17         public static void SendMessage(ChatHub chatHub, MessageData messageData)
18         {
19             //
20             var sendMsg = JsonConvert.SerializeObject(messageData);
21             foreach (ConnectionUser user in ConnectionManager.ConnectionUsers)
22             {
23                 chatHub.Clients.Client(user.ConnectionId).SendAsync("receive", sendMsg);
24             }
25         }
26     }
27 }

 

ConnectionUser类:表示连接用户对象

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 
 5 namespace Mango.SignalR.WeChat.Chat
 6 {
 7     public class ConnectionUser
 8     {
 9         ///
10         /// 用户标识
11         /// 
12         public string UserId { get; set; }
13         ///
14         /// SignalR连接ID
15         /// 
16         public string ConnectionId { get; set; }
17     }
18 }

 

ConnectionManager类:存储用户连接信息

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 namespace Mango.SignalR.WeChat.Chat
 5 {
 6     public class ConnectionManager
 7     {
 8         public static List ConnectionUsers { get; set; } = new List();
 9     }
10 }

 

MessageData类:消息体格式定义

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 
 5 namespace Mango.SignalR.WeChat.Chat
 6 {
 7     public class MessageData
 8     {
 9         ///
10         /// 消息类型
11         /// 
12         public MessageType MessageType { get; set; }
13         ///
14         /// 发送用户(0表示系统消息发送用户)
15         /// 
16         public string SendUserId { get; set; }
17         ///
18         /// 消息内容
19         /// 
20         public string MessageBody { get; set; }
21     }
22 }

 

MessageDealWidth类:处理客户端发送的消息

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using System.Linq;
 5 using System.Threading;
 6 using System.Threading.Tasks;
 7 using Microsoft.AspNetCore.SignalR;
 8 using Newtonsoft.Json;
 9 namespace Mango.SignalR.WeChat.Chat
10 {
11     ///
12     /// 消息处理
13     /// 
14     public class MessageDealWidth
15     {
16         public static async Task DealWidth(string message,ChatHub chatHub)
17         {
18             await Task.Run(() => {
19                 try
20                 {
21                     MessageData data = JsonConvert.DeserializeObject(message);
22                     if (data != null)
23                     {
24                         ConnectionUser connectionUser = null;
25                         MessageData sendMsg = null;
26                         switch (data.MessageType)
27                         {
28                             case MessageType.Line:
29                                 connectionUser = ConnectionManager.ConnectionUsers.Where(m => m.ConnectionId == chatHub.Context.ConnectionId).FirstOrDefault();
30                                 //处理连接消息
31                                 if (connectionUser == null)
32                                 {
33                                     connectionUser = new ConnectionUser();
34                                     connectionUser.ConnectionId = chatHub.Context.ConnectionId;
35                                     connectionUser.UserId = data.SendUserId;
36                                     ConnectionManager.ConnectionUsers.Add(connectionUser);
37                                 }
38                                 //处理发送回执消息
39                                 sendMsg = new MessageData();
40                                 sendMsg.MessageBody = "";
41                                 sendMsg.MessageType = MessageType.LineReceipt;
42                                 sendMsg.SendUserId = "0";
43                                 chatHub.Clients.Client(chatHub.Context.ConnectionId).SendAsync("receive", JsonConvert.SerializeObject(sendMsg));
44                                 break;
45                             case MessageType.Text:
46                                 //处理普通文字消息
47                                 ChatCore.SendMessage(chatHub, data);
48                                 break;
49                             case MessageType.LineReceipt:
50                                 //处理连接回执消息
51                                 ChatCore.SendMessage(chatHub, data);
52                                 break;
53                         }
54                     }
55                 }
56                 catch (Exception ex)
57                 {
58                     Console.WriteLine(ex.Message);
59                 }
60             });
61         }
62     }
63 }

 

MessageType类:消息类型枚举类

 1 using System;
 2 
 3 namespace Mango.SignalR.WeChat.Chat
 4 {
 5     ///
 6     /// 消息类型
 7     /// 
 8     public enum MessageType
 9     {
10         ///
11         /// 连接消息
12         /// 
13         Line=1,
14         ///
15         /// 文字消息
16         /// 
17         Text=2,
18         ///
19         /// 连接回执消息
20         /// 
21         LineReceipt = 98,
22     }
23 }

 

4.创建一个ChatHub的类并且继承Hub父类,代码如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading.Tasks;
 5 using Microsoft.AspNetCore.SignalR;
 6 using Newtonsoft.Json;
 7 namespace Mango.SignalR.WeChat.Chat
 8 {
 9     public class ChatHub : Hub
10     {
11         ///
12         /// 服务器端中转消息处理方法
13         /// 
14         ///
15         /// 
16         public async Task ServerTransferMessage(string message)
17         {
18             await MessageDealWidth.DealWidth(message, this);
19         }
20         ///
21         /// 用户连接方法重写
22         /// 
23         /// 
24         public override Task OnConnectedAsync()
25         {
26             return base.OnConnectedAsync();
27         }
28         ///
29         /// 用户断开连接方法重写
30         /// 
31         ///
32         /// 
33         public override Task OnDisconnectedAsync(Exception exception)
34         {
35             try
36             {
37                 var item = ConnectionManager.ConnectionUsers.Where(m => m.ConnectionId == Context.ConnectionId).FirstOrDefault();
38                 //移除相关联用户
39                 ConnectionManager.ConnectionUsers.Remove(item);
40             }
41             catch (Exception ex)
42             {
43                 throw ex;
44             }
45             return base.OnDisconnectedAsync(exception);
46         }
47     }
48 }

 

5.在Startup类中添加并且启用SignalR组件

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading.Tasks;
 5 using Microsoft.AspNetCore.Builder;
 6 using Microsoft.AspNetCore.Hosting;
 7 using Microsoft.AspNetCore.Http;
 8 using Microsoft.Extensions.DependencyInjection;
 9 using Mango.SignalR.WeChat.Chat;
10 namespace Mango.SignalR.WeChat
11 {
12     public class Startup
13     {
14         // This method gets called by the runtime. Use this method to add services to the container.
15         // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
16         public void ConfigureServices(IServiceCollection services)
17         {
18             //添加SignalR
19             services.AddSignalR();
20         }
21 
22         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
23         public void Configure(IApplicationBuilder app, IHostingEnvironment env)
24         {
25             if (env.IsDevelopment())
26             {
27                 app.UseDeveloperExceptionPage();
28             }
29             //启用Signalr
30             app.UseSignalR(routes =>
31             {
32                 routes.MapHub("/ChatHub");
33             });
34             app.Run(async (context) =>
35             {
36                 await context.Response.WriteAsync("SignalR Success!");
37             });
38         }
39     }
40 }

 

6.把SignalR服务端部署到服务器上

PS:由于微信小程序的特殊性需要使用HTTPS,所以这里我已经提供了一个公共测试域名https://123.51core.net

微信小程序端:

1.使用微信开发者工具创建一个用于测试的项目

2.在lib目录中创建signalR.js文件,这个文件封装一个WebSocket处理模块

  1 var signalR = (function () {
  2   let recordCode = 0x1e;
  3   let recordString = String.fromCharCode(recordCode);
  4   let isConnectioned = false;
  5   let _events=new Array();
  6   //初始化相关事件
  7   //消息发送事件
  8   _events['send'] = function (obj) {
  9     console.log(obj);
 10   };
 11   //消息接收事件
 12   _events['receive']=function(message){
 13     console.log(message);
 14   };
 15   //连接事件
 16   _events['connection']= function () {
 17     console.log(message);
 18   };
 19   //连接关闭事件
 20   _events['close']= function () {
 21     console.log('连接已经关闭');
 22   };
 23   //连接异常处理事件
 24   _events['error'] = function (ex) {
 25     console.log(ex);
 26   };
 27   return {
 28     //事件绑定
 29     on:function(eventName,eventMethod){
 30       if (_events[eventName] != null && _events[eventName]!=undefined){
 31         _events[eventName] = eventMethod;
 32       }
 33     },
 34     //连接方法
 35     connection: function (url) {
 36       let self = this;
 37       wx.connectSocket({
 38         url: url
 39       });
 40       wx.onSocketOpen(function () {
 41         let handshakeRequest = {
 42           protocol: 'json',
 43           version: 1
 44         };
 45         let senddata = `${JSON.stringify(handshakeRequest)}${recordString}`;
 46         self.isConnectioned = true;
 47         wx.sendSocketMessage({
 48           data: senddata,
 49         });
 50         _events['connection']();
 51       });
 52       wx.onSocketClose(function () {
 53         self.isConnectioned = false;
 54         _events['close']();
 55       });
 56       //接收到消息
 57       wx.onSocketMessage(function (res) {
 58         try {
 59           //console.log(res);
 60           let jsonstr = String(res.data).replace(recordString, '');
 61           if (jsonstr.indexOf('{}{') > -1){
 62             jsonstr = jsonstr.replace('{}', '');
 63           }
 64           let obj = JSON.parse(jsonstr);
 65           //当收到返回消息type=1(调用方法)
 66           if (obj.type == 1) {
 67             _events['receive'](obj.arguments[0]);
 68           }
 69         } catch (ex) {
 70           console.log('异常:' + ex);
 71           console.log('收到服务器内容:' + res.data);
 72         }
 73       });
 74       wx.onSocketError(function (ex) {
 75         self.isConnectioned = false;
 76         _events['error'](ex);
 77       });
 78     },
 79     abortConnection: function () {
 80       console.log(String(this.abortConnection.name));
 81       wx.closeSocket();
 82     },
 83     sendMessage: function (data) {
 84       let self = this;
 85       if (!self.isConnectioned) {
 86         _events['error']('未连接');
 87         return;
 88       }
 89       let args=new Array();
 90       args.push(data);
 91       let body = {
 92         arguments: args,   //SignalR服务端接收时必须为数组参数
 93         target: 'ServerTransferMessage',        //SignalR端方法
 94         type: 1,
 95       };
 96       //发送的数据,分隔符结尾:
 97       let senddata = `${JSON.stringify(body)}${recordString}`;
 98       wx.sendSocketMessage({
 99         data: senddata,
100         success: function(res){
101           _events['send'](res);
102         },
103         fail: function(ex){
104           console.log(ex);
105         }
106       });
107     }
108   }
109 });
110 module.exports = {
111   signalR: signalR
112 }

 

 

2.在index.js中调用

 1 //index.js
 2 ///引入这个类库
 3 var signalR = require('../../lib/signalR.js')
 4 //获取应用实例
 5 const app = getApp()
 6 
 7 Page({
 8   data: {
 9     motto: '微信连接SignalR的Demo'
10   },
11   onLoad: function () {
12     //测试WebSocket
13     ///实例化一个对象
14     let _signalR = new signalR.signalR();
15     _signalR.on("receive", function (message) {
16       console.log('服务器返回消息回调方法:' + message);
17     });
18     _signalR.on("connection", function () {
19       //消息格式
20       var msg = {
21         messageType: 1,//消息类型 1.发送连接消息 2.普通内容消息 98.连接回执消息
22         sendUserId: '1',//消息发送人(登录用户ID)
23         messageBody: 'online'//消息内容
24       };
25       _signalR.sendMessage(JSON.stringify(msg));
26     });
27     _signalR.connection('wss://123.51core.net/ChatHub');
28   }
29 })

 

 接下来就可以查看运行结果了,如下图:

本案例源代码已经更新到github上,欢迎大家下载

https://github.com/51core/mango-docs

欢迎加入.Net Core/Asp.Net Core 交流群:95981589

相关文章:

猜你喜欢