一、介绍
SignalR 是一个用于实现实时网站的 Microsoft .NET 库。它使用多种技术来实现服务器与客户端间的双向通信,服务器可以随时将消息推送到连接的客户端。
二、新建Core MVC项目并安装
三、添加 SignalR 客户端库
在“解决方案资源管理器” 中,右键单击项目,然后选择“添加” >“客户端库”
在“添加客户端库” 对话框中,对于“提供程序” ,选择“unpkg” 。
对于“库” ,输入 @aspnet/signalr@1
,然后选择不是预览版的最新版本。
选择“选择特定文件” ,展开“dist/browser” 文件夹,然后选择“signalr.js” 和“signalr.min.js” 。
将“目标位置” 设置为 wwwroot/lib/signalr/ ,然后选择“安装” 。
四、创建 SignalR 中心即操作中心。
Hub 消息处理中心
public class TestHub : Hub { public TestHub() { } public async Task SendMessage(string message, string name) { #region Client //this.Context.ConnectionId //每个连接一个connectionId 表示唯一客户端 //this.Clients.Client().SendAsync(); //指定发送消息 //this.Clients.Clients() #endregion //给多个client发消息 #region Group //this.Clients.Group(); //给某个组发消息 //this.Clients.Groups() //给多个组发消息 //this.Groups.AddToGroupAsync() //将指定连接加入组 //this.Groups.RemoveFromGroupAsync() //将指定连接移除组 #endregion await Clients.All.SendAsync("onMsg", DateTime.Now, message); } //上下线消息 连接、断开事件 //客户端连接上 public override Task OnConnectedAsync() { return base.OnConnectedAsync(); } //客户端断开 public override Task OnDisconnectedAsync(Exception exception) { string connectionId = this.Context.ConnectionId; return base.OnDisconnectedAsync(exception); } }
以上可以看到SignalR
封装了很多常用方法(发送指定消息、群发...)
,我们可以很简单的使用达到目的
创建 Hubs 文件夹 。
在 Hubs 文件夹中,使用以下代码创建 ChatHub.cs 文件 :
using Microsoft.AspNetCore.SignalR; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; namespace Ban.Hubs { public class ChatHub:Hub { /// <summary> /// /服务端方法 发送消息--发送给所有连接的客户端 /// </summary> /// <param name="user"></param> /// <param name="message"></param> /// <returns></returns> public async Task SendMessage(string user,string message) { //ReceiveMessage 为客户端方法,让所有客户端调用这个方法 await Clients.All.SendAsync("ReceiveMessage",user,message); } /// <summary> /// 客户端连接的时候调用 /// </summary> /// <returns></returns> public override Task OnConnectedAsync() { Trace.WriteLine("客户端连接成功"); return base.OnConnectedAsync(); }//所有链接的客户端都会在这里 /// <summary> /// 连接终止时调用。 /// </summary> /// <returns></returns> public override Task OnDisconnectedAsync(Exception exception) { Trace.WriteLine("连接终止"); return base.OnDisconnectedAsync(exception); } } }
六、配置 SignalR
必须配置 SignalR 服务器,以将 SignalR 请求传递到 SignalR。
startup
中ConfigureServices
方法内部添加SignalR
服务services.AddSignalR();
,Configure
中配置具体的Hub
(路由器、中转):
app.UseSignalR(routes => { routes.MapHub<TestHub>("/testHub"); //可以多个map }); app.UseMvc(); //注意UseSignalR需要在UseMvc()之前
这样SignalR
服务器端就开发完成了,网页、Java、.Net客户端都可以连接的
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using test.Hubs; //3、引用 处理客户端 - 服务器通信的高级管道 namespace test { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddSignalR();//1、添加服务 } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseCookiePolicy(); app.UseSignalR(routes => //2、引用 { routes.MapHub<ChatHub>("/chatHub"); }); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } } }
七、添加 SignalR 客户端代码(创建index控制器和视图)
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> </head> <body> <div class="container"> <div class="row"> </div> <div class="row"> <div class="col-6"> </div> <div class="col-6"> User..........<input type="text" id="userInput" /> <br /> Message...<input type="text" id="messageInput" /> <input type="button" id="sendButton" value="Send Message" /> </div> </div> <div class="row"> <div class="col-12"> <hr /> </div> </div> <div class="row"> <div class="col-6"> </div> <div class="col-6"> <ul id="messagesList"></ul> </div> </div> </div> <script src="~/lib/signalr/dist/browser/signalr.js"></script> <script type="text/javascript"> "use strict"; var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build(); //在建立连接之前禁用发送按钮 document.getElementById("sendButton").disabled = true; //接受消息 connection.on("ReceiveMessage", function (user, message) { var msg = message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); var encodedMsg = user + " says " + msg; var li = document.createElement("li"); li.textContent = encodedMsg; document.getElementById("messagesList").appendChild(li); }); //开始链接 connection.start().then(function () { document.getElementById("sendButton").disabled = false; }).catch(function (err) { return console.error(err.toString()); }); //发送消息 document.getElementById("sendButton").addEventListener("click", function (event) { var user = document.getElementById("userInput").value; var message = document.getElementById("messageInput").value; connection.invoke("SendMessage", user, message).catch(function (err) { return console.error(err.toString()); }); event.preventDefault(); }); </script> </body> </html>
Controller中调用SignalR服务
在构造函数注入IHubContext<>
就可以直接使用了,非常方便:
private readonly IHubContext<TestHub> _hubContext; public HomeController(IHubContext<TestHub> hubContext) { _hubContext = hubContext; } public async Task<IActionResult> Notify() { //拿不到当前Hub的clientId 线程是唯一的 await _hubContext.Clients.All.SendAsync("onMsg", "from controller msg"); return Ok(); }