.NET Core和SignalR实现一个简单版聊天系统——服务端2

上一篇完成了服务端的数据库搭建以及登录和注册的方法。                                                  接下来我们要完成的几个方法有:发送给指定用户,获取在线的好友列表,添加好友

目录

 一、发送给指定用户方法(SendToUser)

二、 获取在线的好友列表

三、添加好友


一、发送给指定用户方法(SendToUser)

发送信息给好友我们需要有好友的连接id以及要发送的消息,在上一篇中我们定义了一个类专门用来作为发送消息使用。

public class ToUserMessageDto
    {
        //好友的连接id
        public string ToConnectionId { get; set; }
        public string Message { get; set; }
    }

然后我们来实现这个方法,这个方法的代码很少,因为服务端只是作为通知的,两个客户端之间并不能直接发信息,所以服务端这里只要你给我好友的连接id和你要发送的内容即可。

Clients.Clients(dto.ToConnectionId).ReceiveMessage(dto.Message,sendTime);                     这里在上一篇中提到过,ReceiveMessage这个方法是通过配置Hub的泛型而来的              它的本质是:Clients.Clients(dto.ToConnectionId).SendAsync("ReceiveMessage",dto.Message,sendTime);

而ReceiveMessage这个方法名称也是后面我们客户端需要监听的方法。

这边简单的画了个图 

public class ChatHub:Hub<IChatClient>
    {
        /// <summary>
        /// key用户id,value连接id
        /// </summary>
        private static Dictionary<string, string> map = new Dictionary<string, string>();
        private readonly IUserService _userService;
        public ChatHub(IUserService userService)
        {
            this._userService = userService;
        }
        
        /// <summary>
        /// 发送给指定用户
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task SendToUser(ToUserMessageDto dto)
        {
            var sendTime = DateTime.Now;
            await Clients.Clients(dto.ToConnectionId).ReceiveMessage(dto.Message,sendTime);
        }
        /// <summary>
        /// 连接关闭
        /// </summary>
        /// <param name="exception"></param>
        /// <returns></returns>
        public override Task OnDisconnectedAsync(Exception? exception)
        {
            if(map.Count>0)
            {
                var remove = map.FirstOrDefault(n => n.Value == Context.ConnectionId);
                map.Remove(remove.Key);
            }
            return base.OnDisconnectedAsync(exception);
        }
        /// <summary>
        /// 新连接
        /// </summary>
        /// <returns></returns>
        public override async Task OnConnectedAsync()
        {
            await base.OnConnectedAsync();
        }
        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task Login(string userName,string pwd)
        {
            var userInfo = await _userService.Login(userName, pwd);
            if (userInfo==null)
            {
                await Clients.Clients(Context.ConnectionId).LoginResult(false,0);
                return;
            }
            map.Add(userInfo.Id.ToString(),Context.ConnectionId);
            await Clients.Clients(Context.ConnectionId).LoginResult(true,userInfo.Id);
            OnlineToUserMessage onlineToUserMessage = new OnlineToUserMessage
            {
                NickName = userInfo.NickName,
                ConnectionId = Context.ConnectionId,
            };
            //要通知的好友列表
            var youBuddy =await _userService.GetBuddyId(userInfo.Id);
            var sendList = new List<string>();
            foreach (var item in youBuddy)
            {
                var key = item.Id.ToString();
                if (map.ContainsKey(key))
                {
                    sendList.Add(map[key]);
                }
            }

            if (sendList.Any())
            {
                //通知好友
                await Clients.Clients(sendList).BuddysOnline(onlineToUserMessage);
            }
        }


    }

二、 获取在线的好友列表

在用户登录成功之后,客户端会主动向服务端索要在线的好友列表。也许有人会问为什么不在登录成功的时候服务端主动返回给客户端,这是因为我客户端分了三个窗体,登录,注册,主界面,登录为启动窗体,因为我们在主界面中有个下拉框用于放好友列表,如果在成功之后直接得到好友列表,此时处于登录窗体,我并没有办法追加到主界面的下拉框中,目前来说我不知道窗体之间能否共享的传递控件。所以是这样设计的。

 代码:里面的返回在线的好友列表与上面代码的发送消息是一样的道理,就不再过多解释了,总之客户端winform需要监听ReceiveBuddyList这个方法就对了。

/// <summary>
        /// 获取在线的好友
        /// </summary>
        /// <returns></returns>
        public async Task GetBuddys(long uid)
        {
            //好友列表
            var youBuddy = await _userService.GetBuddyId(uid);
            //在线的好友
            var data = new List<object>();
            foreach (var item in youBuddy)
            {
                var key = item.Id.ToString();
                if (map.ContainsKey(key))
                {
                    data.Add(new
                    {
                        NickName=item.NickName,
                        ConnectionId=map[key]
                    });
                }
            }
            //返回在线的好友列表
            await Clients.Clients(Context.ConnectionId).ReceiveBuddyList(data);
        }
           

三、添加好友

添加好友这块的话其实可以写在controller里面,因为他并不需要太多的交互。我这边是当时忘记了,没想到。

