• 最新 .NET Core 中 WebSocket的使用 在Asp.Net MVC 中 WebSocket的使用 .NET Core 中 SignalR的使用


     

    ASP.NET MVC 中使用WebSocket 笔记

    1.采用控制器的方法 这个只写建立链接的方法的核心方法

    1.1 踩坑 网上都是直接 传个异步方法 直接接受链接 自己尝试了好多次链接是打开的,到时获取不到链接里面的内容!! (如果是我理解有问题的话,欢迎讨论,毕竟这个问题卡了我好久!)

    1.2 自己建立链接的使用截图 方法

       

     1 /// <summary>
     2         /// WebSocket链接 demo地址 ws://Localhost:8080/Get 
     3         /// </summary>
     4         [HttpGet]
     5         public void Get()
     6         {
     7             if (System.Web.HttpContext.Current.IsWebSocketRequest)
     8             {
     9                 //System.Web.HttpContext.Current.AcceptWebSocketRequest(AnalysisOptionChat);
    10                 System.Web.HttpContext.Current.AcceptWebSocketRequest(async (context) => await AnalysisOptionChat(context));
    11             }
    12         }
    View Code

    1.3 判断是WebSocket 链接后 处理消息

     1 /// <summary>
     2         /// WebSocket链接操作
     3         /// </summary>
     4         /// <param name="context"></param>
     5         /// <returns></returns>
     6         private async Task AnalysisOptionChat(AspNetWebSocketContext context)
     7         {
     8             var webSocket = context.WebSocket;
     9             #region 测试demo
    10             try
    11             {
    12                 ConsoleWrite.ConsoleInfo($"Websocket client add--> 自己需要实现 保存链接");
    13                 WebSocketReceiveResult clientData = null;
    14                 do
    15                 {
    16                     var buffer = new ArraySegment<byte>(new byte[1024 * 1000]);
    17                     //if (clientData.MessageType == WebSocketMessageType.Text && !clientData.CloseStatus.HasValue)
    18                     if (webSocket.State == WebSocketState.Open && clientData.MessageType == WebSocketMessageType.Text)
    19                     {
    20                         string msgString = Encoding.UTF8.GetString(buffer.Array, 0, clientData.Count);
    21                         var sendData = string.Empty;
    22                         if ("rub".Equals(msgString))//心跳
    23                         {
    24                             
    25                         }
    26                         else
    27                         {
    28                             int size = clientData.Count;
    29 
    30                             #region 通知
    31                             #endregion
    32 
    33                             #region DB持久化 操作
    34                             #endregion
    35                         }
    36                     }
    37                 }
    38                 //while (!clientData.CloseStatus.HasValue);
    39                 while (webSocket.State == WebSocketState.Open);
    40 
    41                 var state = webSocket.State;
    42                 ConsoleWrite.ConsoleWarning($"Websocket client closed1-->{state.ToString()}");
    43                 ConsoleWrite.ConsoleWarning($"Websocket client closed2-->{clientData.CloseStatus.Value}");
    44                 //关闭事件
    45                 await webSocket.CloseAsync(clientData.CloseStatus.Value, clientData.CloseStatusDescription, CancellationToken.None);
    46             }
    47             catch (Exception ex)
    48             {
    49                 Console.WriteLine(ex.Message);
    50             }
    51 
    52             #endregion
    53 }
    View Code

    1.4 在Asp.Net MVC 中使用可能会遇到 跨域的问题 一下是解决方案

     1 <system.webServer>
     2     <!--全局跨域-->
     3     <httpProtocol>
     4       <customHeaders>
     5         <add name="Access-Control-Allow-Origin" value="*" />
     6         <!--<add name="Access-Control-Allow-Headers" value="*" />
     7         <add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />-->
     8       </customHeaders>
     9     </httpProtocol>
    10 <system.webServer>
    View Code

    .NET Core 中使用WebSocket 笔记

    1.在WepApi中使用法 这个只写建立链接的方法的核心方法

    1.首先需要在Startup.cs 里面的 ConfigureServices里面配置跨域 如果不牵扯跨域的话 可以忽略 1,2 (里面的跨域) 跨域详细配置如下

    1 services.AddCors(options =>
    2             {
    3                 options.AddPolicy("WebSocketCors", builder =>
    4                 {
    5                     builder.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials();
    6                 });
    7             });
    View Code

    2.然后在 Configure方法 里面加入管道 

     1 app.UseWebSockets(new Microsoft.AspNetCore.Builder.WebSocketOptions
     2             {
     3                 //保持活动间隔
     4                 KeepAliveInterval = TimeSpan.FromMinutes(5),
     5             });
     6 
     7             // 注意这个是重点!!!!
     8             app.UseMiddleware<WebsocketHandlerMiddleware>();
     9 
    10  //自定义跨域规则
    11             app.UseCors("WebSocketCors");
    View Code

    详细截图如下

     3. 请求中间件 WebsocketHandlerMiddleware.cs 详细介绍如下

     1 public class WebsocketHandlerMiddleware
     2     {
     3         private readonly RequestDelegate _next;
     4 
     5         public WebsocketHandlerMiddleware(RequestDelegate next)
     6         {
     7             _next = next;
     8         }
     9 
    10         public async Task Invoke(HttpContext context)
    11         {
    12             if (context.Request.Path == "/ws")
    13             {
    14                 //客户端与服务器成功建立连接后,服务器会循环异步接收客户端发送的消息,收到消息后就会执行Handle(WebsocketClient websocketClient)中的do{}while;直到客户端断开连接
    15                 //不同的客户端向服务器发送消息后台执行do{}while;时,websocketClient实参是不同的,它与客户端一一对应
    16                 //同一个客户端向服务器多次发送消息后台执行do{}while;时,websocketClient实参是相同的
    17                 if (context.WebSockets.IsWebSocketRequest)
    18                 {
    19                     var webSocket = await context.WebSockets.AcceptWebSocketAsync();
    20                     
    21                 }
    22                 else
    23                 {
    24                     context.Response.StatusCode = 404;
    25                 }
    26             }
    27             else
    28             {
    29                 await _next(context);
    30             }
    31         }
    32     }
    View Code

    里面处理 WebSocket 请求消息的内容 和 1.3  中方法是一样的 我这里就不重复了 两者的区别都只是 获取方式不一样而已。

    .NET Core 中使用SignalR笔记

    1.在WepApi中使用法 这个只写建立链接的方法的核心方法 以及相关方法介绍

    所使用的Nuget 包 如下:

    1.1 首先需要在Startup.cs 里面的 ConfigureServices方法 注入且配置跨域.

     1 #region SignalR
     2 
     3             services.AddCors(options =>
     4             {
     5                 options.AddPolicy("SignalRCors", builder =>
     6                 {
     7                     builder.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials();
     8                 });
     9             });
    10 
    11             services.AddSignalR().AddHubOptions<SignalrHub>(options =>
    12             {
    13                 options.EnableDetailedErrors = true;
    14             })
    15             // 支持MessagePack
    16             .AddMessagePackProtocol();
    17 
    18             #endregion
    View Code

    同时还需要 注入加入声明周期 管控 

    //特殊的
    services.AddSingleton<SignalrHub>();

    1.2 在Configure方法里面 的相关使用

     1 //自定义跨域规则
     2 app.UseCors("SignalRCors");
     3 
     4 //需要在 Map里面 指定路由
     5 //app.UseHttpsRedirection();
     6  app.UseEndpoints(endpoints =>
     7             {
     8                 endpoints.MapControllers();
     9                 //可以设置SignalR相关参数,这里设置地址
    10                 endpoints.MapHub<SignalrHub>("hubs/signalr", options =>
    11                 {
    12             //配置 几种方式
    13                     options.Transports = HttpTransportType.WebSockets | HttpTransportType.LongPolling;
    14                 });
    15             });
    View Code

    1.3 SignalrHub.cs 集线器类的使用介绍 里面有许多用不上的 自己按照需求自己过滤 主要就是 OnConnectedAsync() 建立链接 OnDisconnectedAsync()断开链接 方法的使用!

      1 //创建SingalR中心跨域
      2     [EnableCors("SignalRCors")]
      3     public  class SignalrHub : Hub
      4     {
      5         //ReceiveMessage 为客户端监听的 方法名称
      6         private static string clientSendMethodName = "ReceiveMessage";
      7 
      8         //Redis 存储信息Key
      9         private static string signalrRedisKey = "SignalRConnections";
     10 
     11         public SignalrHub()
     12         {
     13 
     14         }
     15 
     16 
     17         #region Send
     18 
     19         /// <summary>
     20         /// 发送消息-指定用户集合发送消息
     21         /// </summary>
     22         /// <param name="userIds">通知用户集合</param>
     23         /// <param name="sendObject">通知OBject</param>
     24         /// <returns></returns>
     25         public  async Task SendUserMessage(List<int> userIds,object sendObject)
     26         {
     27             //从redis 获取 userIds 对应的 ConnectionId 进行推送
     28             var connectionUserList = RedisService.GetLPushData<UserConnection>(signalrRedisKey, 0, int.MaxValue);
     29             if(connectionUserList.Count()<=0) throw new Exception("无连接用户,无法进行消息推送。");
     30             var sentUserClient = connectionUserList.Where(x => userIds.Contains(x.UserId)).ToList();
     31             var sendMeaaageToJson = JsonHelper.ObjectToJsonCamelCase(sendObject);
     32 
     33             var connectionIds = sentUserClient.Select(y => y.ConnectionId);
     34 
     35             //全部
     36             //await Clients.All.SendAsync(clientSendMethodName, new { data = sendMeaaageToJson });
     37 
     38             //指定
     39             await Clients.Clients(connectionIds).SendAsync(clientSendMethodName, new { data = sendMeaaageToJson });
     40         }
     41 
     42 
     43         //发送消息--发送给所有连接的客户端
     44         public async Task SendMessage(string msg)
     45         {
     46             //await Clients.All.SendAsync(clientSendMethodName, msg);
     47             Console.WriteLine($"保持心跳链接-->接收参数:{msg}");
     48         }
     49 
     50 
     51 
     52         /// <summary>
     53         /// 除 connectionId 之外的所有发送message
     54         /// </summary>
     55         /// <param name="connectionId"></param>
     56         /// <param name="message"></param>
     57         /// <returns></returns>
     58         public Task SendAllExceptMe(string connectionId, string message)
     59         {
     60 
     61             return Clients.AllExcept(connectionId).SendAsync(clientSendMethodName, $"{Context.ConnectionId}: {message}");
     62         }
     63 
     64         #endregion
     65 
     66 
     67 
     68         #region Group分组的话 依据职位 或者 角色来业务循环获取
     69 
     70 
     71 
     72         #endregion
     73 
     74 
     75         #region overrides
     76 
     77         /// <summary>
     78         /// 当新的客户端连接建立时执行的操作
     79         /// </summary>
     80         /// <returns></returns>
     81         public override async Task OnConnectedAsync()
     82          {
     83             //建立者用户Id
     84             var clientUserId = AuthHelper.GetUserId(Context.User);
     85             //建立者用户Name
     86             var clientUserName = Context.User.Identity.Name;
     87             //建立ConnectionId
     88             var connectionId = Context.ConnectionId;
     89 
     90             if (clientUserId <= 0 || string.IsNullOrWhiteSpace(clientUserName))
     91             {
     92                 throw new Exception("建立连接异常,无法获取用户信息。");
     93             }
     94 
     95             Console.WriteLine($"OnConnectedAsync建立链接----userId:{clientUserId},userName:{clientUserName},connectionId:{ Context.ConnectionId}");
     96 
     97             var userConnections = new List<UserConnection>();
     98             userConnections.Add(new UserConnection() { UserId = clientUserId, UserName = clientUserName, ConnectionId = connectionId, CreateTime = DateTime.Now });
     99 
    100             //redis存储连接用户信息
    101             RedisService.SetLPushValue(signalrRedisKey, false, userConnections);
    102 
    103             //获取所有用户的链接信息
    104             //var aaa = RedisService.GetLPushData<UserConnection>(signalrRedisKey,0,10000000);
    105 
    106             await base.OnConnectedAsync();
    107         }
    108 
    109 
    110         /// <summary>
    111         /// 当客户端断开连接时执行的操作
    112         /// </summary>
    113         /// <param name="exception"></param>
    114         /// <returns></returns>
    115         public override async Task OnDisconnectedAsync(Exception exception)
    116         {
    117             //建立者用户Id
    118             var clientUserId = AuthHelper.GetUserId(Context.User);
    119             //建立者用户Name
    120             var clientUserName = Context.User.Identity.Name;
    121             //建立ConnectionId
    122             var connectionId = Context.ConnectionId;
    123             //NLogHelper.ActionWarn();
    124 
    125             Console.WriteLine($"OnDisconnectedAsync断开链接----userId:{clientUserId},clientUserName:{clientUserName},connectionId:{ connectionId}");
    126 
    127             var connectionUserList = RedisService.GetLPushData<UserConnection>(signalrRedisKey, 0, int.MaxValue);
    128 
    129             //在redis里面依据 Value 移除
    130             var removeItem = connectionUserList.Where(x => x.ConnectionId == connectionId).FirstOrDefault();
    131             if (removeItem != null)
    132             {
    133                 var Drow = await RedisService.LRemAsync(signalrRedisKey, removeItem);
    134                 //var connectionUserLists = RedisService.GetLPushData<UserConnection>(signalrRedisKey, 0, int.MaxValue);
    135             }
    136             await base.OnDisconnectedAsync(exception);
    137         }
    138 
    139         protected override void Dispose(bool disposing)
    140         {
    141             base.Dispose(disposing);
    142         }
    143 
    144         #endregion
    145 
    146 
    147         #region ClearOverTime 清除超时的垃圾数据
    148 
    149         public async Task ClearOverTimeUserRedis(int houre=24) 
    150         {
    151             var connectionUserList = RedisService.GetLPushData<UserConnection>(signalrRedisKey, 0, int.MaxValue);
    152             var thisTime = DateTime.Now;
    153             var delConnection = connectionUserList.Where(x=>(thisTime-x.CreateTime).Duration().TotalHours >= houre).ToList();
    154             if (delConnection != null) 
    155             {
    156                 foreach (var delItem in delConnection)
    157                 {
    158                     var Drow = await RedisService.LRemAsync(signalrRedisKey, delItem);
    159                     //var connectionUserLists = RedisService.GetLPushData<UserConnection>(signalrRedisKey, 0, int.MaxValue);
    160                 }
    161             }
    162         }
    163 
    164         #endregion
    165     }
    View Code

    1.4 SignalrHub.cs 里面所用到的用户链接 UserConnection.cs 类

     1 [Serializable]
     2     public class UserConnection
     3     {
     4         /// <summary>
     5         /// 用户Id
     6         /// </summary>
     7         public int UserId { set; get; }
     8 
     9         /// <summary>
    10         /// 用户名称
    11         /// </summary>
    12         public string UserName { set; get; }
    13 
    14         /// <summary>
    15         /// 连接Id
    16         /// </summary>
    17         public string ConnectionId { set; get; }
    18 
    19         /// <summary>
    20         /// 创建时间
    21         /// </summary>
    22         public DateTime CreateTime { set; get; }
    23     }
    View Code

    作者声明:

    1.文章转载请注明出处 !!! 

    2.文章 如有不正确之处欢迎大家讨论,交流, 如果感觉写的还行,或者帮助了您,请点个赞哈,再次谢过~

  • 相关阅读:
    s3fs 挂载minio为本地文件系统
    P5787 线段树分治
    P5494 线段树分裂
    P1552 [APIO2012]派遣
    CF600E Lomsat gelral(线段树合并)
    P5283 异或粽子
    P4735 最大异或和(可持久化 trie)
    P3960 列队
    bzoj4316 小C的独立集
    P5021 赛道修建
  • 原文地址:https://www.cnblogs.com/goodluckily/p/15211859.html
Copyright © 2020-2023  润新知