栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

在Asp.net Core中使用中间件来管理websocket

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

在Asp.net Core中使用中间件来管理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();
    }
}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(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(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();
services.AddSingleton();

CustomWebSocketFactory负责收集连接的WebSockets列表:

public interface ICustomWebSocketFactory
{   void Add(CustomWebSocket uws);   void Remove(string username);
   List All();
   List Others(CustomWebSocket client);
   CustomWebSocket Client(string username);
}public class CustomWebSocketFactory : ICustomWebSocketFactory
{
   List List;   public CustomWebSocketFactory()
   {
      List = new List();
   }   public void Add(CustomWebSocket uws)
   {
      List.Add(uws);
   }   //when disconnect
   public void Remove(string username) 
   {
      List.Remove(Client(username));
   }   public List All()
   {      return List;
   }   
   public List 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(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(msg);         if (message.Type == WSMessageType.anyType)
         {            await BroadcastOthers(buffer, userWebSocket, wsFactory);
         }
      }      catch (Exception e)
      {         await userWebSocket.WebSocket.SendAsync(new ArraySegment(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(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(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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/231158.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号