在Asp.net Core中使用中介軟體來管理websocket

來源:互聯網
上載者:User
介紹

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

相關文章

Alibaba Cloud 10 Year Anniversary

With You, We are Shaping a Digital World, 2009-2019

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。