什么是SignalR?

SignalR做了什么?
传统HTTP采用的是大家熟知的“拉模式”,即客户端发出的每次请求,服务端都是被动处理。此场景下客户端是老大,很显然只有一方主动,操作与处理起来就没那么完美。

封装与集成

SignalR用途
官方网址和源码
-
官方网址:https://dotnet.microsoft.com/zh-cn/apps/aspnet/signalr
-
微软API文档:https://learn.microsoft.com/zh-cn/aspnet/signalr/overview/getting-started/introduction-to-signalr
-
GitHub网址:https://github.com/SignalR

示例截图

服务端项目创建
using Microsoft.AspNetCore.SignalR;
namespace DemoSignalR.Server.Chat
{
public class ChatHub : Hub
{
#region 连接和断开连接
public override async Task OnConnectedAsync()
{
var connId = Context.ConnectionId;
Console.WriteLine($"{connId} 已连接");
await base.OnConnectedAsync();
}
public void StartNotify(string type)
{
if (type == "1")
{
}
else if (type == "2")
{
};
}
public override async Task OnDisconnectedAsync(Exception ex)
{
//如果断开连接
var connId = Context.ConnectionId;
Console.WriteLine($"{connId} 已断开");
await base.OnDisconnectedAsync(ex);
}
#endregion
}
}
SignalR服务端业务集成
using DemoSignalR.Server.Chat;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
namespace DemoSignalR.Server.Controllers
{
[ApiController]
[Route("[controller]")]
public class TestWebApiController : ControllerBase
{
private readonly ILogger<TestWebApiController> _logger;
private IHubContext<ChatHub> _context;
public TestWebApiController(ILogger<TestWebApiController> logger, IHubContext<ChatHub> context)
{
_logger = logger;
_context = context;
}
[HttpGet]
public void GetTestA(string Name)
{
string info = $"当前接收到的信息为:{Name},{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}";
_context.Clients.All.SendAsync("", info);
}
}
}
using Microsoft.AspNetCore.SignalR;
using System.Timers;
namespace DemoSignalR.Server.Chat
{
public class TestChatInfo
{
private IHubContext<ChatHub> _context;
private System.Timers.Timer _timer;
private readonly static object locker = new object();//锁对象
public static TestChatInfo instance;//当前实例
private readonly ILogger _logger;
private int _index = 0;
private TestChatInfo(IHubContext<ChatHub> _context, ILogger _logger)
{
this._context = _context;
this._logger = _logger;
//定义定时器
_timer = new System.Timers.Timer(100);
_timer.AutoReset = true;
_timer.Enabled = true;
_timer.Elapsed += Timer_Elapsed;
_timer.Start();
}
private void Timer_Elapsed(object? sender, ElapsedEventArgs e)
{
//业务逻辑判断
var obj = new TestValue();
obj.Index = this._index;
obj.Value = DateTime.Now.Millisecond % 100;
_context.Clients.All.SendAsync("RefreshInfos", obj);
this._index++;
}
/// <summary>
/// 注册,即初始化单例实例
/// </summary>
/// <param name="context"></param>
/// <param name="reviewTaskService"></param>
/// <param name="sysParamService"></param>
public static void Register(IHubContext<ChatHub> context, ILogger logger)
{
lock (locker)
{
if (instance == null)
{
lock (locker)
{
instance = new TestChatInfo(context, logger);
}
}
}
}
}
public class TestValue
{
private int index;
public int Index { get { return index; } set { index = value; } }
private float value;
public float Value { get { return value; } set { this.value = value; } }
}
}
SignalR服务端配置
using DemoSignalR.Server.Chat;
using Microsoft.AspNetCore.SignalR;
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();
builder.Services.AddLogging(logging => logging.AddConsole());
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseRouting();
app.UseHttpsRedirection();
app.UseAuthorization();
//在Use中注册单例实例
app.Use(async (context, next) =>
{
var hubContext = context.RequestServices.GetRequiredService<IHubContext<ChatHub>>();
//var logger = context.RequestServices.GetRequiredService<ILogger>();
TestChatInfo.Register(hubContext, null);//调用静态方法注册
if (next != null)
{
await next.Invoke();
}
});
app.MapControllers();
//2.映射路由
app.UseEndpoints(endpoints => {
endpoints.MapHub<ChatHub>("/chat");
});
app.Run();
客户端项目创建
using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DemoSignalR.Client
{
internal class SignalRClient
{
private readonly HubConnection hubConnection;
public HubConnection HubConnection
{
get { return hubConnection; }
}
public SignalRClient()
{
var server = ConfigurationManager.AppSettings["Server"].ToString();
hubConnection = new HubConnectionBuilder().WithUrl($"{server}/chat").WithAutomaticReconnect().Build();
hubConnection.KeepAliveInterval = TimeSpan.FromSeconds(5);
}
public virtual void Listen()
{
}
public async void Start()
{
try
{
await hubConnection.StartAsync();
}
catch (Exception e)
{
}
}
}
}
客户端业务逻辑处理
using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DemoSignalR.Client
{
internal class TestSignalRClient : SignalRClient
{
public Action<object> RefreshInfos;
public Action<string> Reconnected;
public TestSignalRClient() : base()
{
}
public override void Listen()
{
HubConnection.On<object>("RefreshInfos", (obj) =>
{
//
if (obj != null)
{
Console.WriteLine("收到数据");
//发送消息
if (RefreshInfos != null)
{
RefreshInfos(obj);
}
}
});
HubConnection.Reconnected += HubConnection_Reconnected;
}
private Task HubConnection_Reconnected(string arg)
{
return Task.Run(() =>
{
if (Reconnected != null)
{
Reconnected(arg);
}
});
}
public virtual void StartNotify(string condition)
{
HubConnection.SendAsync("StartNotify", condition);
Console.WriteLine($"开始通过知{condition}");
}
}
}
SignalR需要注意事项
关于源码