WPF+ASP.NET SignalR实现简易在线聊天功能

这篇具有很好参考价值的文章主要介绍了WPF+ASP.NET SignalR实现简易在线聊天功能。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在实际业务中,当后台数据发生变化,客户端能够实时的收到通知,而不是由用户主动的进行页面刷新才能查看,这将是一个非常人性化的设计。有没有那么一种场景,后台数据明明已经发生变化了,前台却因为没有及时刷新,而导致页面显示的数据与实际存在差异,从而造成错误的判断。那么如何才能在后台数据变更时及时通知客户端呢?本文以一个简单的聊天示例,简述如何通过WPF+ASP.NET SignalR实现消息后台通知,仅供学习分享使用,如有不足之处,还请指正。

涉及知识点


在本示例中,涉及知识点如下所示:

  1. 开发工具:Visual Studio 2022 目标框架:.NET6.0
  2. ASP.NET SignalR,一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信,目前新版已支持.NET6.0及以上版本。在本示例中,作为消息通知的服务端。
  3. WPF,是微软推出的基于Windows 的用户界面框架,主要用于开发客户端程序。

什么是ASP.NET SignalR?


ASP.NET SignalR 是一个面向 ASP.NET 开发人员的库,可简化将实时 web 功能添加到应用程序的过程。 实时 web 功能是让服务器代码将内容推送到连接的客户端立即可用,而不是让服务器等待客户端请求新数据的能力。

WPF+ASP.NET SignalR实现简易在线聊天功能

SignalR 提供了一个简单的 API,用于创建服务器到客户端远程过程调用 (RPC) ,该调用客户端浏览器 (和其他客户端平台中的 JavaScript 函数) 服务器端 .NET 代码。 SignalR 还包括用于连接管理的 API (,例如连接和断开连接事件) ,以及分组连接。

WPF+ASP.NET SignalR实现简易在线聊天功能

虽然聊天通常被用作示例,但你可以做更多的事情。每当用户刷新网页以查看新数据时,或者该网页实施 Ajax 长轮询以检索新数据时,它都是使用 SignalR 的候选者。SignalR 还支持需要从服务器进行高频更新的全新类型的应用,例如实时游戏。

在线聊天整体架构


在线聊天示例,主要分为服务端(ASP.NET Web API)和客户端(WPF可执行程序)。具体如下所示:

WPF+ASP.NET SignalR实现简易在线聊天功能

ASP.NET SignalR在线聊天服务端


服务端主要实现消息的接收,转发等功能,具体步骤如下所示:

1. 创建ASP.NET Web API项目

首先创建ASP.NET Web API项目,默认情况下SignalR已经作为项目框架的一部分而存在,所以不需要安装,直接使用即可。通过项目--依赖性--框架--Microsoft.AspNetCore.App可以查看,如下所示

WPF+ASP.NET SignalR实现简易在线聊天功能

2. 创建消息通知中心Hub

在项目中新建Chat文件夹,然后创建ChatHub类,并继承Hub基类。主要包括登录(Login),聊天(Chat)等功能。如下所示:

using Microsoft.AspNetCore.SignalR;

namespace SignalRChat.Chat
{
    public class ChatHub:Hub
    {
        private static Dictionary<string,string> dictUsers = new Dictionary<string,string>();


        public override Task OnConnectedAsync()
        {
            Console.WriteLine($"ID:{Context.ConnectionId} 已连接");
            return base.OnConnectedAsync();
        }

        public override Task OnDisconnectedAsync(Exception? exception)
        {
            Console.WriteLine($"ID:{Context.ConnectionId} 已断开");
            return base.OnDisconnectedAsync(exception);
        }

        /// <summary>
        /// 向客户端发送信息
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public Task Send(string msg) {
            return Clients.Caller.SendAsync("SendMessage",msg);
        }

        /// <summary>
        /// 登录功能,将用户ID和ConntectionId关联起来
        /// </summary>
        /// <param name="userId"></param>
        public void Login(string userId) {
            if (!dictUsers.ContainsKey(userId)) {
                dictUsers[userId] = Context.ConnectionId;
            }
            Console.WriteLine($"{userId}登录成功,ConnectionId={Context.ConnectionId}");
            //向所有用户发送当前在线的用户列表
            Clients.All.SendAsync("Users", dictUsers.Keys.ToList());
        }

