当前位置:   article > 正文

.net6API使用SignalR+vue3聊天+WPF聊天_signalr vue3

signalr vue3

目录

一、.net6api接口

二、vue3前端

三、WPF客户端


此案例分为3部分。首先创建.net6api接口,然后使用前端vue3进行聊天,再使用wpf客户端进行聊天,并且互通聊天。

一、.net6api接口

1.首先建立一个能正常运行的api,然后增加ChatHub

2.ChatHub.cs代码

其中注释已经写了,目前的功能是全部发送消息和1对1发送消息,也可以建立组,进行组发送消息。

官网参考

使用 ASP.NET Core SignalR 中的中心 | Microsoft Learn

ASP.NET Core SignalR JavaScript 客户端 | Microsoft Learn

  1. using Microsoft.AspNetCore.SignalR;
  2. using System.Security.Cryptography;
  3. namespace SignalRApi.Controllers
  4. {
  5. public class ChatHub : Hub
  6. {
  7. private static Dictionary<string, string> dicUsers = new Dictionary<string, string>();
  8. public override Task OnConnectedAsync() //登录
  9. {
  10. Console.WriteLine($"ID:{Context.ConnectionId} 已连接"); //控制台记录
  11. var cid = Context.ConnectionId;
  12. //根据id获取指定客户端
  13. var client = Clients.Client(cid);
  14. //向指定用户发送消息
  15. //client.SendAsync("Self", cid);
  16. //像所有用户发送消息
  17. Clients.All.SendAsync("ReceivePublicMessageLogin", $"{cid}加入了聊天室"); //界面显示登录
  18. return base.OnConnectedAsync();
  19. }
  20. public override Task OnDisconnectedAsync(Exception? exception) //退出的时候
  21. {
  22. Console.WriteLine($"ID:{Context.ConnectionId} 已断开");
  23. var cid = Context.ConnectionId;
  24. //根据id获取指定客户端
  25. var client = Clients.Client(cid);
  26. //向指定用户发送消息
  27. //client.SendAsync("Self", cid);
  28. //像所有用户发送消息
  29. Clients.All.SendAsync("ReceivePublicMessageLogin", $"{cid}离开了聊天室"); //界面显示登录
  30. return base.OnDisconnectedAsync(exception);
  31. }
  32. /// <summary>
  33. /// 向所有客户端发送消息
  34. /// </summary>
  35. /// <param name="user"></param>
  36. /// <param name="message"></param>
  37. /// <returns></returns>
  38. public async Task SendPublicMessage(string user, string message)
  39. { //string user,
  40. await Clients.All.SendAsync("ReceivePublicMessage", user, message); //ReceiveMessage 提供给客户端使用
  41. }
  42. /// <summary>
  43. /// 用户登录,密码就不判断了
  44. /// </summary>
  45. /// <param name="userId"></param>
  46. public void Login(string userId) //对应前端的invoke
  47. {
  48. if (!dicUsers.ContainsKey(userId))
  49. {
  50. dicUsers[userId] = Context.ConnectionId;
  51. }
  52. Console.WriteLine($"{userId}登录成功,ConnectionId={Context.ConnectionId}");
  53. //向所有用户发送当前在线的用户列表
  54. Clients.All.SendAsync("dicUsers", dicUsers.Keys.ToList()); //对应前端的on
  55. }
  56. public void ChatOne(string userId, string toUserId, string msg) //用户 发送到的用户 发送的消息
  57. {
  58. string newMsg = $"{userId}对你说{msg}";//组装后的消息体
  59. //如果当前用户在线
  60. if (dicUsers.ContainsKey(toUserId))
  61. {
  62. Clients.Client(dicUsers[toUserId]).SendAsync("ChatInfo", newMsg);
  63. }
  64. else
  65. {
  66. //如果当前用户不在线,正常是保存数据库,等上线时加载,暂时不做处理
  67. }
  68. }
  69. }
  70. }

3.Program.cs代码

一定要写指定的ip地址,否则报错

