之前寫的SignalR通信,是基于.net6api,BS和CS進行通信的。
.net6API使用SignalR+vue3聊天+WPF聊天_signalr wpf_故里2130的博客-CSDN博客
今天寫一篇關(guān)于CS客戶端的SignalR通信,后臺服務(wù)使用.net6api?。其實和之前寫的差不多,主要在于服務(wù)端以后臺進程的方式存在,而客戶端以exe方式存在,其實代碼都一樣,只是生成的方式不一樣。
?一、服務(wù)端
1.首先建立一個.net6的webapi服務(wù)端
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<ChatHub>("/api/chat"); //前端訪問的地址,2邊要統(tǒng)一就行了
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;
//根據(jù)id獲取指定客戶端
var client = Clients.Client(cid);
//向指定用戶發(fā)送消息
//client.SendAsync("Self", cid);
//像所有用戶發(fā)送消息
Clients.All.SendAsync("ReceivePublicMessageLogin", $"{cid}加入了聊天室"); //界面顯示登錄
return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception? exception) //退出的時候
{
Console.WriteLine($"ID:{Context.ConnectionId} 已斷開");
var cid = Context.ConnectionId;
//根據(jù)id獲取指定客戶端
var client = Clients.Client(cid);
//向指定用戶發(fā)送消息
//client.SendAsync("Self", cid);
//像所有用戶發(fā)送消息
Clients.All.SendAsync("ReceivePublicMessageLogin", $"{cid}離開了聊天室"); //界面顯示登錄
return base.OnDisconnectedAsync(exception);
}
/// <summary>
/// 向所有客戶端發(fā)送消息
/// </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) //對應(yīng)前端的invoke
{
if (!dicUsers.ContainsKey(userId))
{
dicUsers[userId] = Context.ConnectionId;
}
Console.WriteLine($"{userId}登錄成功,ConnectionId={Context.ConnectionId}");
//向所有用戶發(fā)送當(dāng)前在線的用戶列表
Clients.All.SendAsync("dicUsers", dicUsers.Keys.ToList()); //對應(yīng)前端的on
}
public void ChatOne(string userId, string toUserId, string msg) //用戶 發(fā)送到的用戶 發(fā)送的消息
{
string newMsg = $"{userId}對你說{msg}";//組裝后的消息體
//如果當(dāng)前用戶在線
if (dicUsers.ContainsKey(toUserId))
{
Clients.Client(dicUsers[toUserId]).SendAsync("ChatInfo", newMsg);
}
else
{
//如果當(dāng)前用戶不在線,正常是保存數(shù)據(jù)庫,等上線時加載,暫時不做處理
}
}
}
}
4.生成方式
選擇Windows應(yīng)用程序?
5.運行
運行后,服務(wù)是以進程的方式存在
6.效果
此時需要注意代碼的這個地址
當(dāng)然IP和端口都可以修改的,也可以增加網(wǎng)頁顯示,根據(jù)業(yè)務(wù)而定。?
二、客戶端
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>發(fā)送給某人:</TextBlock>
<TextBox Name="toUser" Width="300" Height="20" Margin="0,5" ></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock>發(fā)送內(nèi)容:</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">發(fā)送所有人</Button>
<Button Name="btnSendOne" Width="100" Height="20" Margin="0,5" Click="btnSendOne_Click">發(fā)送到個人</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.監(jiān)聽
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 certificate
clientHandler.ServerCertificateCustomValidationCallback +=
(sender, certificate, chain, sslPolicyErrors) => { return true; };
return message;
};
}).WithAutomaticReconnect().Build();
hubConnection.KeepAliveInterval = TimeSpan.FromSeconds(5);
}
List<string> LoginUser;
string msgContent;
/// <summary>
/// 監(jiān)聽數(shù)據(jù)的變化
/// </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);
}); //匿名方法 真實環(huán)境中,此處使用的是屬性變化,不要使用賦值的方式
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.效果
此時,后臺的服務(wù)以進行的方式存在,然后可以和客戶端進行通信,其實和之前寫的是一樣的,只是生成方式不同而已。?
?源碼
https://download.csdn.net/download/u012563853/88061397文章來源:http://www.zghlxwxcb.cn/news/detail-586906.html
來源:基于.net6的WPF程序使用SignalR進行通信-CSDN博客文章來源地址http://www.zghlxwxcb.cn/news/detail-586906.html
到了這里,關(guān)于基于.net6的WPF程序使用SignalR進行通信的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!