查看原文
其他

.NET Core下使用SignalR

DotNet 2021-09-23

(给DotNet加星标,提升.Net技能


转自:cgyqu

cnblogs.com/cgyqu/p/9563193.html


背景


由于要做微信小程序聊天,所以.NetFramwork版本的SignalR版本的不能用了。因为小程序里没有windows对象,导致JQuery无法使用。而Signalr的 js客户端是依赖JQuery的。



services.AddCors(options => options.AddPolicy("SignalR",
  builder =>
  {
      builder.AllowAnyMethod() //允许任意请求方式
             .AllowAnyHeader() //允许任意header
             .AllowAnyOrigin() //允许任意origin
             .AllowCredentials();//允许验证
           //.WithOrigins(domins) //指定特定域名才能访问
  }));


然后在Configure使用定义好的跨域策略


app.UseCors("SignalR");



services.AddSignalR()
       .AddMessagePackProtocol()
       .AddRedis(o =>
       {
           o.ConnectionFactory = async writer =>
           {
               var config = new ConfigurationOptions
               {
                   AbortOnConnectFail = false
               };
               config.EndPoints.Add(IPAddress.Loopback, 0);
               config.SetDefaultPorts();
               var connection = await ConnectionMultiplexer.ConnectAsync(config, writer);
               connection.ConnectionFailed += (_, e) =>
               {
                  Console.WriteLine("Connection Redis failed.");
               };
               if (!connection.IsConnected)
               {
                   Console.WriteLine("Connection did not connect.");
               }
               return connection;
           };
       });



proxy_http_version   1.1;
proxy_set_header  Host $host;
proxy_set_header   Upgrade $http_upgrade;
proxy_set_header   Connection "upgrade";
proxy_connect_timeout   300;
proxy_read_timeout   300;
proxy_send_timeout   300;


于是我把应用发布到本地虚拟机里,并用docker方式运行。然后把配置写进nginx配置文件里。


发现真的不能进行POST请求了,返回400。400的意是思请求异常。肯定是这个配置有问题额。于是又去交友网站找issue,果然又让我找到了。 


在一个issue里面,提供的配置如下


proxy_http_version   1.1;
proxy_set_header   Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;



于是又去看issues,果然,里面也有人问,作者也有解释。


去交友网站看看(https://github.com/aspnet/SignalR/issues/2729)


大体意思ConnectonId是服务端使用,客户端不应该使用这种不可控的方式进行通信。 可以采用Group或者User这种可控方式通信,并且也有例子给出。


这里插一句,在使用.Net Framwork版本时候,我们网站是使用ConnectionId进行通信,经常出现重连导致ConnectionId变掉,进而通信失败。


所以我也调整了下设计思路,改使用Group进行通信。


以上都搞定了,辛苦了这么久,按道理应该没问题了吧!那么发布上线!




看到这个错误,第一个反应,我的想法是难道是Redis没连接成功,所以只能单机跑?所以我就在上面Redis代码加上各种监控,发现连接成功了。代码Review了n遍代码,实在没有地方可以改了。


于是官方文档一个个过。终于发现Js可以进行以下配置


let connection = new signalR.HubConnectionBuilder()
   .withUrl("/myhub", {
       skipNegotiation: true,
       transport: signalR.HttpTransportType.WebSockets
   });
   .build();



private async Task<HttpConnectionContext> GetConnectionAsync(HttpContext context)
{
   var connectionId = GetConnectionId(context);
   if (StringValues.IsNullOrEmpty(connectionId))
   {
       // There's no connection ID: bad request
       context.Response.StatusCode = StatusCodes.Status400BadRequest;
       context.Response.ContentType = "text/plain";
       await context.Response.WriteAsync("Connection ID required");
       return null;
   }
   if (!_manager.TryGetConnection(connectionId, out var connection))
   {
       // No connection with that ID: Not Found
       context.Response.StatusCode = StatusCodes.Status404NotFound;
       context.Response.ContentType = "text/plain";
       await context.Response.WriteAsync("No Connection with that ID");
       return null;
   }
   return connection;
}


这段代码啥意思呢?就是connection在本地没找到的话,就返回404!


我去,难道是代码bug?



啥意思呢?就是这不是bug,就是这么设计的。使用SignalR时,要进行会话保持,请求要一直落到同一台服务器上。这样更稳定,并且还可以实时监控客户端的情况。


于是找运维同学在负载上配置了下会话保持,再次测试,终于可以了。


总结


在此次使用SignalR的过程中,遇到了太多的坑。花了几个小时整理并记录下来,与各位进行分享。


推荐阅读

(点击标题可跳转阅读)

.NET Core SignalR 初体验

ASP.NET Core SignalR中的流式传输

使用 ASP.NET Core SignalR 实现社交网络式通知


看完本文有收获?请转发分享给更多人

关注「DotNet」加星标,提升.Net技能 

: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存