        /// <summary>
        /// 一对一聊天
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="targetUserId"></param>
        /// <param name="msg"></param>
        public void Chat(string userId, string targetUserId, string msg)
        {
            string newMsg = $"{userId}|{msg}";//组装后的消息体
            //如果当前用户在线
            if (dictUsers.ContainsKey(targetUserId))
            {
                Clients.Client(dictUsers[targetUserId]).SendAsync("ChatInfo",newMsg);
            }
            else {
                //如果当前用户不在线,正常是保存数据库,等上线时加载,暂时不做处理
            }
        }

        /// <summary>
        /// 退出功能,当客户端退出时调用
        /// </summary>
        /// <param name="userId"></param>
        public void Logout(string userId)
        {
            if (dictUsers.ContainsKey(userId))
            {
                dictUsers.Remove(userId);
            }
            Console.WriteLine($"{userId}退出成功,ConnectionId={Context.ConnectionId}");
        }
    }
}

3. 注册服务和路由

聊天类创建成功后,需要配置服务注入和路由,在Program中,添加代码,如下所示:

using SignalRChat.Chat;

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();
//1.添加SignalR服务
builder.Services.AddSignalR();
var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseRouting();
app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();
//2.映射路由
app.UseEndpoints(endpoints => {
    endpoints.MapHub<ChatHub>("/chat");
});

app.Run();

4. ASP.NET SignalR中心对象生存周期

你不会实例化 Hub 类或从服务器上自己的代码调用其方法;由 SignalR Hubs 管道为你完成的所有操作。 SignalR 每次需要处理中心操作(例如客户端连接、断开连接或向服务器发出方法调用时)时,SignalR 都会创建 Hub 类的新实例。

由于 Hub 类的实例是暂时性的,因此无法使用它们来维护从一个方法调用到下一个方法的状态。 每当服务器从客户端收到方法调用时,中心类的新实例都会处理消息。 若要通过多个连接和方法调用来维护状态,请使用一些其他方法(例如数据库)或 Hub 类上的静态变量,或者不派生自 Hub的其他类。 如果在内存中保留数据,请使用 Hub 类上的静态变量等方法,则应用域回收时数据将丢失。

如果要从在 Hub 类外部运行的代码将消息发送到客户端,则无法通过实例化 Hub 类实例来执行此操作,但可以通过获取对 Hub 类的 SignalR 上下文对象的引用来执行此操作。

注意:ChatHub每次调用都是一个新的实例,所以不可以有私有属性或变量,不可以保存对像的值,所以如果需要记录一些持久保存的值,则可以采用静态变量,或者中心以外的对象。

SignalR客户端


1. 安装SignalR客户端依赖库

客户端如果要调用SignalR的值,需要通过NuGet包管理器,安装SignalR客户端,如下所示:

WPF+ASP.NET SignalR实现简易在线聊天功能

2. 客户端消息接收发送

在客户端实现消息的接收和发送,主要通过HubConntection实现,核心代码,如下所示:

namespace SignalRClient
{
    public class ChatViewModel:ObservableObject
    {
        #region 属性及构造函数

        private string targetUserName;

        public string TargetUserName
        {
            get { return targetUserName; }
            set { SetProperty(ref targetUserName , value); }
        }


        private string userName;

        public string UserName
        {
            get { return userName; }
            set
            {
                SetProperty(ref userName, value);
                Welcome = $"欢迎 {value} 来到聊天室";
            }
        }

        private string welcome;

        public string Welcome
        {
            get { return welcome; }
            set { SetProperty(ref welcome , value); }
        }

        private List<string> users;

        public List<string> Users
        {
            get { return users; }
            set {SetProperty(ref users , value); }
        }

        private RichTextBox richTextBox;

        private HubConnection hubConnection;

        public ChatViewModel() {

        }

        #endregion

        #region 命令

        private ICommand loadedCommand;

        public ICommand LoadedCommand
        {
            get
            {
                if (loadedCommand == null)
                {
                    loadedCommand = new RelayCommand<object>(Loaded);
                }
                return loadedCommand;
            }
        }

        private void Loaded(object obj)
        {
            //1.初始化
            InitInfo();
            //2.监听
            Listen();
            //3.连接
            Link();
            //4.登录
            Login();
            //
            if (obj != null) {
                var eventArgs = obj as RoutedEventArgs;

                var window= eventArgs.OriginalSource as ChatWindow;
                this.richTextBox = window.richTextBox;
            }
        }

        private IRelayCommand<string> sendCommand;