Cannot send data if the connection is not in the 'Connected' State 

  

  1. using SignalRApi.Controllers;
  2. var builder = WebApplication.CreateBuilder(args);
  3. // Add services to the container.
  4. builder.Services.AddControllers();
  5. // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
  6. builder.Services.AddEndpointsApiExplorer();
  7. builder.Services.AddSwaggerGen();
  8. builder.Services.AddSignalR(); //增加AddSignalR
  9. string[] urls = new[] { "http://localhost:3000" }; //此处一定要写指定的ip地址,地址是前端的ip地址,坑了我1天的时间
  10. builder.Services.AddCors(options =>
  11. options.AddDefaultPolicy(builder => builder.WithOrigins(urls)
  12. .AllowAnyMethod().AllowAnyHeader().AllowCredentials())
  13. );
  14. var app = builder.Build();
  15. // Configure the HTTP request pipeline.
  16. if (app.Environment.IsDevelopment())
  17. {
  18. app.UseSwagger();
  19. app.UseSwaggerUI();
  20. }
  21. app.UseCors(); //增加跨域问题
  22. app.UseHttpsRedirection();
  23. app.UseAuthorization();
  24. app.MapControllers();
  25. app.MapHub<ChatHub>("/api/chat"); //前端访问的地址,2边要统一就行了
  26. app.Run();

4.效果

控制器不取消的话,如图所示

地址后面增加字符串,弹框如下,那么api就算是完成了 

补充说明:如果调试的时候可以使用,实际用的时候,发布Nginx,或者IIS,其中iis要下载安装运行时。

二、vue3前端

1.首先使用HBuilder X建立一个可以运行的vue3程序

然后安装下面@microsoft/signalr,不需要安装@aspnet/signalr,因为前者更加新,后者已经淘汰了。

  1. npm init -y
  2. npm install @microsoft/signalr

2.代码

ui 界面随便做一下,主要看效果就行了

  1. <template>
  2. <el-input v-model="userid" :disabled="isdisabled" placeholder="输入账号" />
  3. <el-input v-model="password" :disabled="isdisabled" placeholder="输入密码" />
  4. <el-button type="primary" :disabled="isdisabled" @click="Login">登录</el-button>
  5. <div>
  6. <ul>
  7. <li v-for="user in LoginUser">{{user}}用户登录</li>
  8. </ul>
  9. </div>
  10. <el-input v-model="sendUserid" :disabled="!isdisabled" placeholder="发送给某人" />
  11. <el-input v-model="sendContent" :disabled="!isdisabled" placeholder="发送内容" />
  12. <el-button type="primary" :disabled="!isdisabled" @click="SendAll">发送所有人</el-button>
  13. <el-button type="primary" :disabled="!isdisabled" @click="SendUser">发送到个人</el-button>
  14. <div>
  15. <ul>
  16. <li v-for="user in msgContent">{{user}}</li>
  17. </ul>
  18. </div>
  19. <!-- <input type="text" v-model="state.userMessage" v-on:keypress="txtMsgOnkeypress" />
  20. <div>
  21. <ul>
  22. <li v-for="(msg,index) in state.messages" :key="index">{{msg}}</li>
  23. </ul>
  24. </div>
  25. <el-button type="primary">发送</el-button>
  26. <el-button type="success">Success</el-button>
  27. <el-button type="info">Info</el-button>
  28. <el-button type="warning">Warning</el-button>
  29. <el-button type="danger">Danger</el-button> -->
  30. </template>
  31. <script setup>
  32. import {
  33. ref
  34. } from 'vue'
  35. import {
  36. reactive,
  37. onMounted
  38. } from 'vue'
  39. import * as signalR from '@microsoft/signalr'
  40. defineProps({
  41. msg: String
  42. })
  43. var connection
  44. const LoginUser = ref([])
  45. const msgContent = reactive([])
  46. const isdisabled = ref(false)
  47. const userid = ref('')
  48. const password = ref('')
  49. const sendUserid = ref('')
  50. const sendContent = ref('')
  51. const Login = async () => {
  52. connection = new signalR.HubConnectionBuilder()
  53. .withUrl(' http://127.0.0.1:5196/api/chat') //这里一定要写指定的ip,否则报错,大坑搞了1天的时间
  54. .withAutomaticReconnect().build();
  55. await connection.start();
  56. connection.on('dicUsers', msg => { //监听用户登录的信息,前后端要一致
  57. console.log(msg)
  58. LoginUser.value = msg
  59. console.log(LoginUser.value)
  60. });
  61. connection.on('ReceivePublicMessageLogin', (Loginmsg) => { //监听登录的信息,前后端要一致
  62. console.log(Loginmsg)
  63. msgContent.push(Loginmsg)
  64. console.log(msgContent.value)
  65. console.log('aaa')
  66. });
  67. connection.on('ReceivePublicMessage', (user, msg) => { //监听发送的信息,前后端要一致
  68. console.log(user)
  69. console.log(msg)
  70. msgContent.push(user + "说:" + msg)
  71. console.log(msgContent.value)
  72. console.log('bbb')
  73. });
  74. connection.on('ChatInfo', msg => { //监听单独发送的信息,前后端要一致
  75. console.log("单独说:" + msg)
  76. msgContent.push("单独说:" + msg)
  77. console.log("单独说:" + msgContent.value)
  78. console.log('ccc')
  79. });
  80. await connection.invoke("Login", userid.value); //发送消息
  81. // connection.on('ReceivePublicMessage', msg => {
  82. // state.messages.push(msg); //监听发送的信息,前后端要一致
  83. // });
  84. isdisabled.value = true
  85. console.log('wewew')
  86. }
  87. const SendAll = async () => {
  88. console.log(userid.value)
  89. console.log(sendContent.value)
  90. await connection.invoke("SendPublicMessage", userid.value, sendContent.value); //发送消息
  91. console.log('zxzx')
  92. }
  93. const SendUser = async () => {
  94. console.log(sendContent.value)
  95. await connection.invoke("ChatOne", userid.value, sendUserid.value, sendContent.value); //发送消息
  96. console.log('55fff')
  97. }
  98. // onMounted(async function() {
  99. // connection = new signalR.HubConnectionBuilder()
  100. // .withUrl(' http://127.0.0.1:5196/api/chat') //这里一定要写指定的ip,否则报错,大坑搞了1天的时间
  101. // .withAutomaticReconnect().build();
  102. // await connection.start();
  103. // connection.on('ReceivePublicMessage', msg => {
  104. // state.messages.push(msg);
  105. // });
  106. // });
  107. </script>
  108. <style scoped>
  109. a {
  110. color: #42b983;
  111. }
  112. </style>

