Asp.net SignalR
一、介绍
SignalR对websocket、SSE、长连接、forever frame进行封装。
websocket(html5):ws协议,这个协议基于tcp的。也就是说和http没有关系(兼容性不好)
SSE:客户端订阅服务器的一个事件,然后方便通过这个事件推送到客户端。 server => client
长链接:保持一次链接的时间,例如保持一个链接5s
forever frame:在body中藏一个iframe,那么这个iframe和server是一个永久链接,如果server来数据,通过这个链接推送到client
二、PersistentConnection
1,参数
《1》 request: 获取一些链接中的附加信息,request.querystring
request.cookie
request是一个katana的包装类。
singlaR 的request 其实是asp.net 中的 Request的子集。
《2》 connectionId 这个参数就是 客户端连接到服务器的唯一标识。。。也就说这个标识标识了客户端。本质上来说,和SessionID是一个性质。 【GUID】
2,demo
using System; using System.Threading.Tasks; using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(WebApplication1.Startup1))] namespace WebApplication1 { public class Startup1 { public void Configuration(IAppBuilder app) { // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888 app.MapSignalR<MyConnection1>("/connection"); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Web; using Microsoft.AspNet.SignalR; namespace WebApplication1 { public class MyConnection1 : PersistentConnection { //js调用 start 触发 protected override Task OnConnected(IRequest request, string connectionId) { return Connection.Send(connectionId, "Welcome!"); } //js 调用send触发 protected override Task OnReceived(IRequest request, string connectionId, string data) { return Connection.Broadcast(data); } //关闭连接(或者浏览器窗口)触发 protected override Task OnDisconnected(IRequest request, string connectionId, bool stopCalled) { return base.OnDisconnected(request, connectionId, stopCalled); } } }
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="Scripts/jquery-1.6.4.js"></script> <script src="Scripts/jquery.signalR-2.2.3.js"></script> <script type="text/javascript"> var con = $.connection("/connection"); //启动 con.start(function (data) { con.send("asdasd") }) con.received(function (data) { console.log("receive:"+data) }) </script> </head> <body> </body> </html>
二、group(建简易聊天室)
using System; using System.Threading.Tasks; using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(WebApplication1.Startup1))] namespace WebApplication1 { public class Startup1 { public void Configuration(IAppBuilder app) { // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888 app.MapSignalR<MyConnection1>("/connection"); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Web; using Microsoft.AspNet.SignalR; namespace WebApplication1 { public class MyConnection1 : PersistentConnection { private const string DEFAULT = "default"; //js调用 start 触发 protected override Task OnConnected(IRequest request, string connectionId) { this.Groups.Add(connectionId, DEFAULT); //excludeConnectionIds:排除通知的connectionId。在default组中,除了自己,其他人都能收到信息 return this.Groups.Send(DEFAULT, connectionId + "进入房间", connectionId); } //js 调用send触发 protected override Task OnReceived(IRequest request, string connectionId, string data) { //excludeConnectionIds:排除通知的connectionId。在default组中,除了自己,其他人都能收到信息 return this.Groups.Send(DEFAULT, connectionId + ":" + data, connectionId); } //关闭连接(或者浏览器窗口)触发 protected override Task OnDisconnected(IRequest request, string connectionId, bool stopCalled) { return base.OnDisconnected(request, connectionId, stopCalled); } } }
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="Scripts/jquery-1.6.4.js"></script> <script src="Scripts/jquery.signalR-2.2.3.js"></script> <script type="text/javascript"> $(function () { var con = $.connection("/connection"); //启动 con.start(function (data) { }) con.received(function (data) { $("#context").append("<br/>"+data) console.log(data) }) $("#send").click(function () { con.send($("#txt").val()) }) }) </script> </head> <body> <input type="text" id="txt" /> <input type="button" id="send" value="发送"/> <div id="context"> </div> </body> </html>
案例下载:https://pan.baidu.com/s/1YJN-bwertKNQc2O5JHlQgg
三、Hub
1,js调用直接后端方法、后端直接调用js方法
using System; using System.Threading.Tasks; using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(WebApplication1.Startup1))] namespace WebApplication1 { public class Startup1 { public void Configuration(IAppBuilder app) { // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888 app.MapSignalR(); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Microsoft.AspNet.SignalR; namespace WebApplication1 { public class MyHub : Hub { public void Hello() { //直接调用前端js方法 Clients.All.aa("abc"); } } }
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="Scripts/jquery-1.6.4.js"></script> <script src="Scripts/jquery.signalR-2.2.3.js"></script> <!--引用js--> <script src="/signalr/js"></script> <script type="text/javascript"> $(function () { //启动hub $.connection.hub.start() var conne = $.connection.myHub; //申明客户端js方法 conne.client.aa = function (msg) { $("#context").append("<br/>" + msg) } $("#send").click(function () { //直接调用后端方法 conne.server.hello(); }) }) </script> </head> <body> <input type="text" id="txt" /> <input type="button" id="send" value="发送"/> <div id="context"> </div> </body> </html>
2,HubName/HubMethodName
using Microsoft.AspNet.SignalR.Hubs;
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Hubs; namespace WebApplication1 { [HubName("MyHub")] public class MyHub : Hub { [HubMethodName("Hello")] public void Hello() { //直接调用前端js方法 Clients.All.aa("abc"); } } }
3,ConnectionId
this.Context.ConnectionId;
四、Hub中的clients 和 groups属性
1,Clients
①T All { get; }
相当于持久连接中的 Broadcast。
②T AllExcept(params string[] excludeConnectionIds);
给排除本人所有人发送消息。(excludeConnectionIds排除的连接id)
③T Client(string connectionId);
跟Send操作就是一样的了。
④T Clients(IList<string> connectionIds);
和Send操作的重载方法一样,可以给一批指定的人发送。
⑤T Group(string groupName, params string[] excludeConnectionIds);
给房间中的指定人发送消息: Clients.Group("room1", "asdfasdfads");
⑥T Groups(IList<string> groupNames, params string[] excludeConnectionIds);
给房间列表中的指定人发送消息; 【天然的聊天室功能】
⑦T User(string userId);
这个和Client是有区别的。 这个userId => this.Context.Request.User.Identity.Name 【form验证】
cookie中间件来做到singlar的身份验证。
userId 是你自己定义的一个标识。
T Users(IList<string> userIds);
2,Groups
①Task Add(string connectionId, string groupName);
向组内添加链接
②Task Remove(string connectionId, string groupName);
删除组内的连接
五、GlobalHost
1,获取Hub的上下文
var hub = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
2,对singlar的全局设置
GlobalHost.Configuration.MaxIncomingWebSocketMessageSize:
websocket模式下,消息的传输大小,如果大于默认的64k,那么就会出问题。
GlobalHost.Configuration.DisconnectTimeout:
websocket强制关闭的时间。 30 seconds
GlobalHost.Configuration.TransportConnectTimeout:
传输的超时时间。 5s
六、生成代理js
下载安装nuget: Microsoft.AspNet.SignalR.Utils
1,模板:signalr.exe ghp /path:《..\bin》 /o:《..\hub.js》
2,案例:
C:\Users\Hunter\Desktop\ConsoleApp3\packages\Microsoft.AspNet.SignalR.Utils.2.2.3\tools>signalr.exe ghp /path:C:\Users\Hunter\Desktop\ConsoleApp3\WebApplication2\bin /o:C:\Users\Hunter\Desktop\ConsoleApp3\WebApplication2\Scripts\hub.js
3,编译命令:
$(SolutionDir)packages\Microsoft.AspNet.SignalR.Utils.2.2.3\tools\signalr.exe ghp /path:$(SolutionDir)$(ProjectName)\$(OutDir) /o:$(SolutionDir)$(ProjectName)\Scripts\hub.js
4,替换代理js
七、支持跨域
①下载安装nuget: Microsoft.Owin.Cors
②配置项
using System; using System.Threading.Tasks; using Microsoft.Owin; using Owin; using Microsoft.AspNet.SignalR; using Microsoft.Owin.Cors; [assembly: OwinStartup(typeof(WebApplication2.Startup))] namespace WebApplication2 { public class Startup { public void Configuration(IAppBuilder app) { // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888 app.UseCors(CorsOptions.AllowAll); app.MapSignalR(); } } }
③生成代理js
④修改代理js
⑤html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="Scripts/jquery-1.6.4.js"></script> <script src="Scripts/jquery.signalR-2.2.3.js"></script> <!--引用js--> <!--<script src="/signalr/js"></script>--> <script src="Scripts/hub.js"></script> <script type="text/javascript"> $(function () { //启动hub $.connection.hub.start() var conne = $.connection.myHub; //申明客户端js方法 conne.client.aa = function (msg) { $("#context").append("<br/>" + msg) } $("#send").click(function () { //直接调用后端方法 conne.server.hello(); }) }) </script> </head> <body> <input type="text" id="txt" /> <input type="button" id="send" value="发送"/> <div id="context"> </div> </body> </html>
案例下载:https://pan.baidu.com/s/1GY_Io63qZeECbGbEH589fg
八、集群部署
使用redis:
nuget: Microsoft.AspNet.SignalR.Redis
using System; using System.Threading.Tasks; using Microsoft.Owin; using Owin; using Microsoft.AspNet.SignalR; using Microsoft.Owin.Cors; [assembly: OwinStartup(typeof(WebApplication2.Startup))] namespace WebApplication2 { public class Startup { public void Configuration(IAppBuilder app) { // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888 //使用redis做底板 GlobalHost.DependencyResolver.UseRedis("localhost", 6379,string.Empty, "mykey"); app.UseCors(CorsOptions.AllowAll); app.MapSignalR(); } } }
九、将singlar.exe 装入到 性能监视器
signlar.exe ipc 命令来安装性能监视器 [install performance counters]
signlar.exe upc 来卸载性能监视器 [uninstall performance counters]
十、HubPipeLine管道
实现:IHubPipelineModule
①入流: BuildIncoming 监控
②出流: BuildOutgoing 监控