        public IRelayCommand<string> SendCommand
        {
            get {
                if (sendCommand == null) {
                    sendCommand = new RelayCommand<string>(Send);
                }
                return sendCommand; }
        }

        private void Send(string msg)
        {
            if (string.IsNullOrEmpty(msg)) {
                MessageBox.Show("发送的消息为空");
                return;
            }
            if (string.IsNullOrEmpty(this.TargetUserName)) {
                MessageBox.Show("发送的目标用户为空");
                return ;
            }
            hubConnection.InvokeAsync("Chat",this.UserName,this.TargetUserName,msg);
            if (this.richTextBox != null)
            {
                Run run = new Run();
                Run run1 = new Run();
                Paragraph paragraph = new Paragraph();
                Paragraph paragraph1 = new Paragraph();
                run.Foreground = Brushes.Blue;
                run.Text = this.UserName;
                run1.Foreground= Brushes.Black;
                run1.Text = msg;
                paragraph.Inlines.Add(run);
                paragraph1.Inlines.Add(run1);
                paragraph.LineHeight = 1;
                paragraph.TextAlignment = TextAlignment.Right;
                paragraph1.LineHeight = 1;
                paragraph1.TextAlignment = TextAlignment.Right;
                this.richTextBox.Document.Blocks.Add(paragraph);
                this.richTextBox.Document.Blocks.Add(paragraph1);
                this.richTextBox.ScrollToEnd();
            }
        }

        #endregion

        /// <summary>
        /// 初始化Connection对象
        /// </summary>
        private void InitInfo() {
            hubConnection = new HubConnectionBuilder().WithUrl("https://localhost:7149/chat").WithAutomaticReconnect().Build();
            hubConnection.KeepAliveInterval =TimeSpan.FromSeconds(5);
        }

        /// <summary>
        /// 监听
        /// </summary>
        private void Listen() {
            hubConnection.On<List<string>>("Users", RefreshUsers);
            hubConnection.On<string>("ChatInfo",ReceiveInfos);
        }

        /// <summary>
        /// 连接
        /// </summary>
        private async void Link() {
            try
            {
               await hubConnection.StartAsync();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void Login()
        {
            hubConnection.InvokeAsync("Login", this.UserName);
        }

        private void ReceiveInfos(string msg)
        {
            if (string.IsNullOrEmpty(msg)) {
                return;
            }
            if (this.richTextBox != null)
            {
                Run run = new Run();
                Run run1 = new Run();
                Paragraph paragraph = new Paragraph();
                Paragraph paragraph1 = new Paragraph();
                run.Foreground = Brushes.Red;
                run.Text = msg.Split("|")[0];
                run1.Foreground = Brushes.Black;
                run1.Text = msg.Split("|")[1];
                paragraph.Inlines.Add(run);
                paragraph1.Inlines.Add(run1);
                paragraph.LineHeight = 1;
                paragraph.TextAlignment = TextAlignment.Left;
                paragraph1.LineHeight = 1;
                paragraph1.TextAlignment = TextAlignment.Left;
                this.richTextBox.Document.Blocks.Add(paragraph);
                this.richTextBox.Document.Blocks.Add(paragraph1);
                this.richTextBox.ScrollToEnd();
            }
        }

        private void RefreshUsers(List<string> users) {
            this.Users = users;
        }
    }
}

运行示例


在示例中,需要同时启动服务端和客户端,所以以多项目方式启动,如下所示:

WPF+ASP.NET SignalR实现简易在线聊天功能

 运行成功后,服务端以ASP.NET Web API的方式呈现,如下所示:

WPF+ASP.NET SignalR实现简易在线聊天功能

 客户端需要同时运行两个,所以在调试运行启动一个客户端后,还要在Debug目录下,手动双击客户端,再打开一个,并进行登录,如下所示:

WPF+ASP.NET SignalR实现简易在线聊天功能

WPF+ASP.NET SignalR实现简易在线聊天功能

 系统运行时,后台日志输出如下所示:

WPF+ASP.NET SignalR实现简易在线聊天功能

备注


以上就是WPF+ASP.NET SignalR实现在线聊天的全部内容,关于SignalR的应用,不仅仅局限于在线聊天,这只是一个简单的入门示例,希望可以抛砖引玉,一起学习,共同进步。学习编程,从关注【老码识途】开始!!!文章来源地址https://www.toymoban.com/news/detail-465800.html

到了这里,关于WPF+ASP.NET SignalR实现简易在线聊天功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于Springboot+WebSocket+Netty实现在线聊天、群聊系统

