基于.net6的WPF程序使用SignalR进行通信

之前写的SignalR通信,是基于.net6api,BS和CS进行通信的。

.net6API使用SignalR+vue3聊天+WPF聊天_signalr wpf_故里2130的博客-CSDN博客

今天写一篇关于CS客户端的SignalR通信,后台服务使用.net6api 。其实和之前写的差不多,主要在于服务端以后台进程的方式存在,而客户端以exe方式存在,其实代码都一样,只是生成的方式不一样。

 一、服务端

1.首先建立一个.net6的webapi服务端

2.Program.cs

using SignalRServerApi.Controllers;namespace SignalRServerApi
{public class Program{public static void Main(string[] args){var builder = WebApplication.CreateBuilder(args);// Add services to the container.builder.Services.AddControllers();// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbucklebuilder.Services.AddEndpointsApiExplorer();builder.Services.AddSwaggerGen();builder.Services.AddSignalR();   //增加AddSignalRstring[] urls = new[] { "http://localhost:3000" };       //此处一定要写指定的ip地址,地址是前端的ip地址,坑了我1天的时间builder.Services.AddCors(options =>options.AddDefaultPolicy(builder => builder.WithOrigins(urls).AllowAnyMethod().AllowAnyHeader().AllowCredentials()));var app = builder.Build();// Configure the HTTP request pipeline.if (app.Environment.IsDevelopment()){app.UseSwagger();app.UseSwaggerUI();}app.UseCors(); //增加跨域问题app.UseHttpsRedirection();app.UseAuthorization();app.MapControllers();app.MapHub<ChatHub>("/api/chat");  //前端访问的地址,2边要统一就行了app.Run();}}
}

3.ChatHub.cs

using Microsoft.AspNetCore.SignalR;
using System.Collections.Concurrent;namespace SignalRServerApi.Controllers
{public class ChatHub : Hub{private static Dictionary<string, string> dicUsers = new Dictionary<string, string>();public override Task OnConnectedAsync()    //登录{Console.WriteLine($"ID:{Context.ConnectionId} 已连接");   //控制台记录var cid = Context.ConnectionId;//根据id获取指定客户端var client = Clients.Client(cid);//向指定用户发送消息//client.SendAsync("Self", cid);//像所有用户发送消息Clients.All.SendAsync("ReceivePublicMessageLogin", $"{cid}加入了聊天室");        //界面显示登录return base.OnConnectedAsync();}public override Task OnDisconnectedAsync(Exception? exception)       //退出的时候{Console.WriteLine($"ID:{Context.ConnectionId} 已断开");var cid = Context.ConnectionId;//根据id获取指定客户端var client = Clients.Client(cid);//向指定用户发送消息//client.SendAsync("Self", cid);//像所有用户发送消息Clients.All.SendAsync("ReceivePublicMessageLogin", $"{cid}离开了聊天室");        //界面显示登录return base.OnDisconnectedAsync(exception);}/// <summary>/// 向所有客户端发送消息/// </summary>/// <param name="user"></param>/// <param name="message"></param>/// <returns></returns>public async Task SendPublicMessage(string user, string message){                                                     //string user,await Clients.All.SendAsync("ReceivePublicMessage", user, message);   //ReceiveMessage 提供给客户端使用}/// <summary>/// 用户登录,密码就不判断了/// </summary>/// <param name="userId"></param>public void Login(string userId)     //对应前端的invoke{if (!dicUsers.ContainsKey(userId)){dicUsers[userId] = Context.ConnectionId;}Console.WriteLine($"{userId}登录成功,ConnectionId={Context.ConnectionId}");//向所有用户发送当前在线的用户列表Clients.All.SendAsync("dicUsers", dicUsers.Keys.ToList());   //对应前端的on}public void ChatOne(string userId, string toUserId, string msg)     //用户  发送到的用户      发送的消息{string newMsg = $"{userId}对你说{msg}";//组装后的消息体//如果当前用户在线if (dicUsers.ContainsKey(toUserId)){Clients.Client(dicUsers[toUserId]).SendAsync("ChatInfo", newMsg);}else{//如果当前用户不在线,正常是保存数据库,等上线时加载,暂时不做处理}}}}

4.生成方式

选择Windows应用程序 

5.运行

运行后,服务是以进程的方式存在

6.效果

此时需要注意代码的这个地址

当然IP和端口都可以修改的,也可以增加网页显示,根据业务而定。 

二、客户端

1.首先建立一个.net6的wpf客户端

2.安装Microsoft.AspNetCore.SignalR.Client

3.建立界面

界面代码

<Window x:Class="SignalRClient.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:SignalRClient"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Grid><StackPanel Orientation="Vertical"><StackPanel Orientation="Horizontal"><TextBlock>账号:</TextBlock><TextBox Name="user" Width="300" Height="20" Margin="0,5"></TextBox></StackPanel><StackPanel Orientation="Horizontal"><TextBlock>密码:</TextBlock><TextBox Name="password" Width="300" Height="20" Margin="0,5"></TextBox></StackPanel><StackPanel Orientation="Horizontal"  ><Button Name="btnLogin" Width="50" Height="20" Margin="0,5" Click="btnLogin_Click">登录</Button></StackPanel><StackPanel Orientation="Horizontal"><TextBlock>发送给某人:</TextBlock><TextBox Name="toUser" Width="300" Height="20" Margin="0,5" ></TextBox></StackPanel><StackPanel Orientation="Horizontal"><TextBlock>发送内容:</TextBlock><TextBox Name="content" Width="300" Height="20" Margin="0,5"></TextBox></StackPanel><StackPanel Orientation="Horizontal"><Button Name="btnSendAll" Width="100" Height="20" Margin="0,5" Click="btnSendAll_Click">发送所有人</Button><Button Name="btnSendOne" Width="100" Height="20" Margin="0,5" Click="btnSendOne_Click">发送到个人</Button></StackPanel><RichTextBox Height="100" Name="rtbtxt"><FlowDocument><Paragraph><Run Text=""/></Paragraph></FlowDocument></RichTextBox></StackPanel></Grid>
</Window>

4.后台代码

using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;namespace SignalRClient
{/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{private HubConnection hubConnection;public MainWindow(){InitializeComponent();//rtbtxt.AppendText("4444");}private void btnLogin_Click(object sender, RoutedEventArgs e){//此处和VUE3界面是一样的,参照写就行了。//1.初始化InitInfo();//2.连接Link();//3.监听Listen();//4.登录Login();}/// <summary>/// 初始化/// </summary>private void InitInfo(){hubConnection = new HubConnectionBuilder().WithUrl("http://127.0.0.1:5000/api/chat", (opt) =>{opt.HttpMessageHandlerFactory = (message) =>{if (message is HttpClientHandler clientHandler)// bypass SSL certificateclientHandler.ServerCertificateCustomValidationCallback +=(sender, certificate, chain, sslPolicyErrors) => { return true; };return message;};}).WithAutomaticReconnect().Build();hubConnection.KeepAliveInterval = TimeSpan.FromSeconds(5);}List<string> LoginUser;string msgContent;/// <summary>/// 监听数据的变化/// </summary>private void Listen(){hubConnection.On<List<string>>("dicUsers", msg =>{LoginUser = msg;string s = string.Empty;foreach (string item in msg){s += item + "用户登录" + Environment.NewLine;}rtbtxt.AppendText(s);});  //匿名方法  真实环境中,此处使用的是属性变化,不要使用赋值的方式hubConnection.On<string>("ReceivePublicMessageLogin", msg => { msgContent = msg; rtbtxt.AppendText(msg + Environment.NewLine); });hubConnection.On<string, string>("ReceivePublicMessage", (user, msg) => { msgContent = msg; rtbtxt.AppendText(user + "说:" + msg + Environment.NewLine); });  //匿名方法hubConnection.On<string>("ChatInfo", msg => { msgContent = msg; rtbtxt.AppendText(msg + Environment.NewLine); });}/// <summary>/// 连接/// </summary>private async void Link(){try{await hubConnection.StartAsync();}catch (Exception ex){MessageBox.Show(ex.Message);}}private static bool ValidateCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors){// 在这里添加你的证书验证逻辑// 返回true表示验证通过,返回false表示验证失败// 例如,你可以添加自定义的证书验证逻辑来允许不受信任的证书return true;}private void Login(){hubConnection.InvokeAsync("Login", user.Text);}private void btnSendAll_Click(object sender, RoutedEventArgs e){hubConnection.InvokeAsync("SendPublicMessage", user.Text, content.Text);}private void btnSendOne_Click(object sender, RoutedEventArgs e){hubConnection.InvokeAsync("ChatOne", user.Text, toUser.Text, content.Text);}}
}

这里需要注意, 一起运行不会报错,但是单独运行会报错

The SSL connection could not be established, see inner exception

需要在初始化InitInfo()方法中增加HttpMessageHandlerFactory,即可解决。

 5.效果

此时,后台的服务以进行的方式存在,然后可以和客户端进行通信,其实和之前写的是一样的,只是生成方式不同而已。 

 源码

https://download.csdn.net/download/u012563853/88061397

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/2637.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu22.04密码忘记怎么办 Ubuntu重置root密码方法

在Ubuntu 22.04 或其他更高版本上不小心忘记root或其他账户的密码怎么办&#xff1f; 首先uname -r查看当前系统正在使用的内核版本&#xff0c;记下来 前提&#xff1a;是你的本地电脑&#xff0c;有物理访问权限。其他如远程登录的不适用这套改密方法。 通过以下步骤&#…

写字楼/办公楼能源管理系统的具体应用 安科瑞 许敏

0 引言 随着社会的进步&#xff0c;我国经济的快速发展&#xff0c;企业的办公环境和方式发生了巨大的变化&#xff0c;专业的写字楼在各大城市遍布林立。写字楼的出现使得各地企业办公集中化、高效化&#xff0c;然而写字楼物业管理的同步发展对于企业服务来说更是一个很大的…

SciencePub学术 | 区块链类重点SCIEEI征稿中

SciencePub学术 刊源推荐: 区块链类重点SCIE&EI征稿中&#xff01;信息如下&#xff0c;录满为止&#xff1a; 一、期刊概况&#xff1a; SCI-01 【期刊简介】IF&#xff1a;4.0-4.5&#xff0c;JCR2区&#xff0c;中科院3区&#xff1b; 【检索情况】SCIE&EI双检&…

Mysql+ETLCloud CDC+StarRocks实时数仓同步实战

一、业务需求及其痛点 大型企业需要对各种业务系统中的销售及营销数据进行实时同步分析&#xff0c;例如库存信息、对帐信号、会员信息、广告投放信息&#xff0c;生产进度信息等等&#xff0c;这些统计分析信息可以实时同步到StarRocks中进行分析和统计&#xff0c;StarRocks…

vue注意点:$attrs、$slots!插槽

$attrs 当父组件给子组件传值&#xff0c;子组件并没有接收数据时&#xff0c;此时数据在$attrs中可以拿到&#xff0c;并且如果子组件不需要使用数据&#xff0c;而孙组件需要&#xff0c;则可以直接v-bind"$attrs"传给孙。 <-- 父组件 --> <div><…

[java安全]URLDNS

文章目录 [java安全]URLDNS前言HashMapURLURLStreamHandler调用过程调用链流程图POC [java安全]URLDNS 前言 URLDNS利用链是一条很简单的链子&#xff0c;可以用来查看java反序列化是否存在反序列化漏洞&#xff0c;如果存在&#xff0c;就会触发dns查询请求 它有如下优点&a…

Centos 8 / TencentOS Server 3.1 安装 docker-ce

目录 前言安装 docker-ce设置Docker Hub 镜像缓存参考 前言 TencentOS Server 3.1(与 CentOS 8用户态完全兼容&#xff0c;配套基于社区5.4 LTS 内核深度优化的 tkernel4版本) 安装 docker-ce 先卸载老版本&#xff0c;没有老版本的跳过 yum remove docker \docker-client \d…

常见面试题之HashMap

1. 二叉树 1.1 二叉树概述 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只有左子节点&#xff0c;有的节…

前端基本功 用 React Hooks + Antd 实现一个 Todo-List

背景 使用 React Hooks 以及组件库 Antd 来实现一个可以 增删 标记是否完成 的 todo-list 思路 要实现一个 todo-list 首先想到用 useState 维护一个状态数组来保存当前 list &#xff0c;还要用一个状态维护添加框中的内容 const [todos, setTodos] useState(initialValu…

Excel之VLOOKUP()函数介绍

Excel之VLOOKUP()函数介绍 Excel的VLOOKUP函数语法&#xff1a; VLOOKUP(lookup_value, table_array, col_index_num, [range_lookup]) 参数说明&#xff1a; lookup_value&#xff1a;要查找的值或要比较的值。 table_array&#xff1a;包含要在其中进行查找的数据表的区…

解决打开excel时报错 “不能使用对象链接和嵌入”

问题截图 打开excel文件或者插入对象时&#xff0c;直接弹出不能使用对象链接和嵌入报错信息。 解决方法 按 winr 组合快捷键&#xff0c;打开运行&#xff0c;输入 dcomcnfg.exe 按回车确定 此时进入到组件服务管理界面&#xff0c;依次选择 组件服务-计算机-我的电脑-DOCM…

S3C2440点亮LED(裸机开发)

文章目录 前言一、环境介绍一、GPIO介绍二、点亮开发板的LED1.预备动作2.led代码 总结 前言 本期和大家主要分享的是使用S3C2440开发板点亮一个LED灯&#xff0c;可能大家拿到开发板之后做的第一件事情都是点灯&#xff0c;这是为什么呢&#xff1f;因为点灯这件事情不仅能够检…

Linux搭建node环境-MobaXterm+node+pm2安装

1.登录session 2.安装X11-forwarding 我也不知道这个有什么用&#xff0c;但是有个叉叉在那里有点难受&#xff0c;就把它解决了什么是X11-forwarding&#xff1f;怎么使用&#xff1f; yum install xorg-x11-xauth xorg-x11-fonts-* xorg-x11-font-utils xorg-x11-fonts-Ty…

redis 和mongodb基础操作练习

目录 redis作业 string、list、hash 数据类型 举例说明list和hash的应用场景&#xff0c;每个至少一个场景 mongodb作业 1. 创建一个数据库 名字grade 2. 数据库中创建一个集合名字 class 3. 集合中插入若干数据 文档格式如下 4. 查找 5. 增加、更新、删除、统计 re…

HTTP1和HTTP2和HTTP3的区别

超文本传输协议是一个简单的请求-响应协议&#xff0c;它通常运行在TCP之上。 目录 HTTP1.1&#xff1a; HTTP2 HTTP3 参考文献 HTTP1.1&#xff1a; 特点&#xff1a; &#xff11;.一条链接只能一次请求一次返回这样子来回。一般的我们浏览器会帮我们一次次请求和收到。…

第八十八回:创建一个调色板

文章目录 概念介绍实现方法整体思路具体步骤 示例代码 我们在上一章回中介绍了打印日志相关的内容&#xff0c;本章回中将介绍 如何创建一个调色板.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在本章回中介绍的调色板是一个具有各种颜色的窗口&#xff0c…

EDM营销过时了?不,这才是跨境电商成功的最佳工具

根据最近的一项研究&#xff0c;电子邮件仍然是最具说服力的营销工具和沟通形式之一。虽然即时通讯等其他渠道正在扎根&#xff0c;但电子邮件仍然是影响最深远的商业交流形式。到2023年&#xff0c;每天发送和接收的电子邮件总数可能会超过333亿封。所以&#xff0c;如果您希望…

iOS 中支持点击网页scheme超链接打开其他app

网页内容如图所示 思路&#xff0c;点击网页中一个href 超链接的时候&#xff0c;会执行 decidePolicyForNavigationAction 方法&#xff0c;我们在改方法中截获URL&#xff0c; 判断如果是URL scheme类型的&#xff0c;则执行 [[UIApplication sharedApplication]openURL:URL…

XUbuntu22.04之vim无法复制内容到系统(一百八十四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

牛客小白月赛75题解

C 豆子 构造题 由构造公式知 第n级好豆子 第n-1级坏豆子^1 所以只需要构造一个豆子结构就行 第 i 级豆子 第 i 级豆子 第 i 级豆子 第 i 级豆子 第 i 级豆子 ^ 1 第i级豆子\begin{aligned} 第i级豆子 && 第i级豆子 \\ 第i级豆子 && 第i级豆子 \verb|^| 1 …