上一篇完成了服务端的数据库搭建以及登录和注册的方法。 接下来我们要完成的几个方法有:发送给指定用户,获取在线的好友列表,添加好友
目录
一、发送给指定用户方法(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,在群里@群主即可