3.运行效果

此时把api运行起来,然后运行vue3项目。

可以1对所有人说,也可以1对1说

三、WPF客户端

1.首先建立一个wpf程序,其实winform也可以

为了简单,wpf就不使用mvvm的方式了,只为实现效果

2.安装Microsoft.AspNetCore.SignalR.Client

3.建立界面

为了方便简单,界面按照vue3的界面做

界面代码 

  1. <Window x:Class="SignalRWPF.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:local="clr-namespace:SignalRWPF"
  7. mc:Ignorable="d"
  8. Title="MainWindow" Height="450" Width="800">
  9. <Grid>
  10. <StackPanel Orientation="Vertical">
  11. <StackPanel Orientation="Horizontal">
  12. <TextBlock>账号:</TextBlock>
  13. <TextBox Name="user" Width="300" Height="20" Margin="0,5"></TextBox>
  14. </StackPanel>
  15. <StackPanel Orientation="Horizontal">
  16. <TextBlock>密码:</TextBlock>
  17. <TextBox Name="password" Width="300" Height="20" Margin="0,5"></TextBox>
  18. </StackPanel>
  19. <StackPanel Orientation="Horizontal" >
  20. <Button Name="btnLogin" Width="50" Height="20" Margin="0,5" Click="btnLogin_Click">登录</Button>
  21. </StackPanel>
  22. <StackPanel Orientation="Horizontal">
  23. <TextBlock>发送给某人:</TextBlock>
  24. <TextBox Name="toUser" Width="300" Height="20" Margin="0,5" ></TextBox>
  25. </StackPanel>
  26. <StackPanel Orientation="Horizontal">
  27. <TextBlock>发送内容:</TextBlock>
  28. <TextBox Name="content" Width="300" Height="20" Margin="0,5"></TextBox>
  29. </StackPanel>
  30. <StackPanel Orientation="Horizontal">
  31. <Button Name="btnSendAll" Width="100" Height="20" Margin="0,5" Click="btnSendAll_Click">发送所有人</Button>
  32. <Button Name="btnSendOne" Width="100" Height="20" Margin="0,5" Click="btnSendOne_Click">发送到个人</Button>
  33. </StackPanel>
  34. <RichTextBox Height="100" Name="rtbtxt">
  35. <FlowDocument>
  36. <Paragraph>
  37. <Run Text=""/>
  38. </Paragraph>
  39. </FlowDocument>
  40. </RichTextBox>
  41. </StackPanel>
  42. </Grid>
  43. </Window>

