前两篇写完了服务端的一些代码,接下来写winform客户端的。
SignalR聊天系统的服务端以及数据库1https://blog.csdn.net/hyx1229/article/details/121258116?spm=1001.2014.3001.5501https://blog.csdn.net/hyx1229/article/details/121258116?spm=1001.2014.3001.5501SignalR聊天系统服务端的方法 2https://blog.csdn.net/hyx1229/article/details/121277634?spm=1001.2014.3001.5501
https://blog.csdn.net/hyx1229/article/details/121277634?spm=1001.2014.3001.5501
一、与服务端连接的静态类
在winform的根目录下建一个类,ChatService.cs,建静态类是为了让三个窗体能共用这些方法和数据,需要先在nuget中安装Microsoft.AspNetCore.SignalR.Client这个包
然后我将解释以下代码
静态的UserId:存放自己账户的id,后续获取自己的好友列表,添加好友等都需要用到
UserList:用于存放自己的好友列表
Connection:就是SignalR连接的上下文了,后续通过它来调用服务端的方法
1.1 await Connection.StartAsync()方法
开启连接,连接成功后服务端可以里面输出当前连接的连接id,只需在服务端中重写Hub的OnConnectedAsync方法 ,服务端全部代码
/// <summary>
/// 新连接
/// </summary>
/// <returns></returns>
public override async Task OnConnectedAsync()
{
Console.WriteLine($"新连接{Context.ConnectionId}");
await base.OnConnectedAsync();
}
这里只要我先打开服务端,再启动winform就能看到这个效果,注意你每次重新启动winform,这个连接id是不一样的。所以我们会在用户登录后把它的连接id存到内存中而不是放到数据库。
1.2Connection.On 监听
前面两篇中说过,服务端主动去发送消息给客户端,同时客户端也需要在建立连接后去监听的。
Connection.On支持泛型,Connection.On<Users>传入的泛型用于约束你将要接收的参数。
写法:Connection.On<string>("test", (msg) =>{MessageBox.Show(msg)});两个必填的参数,第一个是你要监听的方法的名称,第二个是action一个无返回值的委托,也就是你监听到后要做的操作。
这里有个隐藏的知识,看下面代码
服务端发送时的类和客户端监听时的类并不需要是同一个类,但是类中的字段需要相同,否则会监听不到,就好像你被重载了一样。 而利用这个泛型的好处就在于不用一个一个的传参数了,SignalR会主动帮你做序列化。不像websocket只能传输byte数组。
1.3Connection.InvokeAsync("")主动调用服务端的方法
通过它我们可以去发送消息,它主动调用服务端的方法,服务端接收后再通知其他客户端,同时被其他客户端监听到,就实现了发信息的功能。
写法:Connection.InvokeAsync("要调用的方法的名称",参数1,参数2,。。。);支持多参数传递,也可以通过泛型来约束你要调用的方法它所接收的参数类型: Connection.InvokeAsync<Users>("hello","");这种在服务端的方法有重载的情况下就很好用
下面我们代码中,我们将监听的代码封装到了方法中,每个方法几乎都有需要传入一个action的委托,因为在这个静态类中我们不能确定哪个窗体有哪些控件,并且也无法获取到那些控件。所以把要做的操作通过调用的时候传入进来。
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows.Forms;
using ChatRommClient_WinFrom.Dtos;
using Microsoft.AspNetCore.SignalR.Client;
namespace ChatRommClient_WinFrom
{
public static class ChatService
{
public static long UserId = default;
public static List<Users> UsersList = new List<Users>();
public static HubConnection Connection;
/// <summary>
/// 初始化连接
/// </summary>
public static async void SignalRConnection()
{
Connection = new HubConnectionBuilder()
.WithUrl("http://localhost:5160/chatHub")
.Build();
await Connection.StartAsync();
Connection.Closed += async error =>
{
await Task.Delay(new Random().Next(0, 5) * 1000);
await Connection.StartAsync();
};
}
/// <summary>
/// 监听好友上线
/// </summary>
public static void BuddysOnline(Action action)
{
Connection.On<Users>("BuddysOnline", user =>
{
Task.Run(() =>
{
UsersList.Add(user);
action();
MessageBox.Show($"您的好友{user.NickName}上线了", "上线通知", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
});
});
}
/// <summary>
/// 监听接收消息
/// </summary>
/// <param name="action"></param>
public static void ReceiveMessage(Action<string,DateTime> action)
{
//接收消息
Connection.On<string,DateTime>("ReceiveMessage", (msg,sendTime) =>
{
Task.Run(() =>
{
action(msg,sendTime);
});
});
}
/// <summary>
/// 监听登录成功获取在线好友列表
/// </summary>
/// <param name="action"></param>
public static void ReceiveBuddyList(Action action)
{
Connection.On<List<Users>>("ReceiveBuddyList", users =>
{
Task.Run(() =>
{
UsersList.AddRange(users);
action();
});
});
}
/// <summary>
/// 监听登录结果
/// </summary>
/// <param name="success"></param>
/// <param name="error"></param>
public static void ReceiveLoginResult(Action success,Action error)
{
Connection.On<bool,long>("LoginResult", (result,uid) =>
{
if (result)
{
UserId = uid;
success();
}
else
{
error();
}
});
}
/// <summary>
/// 监听添加好友结果
/// </summary>
public static void ReceiveAddBuddyResult(Action action)
{
Connection.On<string>("ReceiveAddBuddyResult", msg =>
{
MessageBox.Show(msg);
action();
});
}
}
public class Users
{
public string NickName { get; set; }
public string ConnectionId { get; set; }
}
}
二、登录界面
2.1初始化SignalR连接
程序启动时就开启连接,并开始监听登录结果这个方法
监听登录成功结果,我们需要传入两个方法,一个是登录成功后的操作,一个是失败的操作
private void LoginSuccess()
{
MainFrm mainFrm = new MainFrm();
mainFrm.Show();
this.Visible = false;
}
private void LoginError()
{
MessageBox.Show("登录失败,账号或密码错误");
}
private void LoginFrm_Load(object sender, EventArgs e)
{
//初始化连接
ChatService.SignalRConnection();
//监听登录的结果
ChatService.ReceiveLoginResult(LoginSuccess,LoginError);
}
在登录窗体点击注册按钮弹出注册的模态窗体
private void btn_registerFrom_Click(object sender, EventArgs e)
{
RegisterFrm frm = new RegisterFrm();
frm.ShowDialog();
}
2.2注册方法
在注册界面点击注册时通过发送http请求,请求服务端写好的注册的api接口
/// <summary>
/// 注册
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void btn_register_Click(object sender, EventArgs e)
{
var userInfo = new
{
UserName=tb_userName.Text,
NickName=tb_nickName.Text,
PassWord=tb_pwd.Text
};
HttpClient client = new HttpClient();//创建客户端
HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(userInfo));//请求的参数
httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");//设置请求参数的格式
var resMsg = client.PostAsync("http://localhost:5160/api/user/register", httpContent);//发出请求,接收返回值
var result = await resMsg.Result.Content.ReadAsStringAsync();
MessageBox.Show(result);
}
这个id呢就类似与qq号码这个东西,是由后端返回的,之后添加好友也需要通过这个id,其实呢你们可以在后端把id设为Guid类型的,我这里就用的int。
2.3登录方法
上面我们写了监听,所以当登录成功后就会直接跳到主界面了。
private async void bt_login_Click(object sender, EventArgs e)
{
var uname = tb_userName.Text;
var pwd = tb_pwd.Text;
await ChatService.Connection.InvokeAsync("Login",uname,pwd);
}
成功:
失败:
下一篇写发送消息和添加好友
源码地址:https://download.csdn.net/download/hyx1229/42548815
需要免费源码的可以加.net core学习交流群:831181779,在群里@群主即可