Net Core中使用WebSocket默认是没有路由系统的,只能通过Request.Path=="/xxx"来判断请求,例如:

 1 2 3 4 5 6 7 8 91011121314151617181920
app.Use(async (context, next) =>{    if (context.Request.Path == "/ws")    {        if (context.WebSockets.IsWebSocketRequest)        {            WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();            await Echo(context, webSocket);        }        else        {            context.Response.StatusCode = 400;        }    }    else    {        await next();    }});

要使用类似[HttpGet("/xxx")]这种特性标签的路由方式,可以自己写一个简单的Attribute来实现。

这个Attribute类很简单,只接收一个定义的Path,用来和开头提到的Request.Path对应。

 1 2 3 4 5 6 7 8 910111213
/// <summary>    /// WebSockets执行函数特性标签    /// </summary>[AttributeUsage(AttributeTargets.Method,Inherited = false)] public class WebSocketsAttribute:Attribute {     // WebSocket请求的Path    public string Path;    public WebSocketsAttribute(string path)    {        Path = path;    }}

使用一个帮助类来根据请求的PATH分发给对应的函数。该类中有两个静态方法,实现同样的功能,区别是一个会缓存请求的Path和处理请求函数,另一个是实时反射解析的,实际使用中当然推荐带缓存的,因为反射对性能的损耗也是很大的。

2.1. 不带缓存的分发函数

 1 2 3 4 5 6 7 8 9101112131415161718192021222324252627282930313233343536
/// <summary>/// 分发websockets请求(没有缓存)/// </summary>/// <param name="assemblyName">对应处理程序所在的程序集名称</param>/// <param name="context">HTTP上下文</param>/// <param name="task">TASK任务</param>/// <returns></returns>public static async Task DistributeAsync(string assemblyName, HttpContext context, Func<Task> task){    try    {        // 获取在WebSockets下面的websocket处理methods        var assembly = Assembly.Load(assemblyName);        // 根据特性标签获取对应的执行函数        var methods = assembly            .GetTypes()            .SelectMany(s => s.GetMethods())            .First(f => f                .GetCustomAttributes(typeof(WebSocketsAttribute), false)  // 这一步获取打了WebSocketsAttribute特性标签的函数                .Any(w => ((WebSocketsAttribute)w).Path == context.Request.Path)); // 过滤找出其中WebSocketsAttribute标签中Path参数对应的执行函数        if (context.WebSockets.IsWebSocketRequest)        {            var webSockt = await context.WebSockets.AcceptWebSocketAsync();            // 异步调用该方法            await (Task)methods.Invoke(null, new object[] { context, webSockt });        }        else        {            context.Response.StatusCode = 400;        }    }    catch (Exception)    {        await task();    }}

2.2. 带缓存的分发函数

 1 2 3 4 5 6 7 8 910111213141516171819202122232425262728293031323334353637383940414243444546
// 使用并发安全的字段类型缓存请求Path与处理请求函数private static ConcurrentDictionary<string, MethodInfo> ExecuteMethods;/// <summary>/// 分发websockets请求(缓存执行函数)/// </summary>/// <param name="assemblyName">对应处理程序所在的程序集名称</param>/// <param name="context">HTTP上下文</param>/// <param name="task">TASK任务</param>/// <returns></returns>public static async Task DistributeAsync(string assemblyName, HttpContext context, Func<Task> task){    if (!ExecuteMethods.Any())    {        // 获取在WebSockets下面的websocket处理methods        var assembly = Assembly.Load(assemblyName);        // 根据特性标签获取对应的执行函数        var methods = assembly            .GetTypes()            .SelectMany(s => s.GetMethods())            .Select(s => new            {                ((WebSocketsAttribute) s.GetCustomAttributes(typeof(WebSocketsAttribute), false).First()).Path,                s            }).ToArray();        ExecuteMethods =            new ConcurrentDictionary<string, MethodInfo>(methods.ToDictionary(t => t.Path, t => t.s));        await task();    }    else    {        if (context.WebSockets.IsWebSocketRequest)        {            var webSockt = await context.WebSockets.AcceptWebSocketAsync();            // 从键值对中获取对应的执行函数            ExecuteMethods.TryGetValue(context.Request.Path, out var method);            if (method != null)                // 异步调用该方法                await (Task) method.Invoke(null, new object[] {context, webSockt});        }        else        {            context.Response.StatusCode = 400;        }    }}

startup.cs中的Config函数中可以使用我们自己创建的分发函数,需要注意的是我们自定义的函数需要传入程序集的名称,也就是真实的请求处理函数所在的程序集。

由此可见,这种方式使用的一些限制,请求处理函数必须写在一个程序集里面,不过我想一般情况下,没有人会把同一类型的处理函数写在不同的程序集,所以这应该不算是问题。

 1 2 3 4 5 6 7 8 91011121314
/// <summary>/// startup.cs/// </summary>public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory){    ...    // 增加websocket    app.Use(async (context, next) =>    {        // 将原本的Echo方法换成我们自定义的分发函数        await WebSocketsHandler.DistributeAsync("NetCoreFrame.WebSockets", context, next);    });    ...}

使用方式很简单,就是一个正常的WebSocket处理函数,只不过标注了我们自己的“路由特性标签”。

 1 2 3 4 5 6 7 8 91011121314151617181920