客户端同样需要监听ReceiveAddBuddyResult(添加结果)方法。

/// <summary>
        /// 添加好友
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="buddyId"></param>
        /// <returns></returns>
        public async Task AddBuddy(long userId,long buddyId)
        {
            Buddy buddy = new Buddy()
            {
                UserId =userId,
                FriendId = buddyId
            };
            var result= await _userService.AddBuddy(buddy);
            //返回添加的结果
            await Clients.Clients(Context.ConnectionId).ReceiveAddBuddyResult(result);
        }

 到这里的话,我们的服务端就基本上完成了。以下是ChatHub的全部代码,有些注释没有是因为上面的注释都是我写文章的时候临时加的。

 public class ChatHub:Hub<IChatClient>
    {
        /// <summary>
        /// key用户id,value连接id
        /// </summary>
        private static Dictionary<string, string> map = new Dictionary<string, string>();
        private readonly IUserService _userService;
        public ChatHub(IUserService userService)
        {
            this._userService = userService;
        }
        
        /// <summary>
        /// 发送给指定用户
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task SendToUser(ToUserMessageDto dto)
        {
            var sendTime = DateTime.Now;
            await Clients.Clients(dto.ToConnectionId).ReceiveMessage(dto.Message,sendTime);
        }
        /// <summary>
        /// 连接关闭
        /// </summary>
        /// <param name="exception"></param>
        /// <returns></returns>
        public override Task OnDisconnectedAsync(Exception? exception)
        {
            if(map.Count>0)
            {
                var remove = map.FirstOrDefault(n => n.Value == Context.ConnectionId);
                map.Remove(remove.Key);
            }
            return base.OnDisconnectedAsync(exception);
        }
        /// <summary>
        /// 新连接
        /// </summary>
        /// <returns></returns>
        public override async Task OnConnectedAsync()
        {
            await base.OnConnectedAsync();
        }
        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task Login(string userName,string pwd)
        {
            var userInfo = await _userService.Login(userName, pwd);
            if (userInfo==null)
            {
                await Clients.Clients(Context.ConnectionId).LoginResult(false,0);
                return;
            }
            map.Add(userInfo.Id.ToString(),Context.ConnectionId);
            await Clients.Clients(Context.ConnectionId).LoginResult(true,userInfo.Id);
            OnlineToUserMessage onlineToUserMessage = new OnlineToUserMessage
            {
                NickName = userInfo.NickName,
                ConnectionId = Context.ConnectionId,
            };
            //要通知的好友列表
            var youBuddy =await _userService.GetBuddyId(userInfo.Id);
            var sendList = new List<string>();
            foreach (var item in youBuddy)
            {
                var key = item.Id.ToString();
                if (map.ContainsKey(key))
                {
                    sendList.Add(map[key]);
                }
            }

            if (sendList.Any())
            {
                //通知好友
                await Clients.Clients(sendList).BuddysOnline(onlineToUserMessage);
            }
        }
        /// <summary>
        /// 获取在线的好友
        /// </summary>
        /// <returns></returns>
        public async Task GetBuddys(long uid)
        {
            //好友列表
            var youBuddy = await _userService.GetBuddyId(uid);
            //在线的好友
            var data = new List<object>();
            foreach (var item in youBuddy)
            {
                var key = item.Id.ToString();
                if (map.ContainsKey(key))
                {
                    data.Add(new
                    {
                        NickName=item.NickName,
                        ConnectionId=map[key]
                    });
                }
            }
            //返回在线的好友列表
            await Clients.Clients(Context.ConnectionId).ReceiveBuddyList(data);
        }
        /// <summary>
        /// 添加好友
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="buddyId"></param>
        /// <returns></returns>
        public async Task AddBuddy(long userId,long buddyId)
        {
            Buddy buddy = new Buddy()
            {
                UserId =userId,
                FriendId = buddyId
            };
            var result= await _userService.AddBuddy(buddy);
            await Clients.Clients(Context.ConnectionId).ReceiveAddBuddyResult(result);
        }
    }

 最后我们将写好的集线器ChatHub配置路由终结点,在ConfigureServices中注册SignalR服务,这些方法需要引入相应的命名空间,根据提示引入一下就可以。

public void ConfigureServices(IServiceCollection services)
        {

            services.AddControllers();
            services.AddSignalR();
            services.AddScoped<IUserService, UserService>();
            services.AddDbContext<ChatRoomContext>(options =>
            {
                options.UseSqlServer(Configuration.GetConnectionString("Default"));
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapHub<ChatHub>("/chatHub");
            });
        }

然后我们将服务端启动一下看,localhost:5160/chatHub就是后面客户端的连接地址了。

 源码地址:https://download.youkuaiyun.com/download/hyx1229/42548815 

需要免费源码的可以加.net core学习交流群:831181779,在群里@群主即可

.NET Core和SignalR实现一个简单版聊天系统——服务端1https://blog.youkuaiyun.com/hyx1229/article/details/121258116?spm=1001.2014.3001.5502

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不想只会CRUD的猿某人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值