我喜欢.NET CORE 这个东西,其实不仅仅源于它性能很高,可以跨平台,还因为它的设计模式确实令人着迷。以前没.NET CORE 的时候,.NET用websocket必须跑在windows server 2012上,但我一般不会这么干,都把websocket架在nodejs的服务器上。这么分出来,麻烦肯定是麻烦的,而且js这东西,写复杂和几年后再看都是头疼的问题。那么,如果.NET CORE是以kestrel运行的,那么就不再需要考虑服务器的版本运行,任何一个地方都可以用websocket
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包含有关消息的逻辑(即在连接时需要发送任何消息以及如何对传入消息作出反应)