系列
源碼地址:https://github.com/QQ2287991080/SignalRServerAndVueClientDemo
概述:ASP.NET Core SignalR是一種開放源代碼庫,可簡化將實時 web 功能添加到應用程序的功能。 實時 web 功能使服務器端代碼可以立即將內容推送到客戶端。
這玩意的概念我就不多講了,官方文檔:https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction?view=aspnetcore-3.0
今天這個demo,就是用SignalR 做服務端,vue做客戶端。
以下演示皆為本地環境
先看看最終效果
上代碼
先建一個項目,我core的版本是3.0,我選擇的應用“Web應用程序”,其實我這創建的就跟官網的JavaScript教程一樣的。
項目建好之后右鍵項目->添加>客戶端庫
按圖上添加就好了
把Pages下面的Index視圖的代碼換成如下:
@page <div class="container"> <div class="row"> </div> <div class="row"> <div class="col-2">User</div> <div class="col-4"><input type="text" id="userInput" /></div> </div> <div class="row"> <div class="col-2">Message</div> <div class="col-4"><input type="text" id="messageInput" /></div> </div> <div class="row"> </div> <div class="row"> <div class="col-6"> <input type="button" id="sendButton" value="Send Message" /> </div> </div> </div> <div class="row"> <div class="col-12"> <hr /> </div> </div> <div class="row"> <div class="col-6"> <ul id="messagesList"></ul> </div> </div> <script src="~/js/signalr/dist/browser/signalr.js"></script> <script src="~/js/chat.js"></script>
在放靜態文件的wwwroot的js下面新建一個chat.js,並放入如下代碼
"use strict"; var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build(); //Disable send button until connection is established 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(); });
添加SignalR中心,加個Hubs文件夾,加個ChatHub類
public class ChatHub : Hub { /// <summary> /// 給所有客戶端發送消息 /// </summary> /// <param name="user">用戶</param> /// <param name="message">消息</param> /// <returns></returns> public async Task SendMessage(string user, string message) { await Clients.All.SendAsync("ReceiveMessage", user, message); } /// <summary> /// 向調用客戶端發送消息(備用) /// </summary> /// <param name="message"></param> /// <returns></returns> public async Task SendMessageCaller(string message) { await Clients.Caller.SendAsync("ReceiveCaller", message); } }
在Startup里配置SignalR
ConfigureServices里加上
services.AddSignalR();
Configure
app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); endpoints.MapHub<ChatHub>("/chathub"); });
看看效果
是不是有聊天室那味了。。
哎呀不對,標題咋不說要弄vue做客戶端啊,咋現在還在這寫視圖呢。
那么接下來就用vue做客戶端,我用的腳手架,引用vue.js也是能實現的。
先用腳手架建一個項目,把不要的東西都刪除,只留下一個home.vue,記得路由里面也刪除干凈,要不然會報錯的。
首先我們先安裝前端的js包,上文也看到我們調用signalr中心有對應的js客戶端
npm install @aspnet/signalr
安裝好之后,我們開始寫前端代碼
在home.vue里面放兩個輸入框和一個按鈕,和core的index視圖差不多,樣式就不美化,主要做效果。
<input v-model="user" type="text" /> <input v-model="message" type="text" /> <button @click="sendAll">發送全部</button>
引用安裝的@aspnet/signalr
import * as signalR from "@aspnet/signalr";
定義需要的變量
data() { return { user: "",//用戶 message: "",//消息 connection: "",//signalr連接 messages: []//返回消息 }; },
定義頁面加載連接signalr
created: function() { let thisVue = this; this.connection = new signalR.HubConnectionBuilder() .withUrl("http://localhost:13989/chathub", { skipNegotiation: true, transport: signalR.HttpTransportType.WebSockets }) .configureLogging(signalR.LogLevel.Information) .build(); this.connection.on("ReceiveMessage", function(user, message) { thisVue.messages.push({ user, message }); console.log({ user, message }); }); this.connection.start(); }
給按鈕來個點擊事件
methods: { //給全部發送消息 sendAll: function() { this.connection .invoke("SendMessage", this.user, this.message) .catch(function(err) { return console.error(err); }); } }
🆗。把代碼跑起來,npm run serve........
等一下,先把我們的后端跑起來,要不然是接受不到的。
測試看看先。。
數據拿到了,忘記展示了,先加個<ul>
<div>
<ul v-for="(item ,index) in messages" v-bind:key="index +'itemMessage'">
<li>{{item.user}} says {{item.message}}</li>
</ul>
</div>
我再加個標題吧好看點。
哎。有內味兒了。
不知道還有人記得之前chahub里面我預留了一個給自己發消息的方法。
嘿,這會兒就給他實現一下,首先我先加個按鈕,然后在注冊給自己發送的方法。這回我代碼就不填出來,先看看效果,之后代碼全都給出來。
來了來了,壓縮囂張至極。。。
先把前端代碼放出來,完整版
<template> <div class="home"> <h1>前端演示SignalR</h1> <input v-model="user" type="text" /> <input v-model="message" type="text" /> <button @click="sendAll">發送全部</button> <button @click="sendOwn">對自己發送</button> <div> <ul v-for="(item ,index) in messages" v-bind:key="index +'itemMessage'"> <li>{{item.user}} says {{item.message}}</li> </ul> </div> </div> </template> <script> // @ is an alias to /src import HelloWorld from "@/components/HelloWorld.vue"; import * as signalR from "@aspnet/signalr"; export default { name: "Home", components: { HelloWorld }, data() { return { user: "", //用戶 message: "", //消息 connection: "", //signalr連接 messages: [] //返回消息 }; }, methods: { //給全部發送消息 sendAll: function() { this.connection .invoke("SendMessage", this.user, this.message) .catch(function(err) { return console.error(err); }); }, //只給自己發送消息 sendOwn: function() { this.connection .invoke("SendMessageCaller", this.message) .catch(function(err) { return console.error(err); }); } }, created: function() { let thisVue = this; this.connection = new signalR.HubConnectionBuilder() .withUrl("http://localhost:13989/chathub", { skipNegotiation: true, transport: signalR.HttpTransportType.WebSockets }) .configureLogging(signalR.LogLevel.Information) .build(); this.connection.on("ReceiveMessage", function(user, message) { thisVue.messages.push({ user, message }); console.log({ user, message }); }); this.connection.on("ReceiveCaller", function(message) { let user = "自己";//這里為了push不報錯,我就弄了一個默認值。 thisVue.messages.push({ user, message }); console.log({ user, message }); }); this.connection.start(); } }; </script>
完結!!!
這個其實還是不是特別我完整,下次有時間把中心服務到客戶端的也搞出來大伙看看。
(中心往外部發送)