介绍
ASP.NET Core SignalR是一个有用的库,可以简化Web应用程序中实时通信的管理。但是,我宁愿使用WebSockets,因为我想要更灵活,并且与任何WebSocket客户端兼容。
在Microsoft的文档中,我找到了一个很好的WebSockets工作示例。它仍然是管理连接,以便能够从一个连接向其他连接广播消息,这是SignalR开箱即用的功能。期望这个逻辑非常复杂,我想从Startup类中删除它。
背景
要阅读ASP.NET Core中的WebSockets支持,可以在此处查看。如果您想了解中间件以及如何在ASP.NET Core中编写它,请阅读此链接。
代码使用
首先,你必须添加 Microsoft.AspNetCore.WebSockets 包到你的项目。
现在,您可以创建一个扩展方法和类来管理WebSockets:
public static class WebSocketExtensions
{ public static IApplicationBuilder UseCustomWebSocketManager(this IApplicationBuilder app)
{ return app.UseMiddleware<CustomWebSocketManager>();
}
}public class CustomWebSocketManager
{ private readonly RequestDelegate _next; public CustomWebSocketManager(RequestDelegate next)
{
_next = next;
} public async Task Invoke(HttpContext context, ICustomWebSocketFactory wsFactory, ICustomWebSocketMessageHandler wsmHandler)
{ if (context.Request.Path == "/ws")
{ if (context.WebSockets.IsWebSocketRequest)
{ string username = context.Request.Query["u"]; if (!string.IsNullOrEmpty(username))
{
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
CustomWebSocket userWebSocket = new CustomWebSocket()
{
WebSocket = webSocket,
Username = username
};
wsFactory.Add(userWebSocket); await wsmHandler.SendInitialMessages(userWebSocket); await Listen(context, userWebSocket, wsFactory, wsmHandler);
}
} else
{
context.Response.StatusCode = 400;
}
} await _next(context);
} private async Task Listen(HttpContext context, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory, ICustomWebSocketMessageHandler wsmHandler)
{
WebSocket webSocket = userWebSocket.WebSocket; var buffer = new byte[1024 * 4];
WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); while (!result.CloseStatus.HasValue)
{ await wsmHandler.HandleMessage(result, buffer, userWebSocket, wsFactory);
buffer = new byte[1024 * 4];
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
}
wsFactory.Remove(userWebSocket.Username); await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}
}在这种情况下,WebSockets请求在URL中始终包含“/ ws”。查询字符串包含用于将WebSocket与登录用户相关联的用户名的参数u。
CustomWebSocket是一个包含WebSocket和用户名的类:
public class CustomWebSocket
{ public WebSocket WebSocket { get; set; } public string Username { get; set; }
}我也创建了自定义WebSocket消息:
class CustomWebSocketMessage
{ public string Text { get; set; } public DateTime MessagDateTime { get; set; } public string Username { get; set; } public WSMessageType Type { get; set; }
}其中Type是您可能拥有的不同类型消息的枚举。
在Startup类中,您必须注册以下服务:
services.AddSingleton<ICustomWebSocketFactory, CustomWebSocketFactory>(); services.AddSingleton<ICustomWebSocketMessageHandler, CustomWebSocketMessageHandler>();
CustomWebSocketFactory负责收集连接的WebSockets列表:
public interface ICustomWebSocketFactory
{ void Add(CustomWebSocket uws); void Remove(string username);
List<CustomWebSocket> All();
List<CustomWebSocket> Others(CustomWebSocket client);
CustomWebSocket Client(string username);
}public class CustomWebSocketFactory : ICustomWebSocketFactory
{
List<CustomWebSocket> List; public CustomWebSocketFactory()
{
List = new List<CustomWebSocket>();
} public void Add(CustomWebSocket uws)
{
List.Add(uws);
} //when disconnect
public void Remove(string username)
{
List.Remove(Client(username));
} public List<CustomWebSocket> All()
{ return List;
}
public List<CustomWebSocket> Others(CustomWebSocket client)
{ return List.Where(c => c.Username != client.Username).ToList();
}
public CustomWebSocket Client(string username)
{ return List.First(c=>c.Username == username);
}
}CustomWebSocketMessageHandler包含有关消息的逻辑(即在连接时需要发送任何消息以及如何对传入消息作出反应)
public interface ICustomWebSocketMessageHandler
{
Task SendInitialMessages(CustomWebSocket userWebSocket);
Task HandleMessage(WebSocketReceiveResult result, byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory);
Task BroadcastOthers(byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory);
Task BroadcastAll(byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory);
}public class CustomWebSocketMessageHandler : ICustomWebSocketMessageHandler
{ public async Task SendInitialMessages(CustomWebSocket userWebSocket)
{
WebSocket webSocket = userWebSocket.WebSocket; var msg = new CustomWebSocketMessage
{
MessagDateTime = DateTime.Now,
Type = WSMessageType.anyType,
Text = anyText,
Username = "system"
}; string serialisedMessage = JsonConvert.SerializeObject(msg); byte[] bytes = Encoding.ASCII.GetBytes(serialisedMessage); await webSocket.SendAsync(new ArraySegment<byte>(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None);
} public async Task HandleMessage(WebSocketReceiveResult result, byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory)
{ string msg = Encoding.ASCII.GetString(buffer); try
{ var message = JsonConvert.DeserializeObject<CustomWebSocketMessage>(msg); if (message.Type == WSMessageType.anyType)
{ await BroadcastOthers(buffer, userWebSocket, wsFactory);
}
} catch (Exception e)
{ await userWebSocket.WebSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
}
} public async Task BroadcastOthers(byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory)
{ var others = wsFactory.Others(userWebSocket); foreach (var uws in others)
{ await uws.WebSocket.SendAsync(new ArraySegment<byte>(buffer, 0, buffer.Length), WebSocketMessageType.Text, true, CancellationToken.None);
}
} public async Task BroadcastAll(byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory)
{ var all = wsFactory.All(); foreach (var uws in all)
{ await uws.WebSocket.SendAsync(new ArraySegment<byte>(buffer, 0, buffer.Length), WebSocketMessageType.Text, true, CancellationToken.None);
}
}
}最后,在Configure方法的Startup类中添加以下内容:
var webSocketOptions = new WebSocketOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(120),
ReceiveBufferSize = 4 * 1024};
app.UseWebSockets(webSocketOptions);
app.UseCustomWebSocketManager();通过这种方式,Starup类保持干净,管理WebSockets的逻辑可以扩展,使您可以根据自己的喜好灵活地组织它。喜欢这篇文章就转载吧。在Asp.net Core中使用中间件来管理websocket
原文 出处:https://www.cnblogs.com/bruceday/p/9600770.html
共同學習,寫下你的評論
評論加載中...
作者其他優質文章