public class Test{    [WebSockets("/ws")]    public static async Task Echo(HttpContext context, WebSocket webSocket)    {        var buffer = new byte[1024 * 4];        var result =            await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);        while (!result.CloseStatus.HasValue)        {            await webSocket.SendAsync(                    new ArraySegment<byte>(buffer, 0, result.Count),                    result.MessageType, result.EndOfMessage,                    CancellationToken.None                );            result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);        }        await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);    }}

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/websockets?view=aspnetcore-2.2

原文地址:

http://haijd.tech/csharp/%E5%9C%A8.net-core%E4%B8%AD%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AAwebsocket%E8%B7%AF%E7%94%B1/


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

在.Net Core中实现一个WebSocket路由相关推荐

  1. 处理ASP.NET Core中的HTML5客户端路由回退

    在使用由Angular,React,Vue等应用程序框架构建的客户端应用程序时,您总是会处理HTML5客户端路由,它将完全在浏览器中处理到页面和组件的客户端路由.几乎完全在浏览器中... HTML5客 ...

  2. .NET Core中的一个接口多种实现的依赖注入与动态选择

    最近有个需求就是一个抽象仓储层接口方法需要SqlServer以及Oracle两种实现方式,为了灵活我在依赖注入的时候把这两种实现都给注入进了依赖注入容器中,但是在服务调用的时候总是获取到最后注入的那个 ...

  3. 在.NET Core中处理一个接口多个不同实现的依赖注入问题

    前言 近段时间在准备公司的技术分享,所以这段时间将大部分时间放在准备分享内容上去了.博客也就停了一下下. 在.NET Core中处理依赖注入问题时,往往是定义好了一个操作规范的接口,会有N多个基于不同 ...

  4. 在ASP.NET Core中实现一个Token base的身份认证

    以前在web端的身份认证都是基于Cookie | Session的身份认证, 在没有更多的终端出现之前,这样做也没有什么问题, 但在Web API时代,你所需要面对的就不止是浏览器了,还有各种客户端, ...

  5. 在ASP.NET Core中创建自定义端点可视化图

    在上篇文章中,我为构建自定义端点可视化图奠定了基础,正如我在第一篇文章中展示的那样.该图显示了端点路由的不同部分:文字值,参数,动词约束和产生结果的端点: 在本文中,我将展示如何通过创建一个自定义的D ...

  6. ASP.NET Core中为指定类添加WebApi服务功能

    POCO Controller是 ASP.NET Core 中的一个特性,虽然在2015年刚发布的时候就有这个特性了,可是大多数开发者都只是按原有的方式去写,而没有用到这个特性.其实,如果利用这个特性 ...

  7. ASP.NET Core 中是否有 PostAsJsonAsync() 方法?

    咨询区 LP13 在 Asp.NET 中我一般都用 PostAsJsonAsync() 做数据提交,在 Asp.NET Core 时代我貌似没有找到,按照程序集的命名规范,我觉得应该也是由 Micro ...

  8. 如何在 .Net Core 中使用 IHostedService

    在我们应用程序中常常会有一些执行后台任务和任务调度的需求,那如何在 ASP.Net Core 中实现呢?可以利用 Azure WebJobs 或者其他一些第三方任务调度框架,如:Quartz 和 Ha ...

  9. 如何在 Asp.Net Core 中 管理敏感数据

    译文链接:https://www.infoworld.com/article/3576292/how-to-work-with-user-secrets-in-asp-net-core.html 在应 ...

最新文章

  1. 开源——需要分享共享的无私精神
  2. Spring-学习笔记09【JdbcTemplate的基本使用】
  3. C#LeetCode刷题之#205-同构字符串(Isomorphic Strings)
  4. 帧间差分法_OpenCV_详解
  5. 【英语学习】【Daily English】U14 Transportation L01There will be a car exhibition next month
  6. MTK 驱动(71)---DDR进行bitflip压力测试
  7. 【linux系统编程】基础开发工具:gcc/g++
  8. 数组多重筛选条件排序方法
  9. 在 Panorama 页面中添加 ApplicationBar
  10. php实现des加密,如何在PHP项目中实现一个DES加密解密功能
  11. 广告违规词、敏感词在线检测
  12. 小楼一夜听春雨,天下谁人不识君?
  13. 文件云端备份恢复onedriver+SyncToy
  14. 小甲鱼python入门笔记(一)(全)
  15. POI将网络图片添加到excel
  16. excel-柱状图不同柱子不同颜色设置
  17. Day 06 | 242.有效的字母异位词 349. 两个数组的交集 202.快乐数 1. 两数之和
  18. IDEA 快速返回上次查看代码的位置常用的IDEA快捷键(持续更新)
  19. Git教学资源,安装,关联账号,创建/关联/克隆库,版本回退,管理修改基本指令
  20. 字节也开始缩招了...

热门文章

  1. Mac OS使用技巧之十:Finder的详细使用方法
  2. 在Teams app代码中enable nullable
  3. latex插入gif_如何将照片和GIF插入Google幻灯片
  4. Linux下oracle11g 导入导出操作详细
  5. Linux 远程桌面 rdesktop 软件
  6. Xamarin效果第五篇之ScrollView动态滚动效果
  7. 2021.NET大会日程首发!行程亮点全曝光!
  8. Win11重磅新功能推送!
  9. 支持c#的分表分库组件-Ctrip DAL
  10. NET问答: 如何实现读写 file 的时候不用锁模式 ?