后台代码,此处代码可以看vue3怎么调用的就行了,照猫画虎即可,这只是普通的写法,还可以使用属性变化,加上MVVM。

  1. using Microsoft.AspNetCore.SignalR.Client;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using System.Windows;
  8. using System.Windows.Controls;
  9. using System.Windows.Data;
  10. using System.Windows.Documents;
  11. using System.Windows.Input;
  12. using System.Windows.Interop;
  13. using System.Windows.Media;
  14. using System.Windows.Media.Imaging;
  15. using System.Windows.Navigation;
  16. using System.Windows.Shapes;
  17. namespace SignalRWPF
  18. {
  19. /// <summary>
  20. /// Interaction logic for MainWindow.xaml
  21. /// </summary>
  22. public partial class MainWindow : Window
  23. {
  24. private HubConnection hubConnection;
  25. public MainWindow()
  26. {
  27. InitializeComponent();
  28. //rtbtxt.AppendText("4444");
  29. }
  30. private void btnLogin_Click(object sender, RoutedEventArgs e)
  31. {
  32. //此处和VUE3界面是一样的,参照写就行了。
  33. //1.初始化
  34. InitInfo();
  35. //2.连接
  36. Link();
  37. //3.监听
  38. Listen();
  39. //4.登录
  40. Login();
  41. }
  42. /// <summary>
  43. /// 初始化
  44. /// </summary>
  45. private void InitInfo()
  46. {
  47. hubConnection = new HubConnectionBuilder().WithUrl("http://127.0.0.1:5196/api/chat").WithAutomaticReconnect().Build();
  48. hubConnection.KeepAliveInterval = TimeSpan.FromSeconds(5);
  49. }
  50. List<string> LoginUser;
  51. string msgContent;
  52. /// <summary>
  53. /// 监听数据的变化
  54. /// </summary>
  55. private void Listen()
  56. {
  57. hubConnection.On<List<string>>("dicUsers", msg =>
  58. {
  59. LoginUser = msg;
  60. string s = string.Empty;
  61. foreach (string item in msg)
  62. {
  63. s += item + "用户登录" + Environment.NewLine;
  64. }
  65. rtbtxt.AppendText(s);
  66. }); //匿名方法 真实环境中,此处使用的是属性变化,不要使用赋值的方式
  67. hubConnection.On<string>("ReceivePublicMessageLogin", msg => { msgContent = msg; rtbtxt.AppendText(msg + Environment.NewLine); });
  68. hubConnection.On<string, string>("ReceivePublicMessage", (user, msg) => { msgContent = msg; rtbtxt.AppendText(user + "说:" + msg + Environment.NewLine); }); //匿名方法
  69. hubConnection.On<string>("ChatInfo", msg => { msgContent = msg; rtbtxt.AppendText(msg + Environment.NewLine); });
  70. }
  71. /// <summary>
  72. /// 连接
  73. /// </summary>
  74. private async void Link()
  75. {
  76. try
  77. {
  78. await hubConnection.StartAsync();
  79. }
  80. catch (Exception ex)
  81. {
  82. MessageBox.Show(ex.Message);
  83. }
  84. }
  85. private void Login()
  86. {
  87. hubConnection.InvokeAsync("Login", user.Text);
  88. }
  89. private void btnSendAll_Click(object sender, RoutedEventArgs e)
  90. {
  91. hubConnection.InvokeAsync("SendPublicMessage", user.Text, content.Text);
  92. }
  93. private void btnSendOne_Click(object sender, RoutedEventArgs e)
  94. {
  95. hubConnection.InvokeAsync("ChatOne", user.Text, toUser.Text, content.Text);
  96. }
  97. }
  98. }

4.效果

同时打开api,打开2个窗体,然后进行对话。 

至此,所有代码就完成了,那么我们把api,vue,wpf都运行起来,然后进行聊天演示。

源码:

https://gitee.com/602874946/signal-rs

来源:

.net6API使用SignalR+vue3聊天+WPF聊天_.net6 signalr-CSDN博客

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/761353
推荐阅读
相关标签
  

闽ICP备14008679号