介绍

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 = ;
}
}
await _next(context);
} private async Task Listen(HttpContext context, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory, ICustomWebSocketMessageHandler wsmHandler)
{
WebSocket webSocket = userWebSocket.WebSocket;
var buffer = new byte[ * ];
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[ * ];
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, , 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, , 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, , 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, , buffer.Length), WebSocketMessageType.Text, true, CancellationToken.None);
}
}
}

最后,在Configure方法的Startup类中添加以下内容:

var webSocketOptions = new WebSocketOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(),
ReceiveBufferSize = *
}; app.UseWebSockets(webSocketOptions);
app.UseCustomWebSocketManager();

通过这种方式,Starup类保持干净,管理WebSockets的逻辑可以扩展,使您可以根据自己的喜好灵活地组织它。喜欢这篇文章就转载吧。在Asp.net Core中使用中间件来管理websocket

在Asp.net Core中使用中间件来管理websocket的更多相关文章

  1. ASP.NET Core 中的中间件

    前言   由于是第一次写博客,如果您看到此文章,希望大家抱着找错误.批判的心态来看. sky! 何为中间件? 在 ASP.NET Framework 中应该都知道请求管道.可参考:浅谈 ASP.NET ...

  2. 在Asp.NET Core中如何优雅的管理用户机密数据

    在Asp.NET Core中如何优雅的管理用户机密数据 背景 回顾 在软件开发过程中,使用配置文件来管理某些对应用程序运行中需要使用的参数是常见的作法.在早期VB/VB.NET时代,经常使用.ini文 ...

  3. 在Asp.Net Core中使用中间件保护非公开文件

    在企业开发中,我们经常会遇到由用户上传文件的场景,比如某OA系统中,由用户填写某表单并上传身份证,由身份管理员审查,超级管理员可以查看. 就这样一个场景,用户上传的文件只能有三种人看得见(能够访问) ...

  4. Asp.Net Core 通过自定义中间件防止图片盗链的实例(转)

    一.原理 要实现防盗链,我们就必须先理解盗链的实现原理,提到防盗链的实现原理就不得不从HTTP协议说起,在HTTP协议中,有一个表头字段叫referer,采用URL的格式来表示从哪儿链接到当前的网页或 ...

  5. ASP.NET Core系列:中间件

    1. 概述 ASP.NET Core中的中间件是嵌入到应用管道中用于处理请求和响应的一段代码. 2. 使用 IApplicationBuilder 创建中间件管道 2.1 匿名函数 使用Run, Ma ...

  6. ASP.NET Core 中的那些认证中间件及一些重要知识点

    前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...

  7. [转]ASP.NET Core 中的那些认证中间件及一些重要知识点

    本文转自:http://www.qingruanit.net/c_all/article_6645.html 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系 ...

  8. 在ASP.NET Core 中使用Cookie中间件

    在ASP.NET Core 中使用Cookie中间件 ASP.NET Core 提供了Cookie中间件来序列化用户主题到一个加密的Cookie中并且在后来的请求中校验这个Cookie,再现用户并且分 ...

  9. ASP.NET Core中使用GraphQL - 第二章 中间件

    前文:ASP.NET Core中使用GraphQL - 第一章 Hello World 中间件 如果你熟悉ASP.NET Core的中间件,你可能会注意到之前的博客中我们已经使用了一个中间件, app ...

随机推荐

  1. Python requests 使用心得

    最近在用requests写一些项目,遇见了一些问题,百度了很多,有些都不太好使,最后看了下requestsAPI文档,才明白了很多,最后项目趋于稳定.看来学东西还是API文档比较权威啊~ 问题场景 项 ...

  2. oralce 存储过程、函数和触发器

    一.存储过程和存储函数 指存储在数据库中供所有用户程序调用的子程序叫存储过程.存储函数.   创建存储过程 用CREATE PROCEDURE命令建立存储过程. 语法: create [or repl ...

  3. PL/Sql快速执行 insert语句的.sql文件

    当全是 insert语句的.sql文件太大时(insert 语句条数太大),直接打开执行sql文件,pl/sql会卡死. 这是可以用pl/sql的命令窗口来执行.sql文件,操作步骤如下: 1.新建命 ...

  4. Golang之并发篇

    进程和线程 A.进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位. B.线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位. C.一 ...

  5. Oracle增加一列、修改一列数据类型

    Oracle增加一列.修改一列数据类型: 添加一列: alter   table   A   add( CFYJSNR  varchar2(20)); 修改列: alter  table A  ren ...

  6. mybatis的select、insert、update、delete语句

    一.select <!-- 查询学生,根据id --> <select id="getStudent" parameterType="String&qu ...

  7. 品味性能之道<十>:Oracle Hint

    Hint 是Oracle 提供的一种SQL语法,它允许用户在SQL语句中插入相关的语法,从而影响SQL的执行方式. 因为Hint的特殊作用,所以对于开发人员不应该在代码中使用它,Hint 更像是Ora ...

  8. [Selenium]显式等待 Explicit wait & 隐式等待 Implicit wait

    显式等待 Explicit wait 显示等待 , 就是明确的要等到某个元素出现或者某个元素满足某种条件,每隔一段时间检查一次,等不到,就一直等,如果在规定的时间内还没有找到,就跳出来检查间隔的时间和 ...

  9. python常用模块及面向对象(一)

    目录: 常用模块之time模块 常用模块之random模块 常用模块之os模块 常用模块之sys模块 常用模块之subprocess模块 常用模块之json模块 常用模块之pickle模块 常用模块之 ...

  10. Python鸭子类型思想

    动态语言中经常提到鸭子类型,所谓鸭子类型就是:如果走起路来像鸭子,叫起来也像鸭子,那么它就是鸭子(If it walks like a duck and quacks like a duck, it ...