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

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

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

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

 一、服务端

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

基于.net6的WPF程序使用SignalR进行通信_第1张图片

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/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();
            builder.Services.AddSignalR();   //增加AddSignalR
            string[] 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("/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 dicUsers = new Dictionary();
        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);
        }
        /// 
        /// 向所有客户端发送消息
        /// 
        /// 
        /// 
        /// 
        public async Task SendPublicMessage(string user, string message)
        {                                                     //string user,
            await Clients.All.SendAsync("ReceivePublicMessage", user, message);   //ReceiveMessage 提供给客户端使用
        }

        /// 
        /// 用户登录,密码就不判断了
        /// 
        /// 
        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应用程序 

基于.net6的WPF程序使用SignalR进行通信_第2张图片

5.运行

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

基于.net6的WPF程序使用SignalR进行通信_第3张图片

6.效果

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

基于.net6的WPF程序使用SignalR进行通信_第4张图片

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

二、客户端

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

基于.net6的WPF程序使用SignalR进行通信_第5张图片

2.安装Microsoft.AspNetCore.SignalR.Client

3.建立界面

界面代码


    
        
            
                账号:
                
            
            
                密码:
                
            
            
                
            
            
                发送给某人:
                
            
            
                发送内容:
                
            
            
                
                
            
            
                
                    
                        
                    
                
            
        
    

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
{
    /// 
    /// Interaction logic for MainWindow.xaml
    /// 
    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();


        }
        /// 
        /// 初始化
        /// 
        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 certificate
                        clientHandler.ServerCertificateCustomValidationCallback +=
                            (sender, certificate, chain, sslPolicyErrors) => { return true; };
                    return message;
                };

            }).WithAutomaticReconnect().Build();
            hubConnection.KeepAliveInterval = TimeSpan.FromSeconds(5);
        }
        List LoginUser;
        string msgContent;

        /// 
        /// 监听数据的变化
        /// 
        private void Listen()
        {
            hubConnection.On>("dicUsers", msg =>
            {
                LoginUser = msg;
                string s = string.Empty;
                foreach (string item in msg)
                {
                    s += item + "用户登录" + Environment.NewLine;
                }
                rtbtxt.AppendText(s);


            });  //匿名方法  真实环境中,此处使用的是属性变化,不要使用赋值的方式
            hubConnection.On("ReceivePublicMessageLogin", msg => { msgContent = msg; rtbtxt.AppendText(msg + Environment.NewLine); });
            hubConnection.On("ReceivePublicMessage", (user, msg) => { msgContent = msg; rtbtxt.AppendText(user + "说:" + msg + Environment.NewLine); });  //匿名方法
            hubConnection.On("ChatInfo", msg => { msgContent = msg; rtbtxt.AppendText(msg + Environment.NewLine); });
        }

        /// 
        /// 连接
        /// 
        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.效果

基于.net6的WPF程序使用SignalR进行通信_第6张图片

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

 源码

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

你可能感兴趣的:(C#,.net,wpf)