首页 > 解决方案 > SignalR 和 React - 由于底层连接被关闭而取消调用

问题描述

晚上好。我正在使用 SignalR(5.0.1,我还尝试了早期版本 3.0.0)和 dotnet core 3.1 构建聊天组件。

任何用户发表的评论都可以发送给所有已连接的客户端,所有已连接的客户端都可以看到该评论。但是,发送评论的客户端将断开连接,并捕获错误addComment() in the mobx store

客户端发送评论后将失去连接(发送者和其他客户端可以获取已从 ChatHub 处理的评论)。我不知道为什么服务器决定断开连接并引发错误。一世

错误:

[2021-01-10T22:38:14.314Z] Information: Connection disconnected.
adventureStore.ts:73 Error: Invocation canceled due to the underlying connection being closed.
    at HubConnection.connectionClosed (HubConnection.ts:654)
    at HttpConnection.HubConnection.connection.onclose (HubConnection.ts:103)
    at HttpConnection.stopConnection (HttpConnection.ts:488)
    at WebSocketTransport.transport.onclose (HttpConnection.ts:410)
    at WebSocketTransport.close (WebSocketTransport.ts:135)
    at WebSocket.webSocket.onclose (WebSocketTransport.ts:97)

以下是代码:

启动:

public class Startup
    {
            // only showing the codes related to problem
            services.AddSignalR();
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(opt =>
                {
                    opt.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = key,
                        ValidateAudience = false,
                        ValidateIssuer = false
                    };
                    opt.Events = new JwtBearerEvents
                    {
                        OnMessageReceived = context => 
                        {
                            var accessToken = context.Request.Query["access_token"];
                            var path = context.HttpContext.Request.Path;
                            if (!string.IsNullOrEmpty(accessToken) && 
                                (path.StartsWithSegments("/chat")))
                            {
                                context.Token = accessToken;
                            }
                            return Task.CompletedTask;
                        }
                    };
                });
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseMiddleware<ErrorHandlingMiddleware>();
            if (env.IsDevelopment())
            {
                // app.UseDeveloperExceptionPage();
            }

            // app.UseHttpsRedirection();

            app.UseRouting();
            app.UseCors("CorsPolicy");

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapHub<ChatHub>("/chat");
            });
        }
    }

ChatHub.cs:

public class ChatHub : Hub
    {
        private readonly IMediator _mediator;
        public ChatHub(IMediator mediator)
        {
            _mediator = mediator;
        }

        public async Task SendComment(Create.Command command)
        {
            var username = Context.User?.Claims?.FirstOrDefault(x => x.Type == 
            ClaimTypes.NameIdentifier)?.Value;

            command.Username = username;

            var comment = await _mediator.Send(command);
            
            // clients can successfully receive the comment and load it to their mobx store
            await Clients.All.SendAsync("ReceiveComment", comment);
        }
    }

建立连接的 mobx 商店:

  @observable comments: IComment[] | null = null;
  @observable.ref hubConnection: HubConnection | null = null;

  @action createHubConnection = () => {
    this.hubConnection = new HubConnectionBuilder()
      .withUrl("http://localhost:5000/chat", {
        accessTokenFactory: () => this.rootStore.commonStore.token!,
      })
      .configureLogging(LogLevel.Information)
      // i have to do this for now. Need to fix that disconnecting right
      // after Clients.All.SendAsync("ReceiveComment", comment); in ChatHub.cs
      // .withAutomaticReconnect([0, 0, 10000])
      .build();
    
    this.hubConnection
      .start()
      .then(() => console.log(this.hubConnection!.state))
      .catch((error) => console.log("Error establishing connection: ", error));

    this.hubConnection.on("ReceiveComment", (comment) => {
      runInAction(() => {
        if (this.comments == null) {
          this.comments = new Array<IComment>();
        }
        this.comments.push(comment);
      });
    });
  };

  @action stopHubConnection = () => {
    this.hubConnection!.stop();
  };
  
  @action addComment = async (values: any) => {
    try {
      await this.hubConnection!.invoke("SendComment", values);
    } catch (error) {
      console.log(error);
    }
  };

标签: reactjssignalr

解决方案


在 Asp.net Core 3.1 中连接到 SignalR Hub 时,我有一个 Angular 客户端面临同样的问题。应用的 NuGet 包是“Microsoft.AspNetCore.SignalR.Core”版本 1.1.0。将 Asp.net Web API 门户升级到 .Net 5.0 后。问题已解决。


推荐阅读