编辑
2020-12-04
我当开发
00

目录

1. 引用SignalR
2. 服务端注册使用
3. Vue端连接使用
4. 其他-invoke的响应

Vue + SignalR + .NET Core 2.2 通讯

1. 引用SignalR

服务端略

Vue 添加 依赖 @microsoft/signalr

npm install @microsoft/signalr

2. 服务端注册使用

ConfigureServices 中加入 AddHttpContextAccessor 和 AddSignalR

// 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; }); //获取连接ID用的 services.AddHttpContextAccessor(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); //添加SignalR services.AddSignalR(); //MQ的注入 services.AddSingleton<IMyMQ, MyMQ>(); }

Configure中

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { /*这里引用的顺序如果不对会报跨域错误*/ app.UseCors(builder => { //builder.WithOrigins(""http://127.0.0.1:44325");//指定IP //builder.AllowAnyOrigin();//这个不好使 builder.SetIsOriginAllowed(origin => true); builder.AllowAnyHeader(); builder.AllowAnyMethod(); builder.AllowCredentials(); }); app.UseWebSockets(); //取个名Home 这个随便 前端跟他一样就行 //ViewHub 是新建的类 app.UseSignalR(routes => { routes.MapHub<ViewHub>("/Home"); }); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseCookiePolicy(); //app.UseSession(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } }

ViewHub 类继承 Hub

public class ViewHub : Hub { /// <summary> /// websocket SignalR /// </summary> private readonly IHubContext<ViewHub> _messageHub; /// <summary> /// MQ /// </summary> private readonly IMyMQ _mymq; private readonly IHttpContextAccessor _accessor; //第一个是我的MQ注入,第二个是连接的注入 public ViewHub(IMyMQ mymq, IHubContext<ViewHub> messageHub,IHttpContextAccessor accessor) { this._mymq = mymq; this._messageHub = messageHub; this._accessor = accessor; //发送消息 messageHub.Clients.All.SendAsync("MQLOG", "XXXX"); } public override Task OnConnectedAsync() { //可以拿到当前连接的ID 作为标识 string connId = Context.ConnectionId; //在连接时还可以传递其他信息 //var token = _accessor.HttpContext.Request.Query["access_token"]; //给当前连接返回消息 .Clients可以发多个连接ID Clients.Client(connId).SendAsync("ConnectResponse", id+"连接成功"); return base.OnConnectedAsync(); } //接收前端来的消息 public async Task SendMessage(string theme, string data,string GUID) { JObject msg = new JObject(); msg.Add("msg","发送成功"); msg.Add("GUID", GUID); //也可以这样直接发送消息 await Clients.All.SendAsync("MQSend", msg.ToString()); } }

3. Vue端连接使用

建一个signalR.js

import * as signalR from "@microsoft/signalr"; //Url 注意/Home 跟服务端一致 const url = "http://localhost:63437/Home"; const signal = new signalR.HubConnectionBuilder() //服务器地址 .withUrl(url, { //传递Token accessTokenFactory: () => "00001" }) .withAutomaticReconnect()//自动重连 .build(); async function start() { try { await signal.start(); console.log("connected"); } catch (err) { console.log(err); //半自动重连 //setTimeout(() => start(), 5000); } } //关闭 signal.onclose(async err => { //await start(); console.log(err); }); //将创建的signal赋值给Vue实例 export default { //install方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象。 install: function(Vue) { Vue.prototype.signalr = signal; } };

在main.js中引用

import signalr from "./utils/signalR"; Vue.use(signalr);

连接,这里写在了App.vue中

created() { //接收消息建议在start之前注册,至少注册一个 //参照服务端 连接之后会有个ConnectResponse返回ID this.signalr.on("ConnectResponse", res => { //可以做相关业务逻辑 console.log(res); }); this.signalr.on("MQSend", res => { res = JSON.parse(res); }); }, mounted() { this.signalr.start().then(() => { console.log("连接"); }); }, methods: { //向服务端发送消息 async setMessage(theme, data) { return new Promise((resolve, reject) => { //对应服务端的SendMessage方法 this.signalr .invoke("SendMessage", theme, JSON.stringify(data), guid) .catch(function(err) { console.error(err.toString()) //reject(err.toString()); }); resolve('done') }); }); }

4. 其他-invoke的响应

到这就可以了,但是使用中 invoke 是不返回消息的,如果返回消息还要再下发,在 on 里接收,这是两个独立事件,业务页面我要先写个监听返回再写个发送方法,如果我能写成 await 形式就方便了,比如

let res = await this.App.setMessage("XXX", {XXXX}); this.$message(res.msg);

这里要将App.vue中的setMessage重写,有返回结果后再执行Promise的resolve,

async setMessage(theme, data) { //先取一个标识 const guid = this.$newGUID(); //存储当前的Promise let prom = {}; //创建Promise 将GUID一并上传 let p = new Promise((resolve, reject) => { this.signalr .invoke("SendMessage", theme, JSON.stringify(data), guid) //将resolve 缓存 prom.resolve = resolve; }); //将Promise缓存 prom.p = p; //放到页面缓存 this.MQsend[guid] = prom; //由于没有执行resolve 这个请求将一直挂起 直到执行resolve return p; }

App.vue接收结果改为

this.signalr.on("MQSend", res => { res = JSON.parse(res); /** *服务返回GUID *先找到缓存中GUID对应的Promise *再执行resolve 执行后删除缓存 *这时Promise的状态改变 await结束 */ if (res.GUID && this.MQsend[res.GUID]) { this.MQsend[res.GUID].resolve(res); delete this.MQsend[res.GUID]; } });
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:没想好

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!