    此文主要实现在好友添加、建群、聊天对话、群聊功能,使用Java作为后端语言进行支持,界面友好,开发简单。 2.1、下载安装IntelliJ IDEA(后端语言开发工具),Mysql数据库,微信Web开发者工具。 1.创建maven project 先创建一个名为SpringBootDemo的项目,选择【New Project】 然后在弹出

    2024年02月14日
    浏览(42)
  • 毕业设计——基于springboot的在线聊天系统设计与实现

    完整项目地址:https://download.csdn.net/download/lijunhcn/88430400 本项目是一套聊天系统,包括前台手机界面及后台分布式系统,基于SpringBoot+Netty+MUI+H5Plus+Nginx+FastDFS分布式文件系统搭建的聊天系统。 前端聊天系统包含首页门户登录注册、互信、通讯录、发现、我等模块,添加了扫一

    2024年02月03日
    浏览(46)
  • C语言实现--基于UDP的多人在线聊天室

    目录 实现功能 实现思想 实现代码(部分及详解) 服务端部分代码 客户端部分代码 实现效果 项目中出现的问题和解决方法 项目整体代码展示 代码优化思路 服务端代码 客户端代码 服务端可以同时连接多个客户端; 新的客户端连接服务端时,可以在服务端显示自己的名字并

    2024年02月04日
    浏览(64)
  • SpringBoot+Netty+Vue+Websocket实现在线推送/聊天系统

    ok,那么今天的话也是带来这个非常常用的一个技术,那就是咱们完成nutty的一个应用,今天的话,我会介绍地很详细,这样的话,拿到这个博文的代码就基本上可以按照自己的想法去构建自己的一个在线应用了。比如聊天,在线消息推送之类的。其实一开始我原来的想法做在

    2024年02月03日
    浏览(43)
  • 基于Unity客户端与服务端实现登录与注册以及多人在线聊天

    1.在Unity下,创建一个GameManager空对象,用于启动客户端连接以及实例化一个登录页面LoginView的Prefab,并将脚本LoginView挂载在上面。 2.创建一个Client类,用于客户端向服务端发起连接请求,并且发送给服务端消息以及接收服务端的响应 3.创建一个脚本LoginView挂载在LoginView对象上

    2024年04月16日
    浏览(51)
  • 基于 SpringBoot+WebSocket 无DB实现在线聊天室(附源码)

    0.1 样例展示 0.2 源码地址 GitHub:https://github.com/ShiJieCloud/web-chat Gitee:https://gitee.com/suitbaby/web-chat GitCode:I’m Jie / web-chat · GitCode 1.1 HTTP 常用的 HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出

    2024年02月05日
    浏览(50)
  • 【Unity 3D】利用C#、Unity和Socket实现简单的在线聊天室工具(附源码 简单易懂)

    需要源码请点赞关注收藏后评论区留言并且私信~~~ 下面利用Unity和C#语言做一个简单的聊天室程序,主要用到的技术就是Socket通信连接,需要一个客户端和一个服务器端,服务器端就使用C#语言的控制台完成 下面就开始搭建C#语言服务器端 1:新建一个C#语言控制台程序 2:命名

    2024年02月05日
    浏览(68)
  • 开源在线客服系统-客服系统历史消息记录功能-点击加载历史聊天记录-分页展示历史消息功能实现

    之前开发的开源在线客服系统gofly,访客端一直没有展示历史聊天记录,最近抽时间给加上了 实现的效果就是,访客刚进聊天界面,如果存在历史记录,按5条分页,默认查询加载5条聊天记录。 如果历史记录超过5条,顶部出现 “点击加载更多” 按钮,点击按钮就分页查询历

    2023年04月12日
    浏览(51)
  • 微人事项目在线聊天(一)

    添加一个消息按钮 Home.vue 添加点击事件方法 创建聊天页面组件 添加路由

    2024年02月12日
    浏览(42)
  • ASP.NET Core+Vue3 实现SignalR通讯

    从ASP.NET Core 3.0版本开始,SignalR的Hub已经集成到了ASP.NET Core框架中。因此,在更高版本的ASP.NET Core中,不再需要单独引用Microsoft.AspNetCore.SignalR包来使用Hub。 在项目创建一个类继承Hub, 首先是写一个CreateConnection方法 ConnectionId是SignalR中标识的客户端连接的唯一标识符, 将userId和

    2024年02月06日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包