隐藏

在微信小程序中使用WebSocket连接Asp.Net Core SignalR

发布:2020/10/28 17:46:13作者:管理员 来源:本站 浏览次数:1603

最近在公司开发一个小程序时,需要使用到实时通信,然后在网上找了相关资料进行改进和封装,现在把整个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