websocket 使用SignalR托管的Blazor Webassembly中的连接问题

zwghvu4y  于 2023-04-06  发布在  其他
关注(0)|答案(1)|浏览(360)

摘要

我正在做一个微服务项目,有几个客户端访问(mvcasp.netweb应用程序,托管的blazor webassembly等)都在kubernetes集群中。最近我将所有应用程序更新到.NET 7,但我不知道这是否是我的问题的原因。

症状

在Blazor Webassembly(Hosted)PWA中,我使用SignalR Hub进行Blazor.Client和Blazor.Server之间的通信。当我调用页面时,然后在页面完全加载之前立即返回,我会得到Web Socket错误。另一方面,应用程序非常慢。

错误

  • 未处理异常渲染组件:**无法访问已释放的对象。**对象名称:'集线器连接'.系统.对象处理异常....在集线器连接中.发送核心异步... *
  • 未处理异常渲染组件:如果连接未处于活动状态,则无法调用“SendCoreAsync”方法。System.InvalidOperationException....in ReconnectingConnectionState.WaitForActiveConnectionAsync ... *
    尝试变通办法

我试图捕捉这些异常,因为我找不到原因或解决方案(扩展方法CallAsync):

if ( hubConnection is not null )
{
    try
    {    
        await hubConnection.SendAsync( methodName, arg1, arg2, cancellationToken );
    }
    catch ( ObjectDisposedException ) { }
    catch ( InvalidOperationException ) { }
}

但我还是得到错误消息“操作已取消”。

更多代码

在方法(客户端)中创建集线器连接:

var hubConnection = new HubConnectionBuilder()
    .WithUrl( Navigator.ToAbsoluteUri( hubPath ), options =>
    {
        options.AccessTokenProvider = () => Task.FromResult( ((AuthStateProvider)AuthStateProv).Token );
        // added the next lines later to try out
        options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets;
        options.SkipNegotiation = true;
    })
    .WithAutomaticReconnect()
    .Build();

使用集线器连接(客户端):

// this is the method above passing the hubPath
hubConnection = CreateHubConnection( "/testhub" );
hubConnection.On<MyDataModel>( "ReceiveData", ( result ) => HandleData( result ) );
await hubConnection.StartAsync();
// calling method (first code above)
await CallAsync( hubConnection, "RequestData" );

在剃刀组件中处理轮毂连接:

public override async ValueTask DisposeAsync()
{
    if ( hubConnection is not null )
    {
        try
        {
            await hubConnection.StopAsync();
        }
        finally
        {
            await hubConnection.DisposeAsync();
        }
    }
}

服务器(Server):

public class TestHub : BaseHub
{
    public async Task RequestData()
    {
        // get data from a microservice api
        var result = await _getQuery.Get();

        await Clients.Caller.SendAsync( "ReceiveData", result );
    }
}

Blazor.服务器启动配置(Program.cs):

builder.Services.AddSignalR( options =>
{
    options.ClientTimeoutInterval = TimeSpan.FromSeconds( 60 );
    options.HandshakeTimeout = TimeSpan.FromSeconds( 30 );
    options.MaximumParallelInvocationsPerClient = 3;
    options.EnableDetailedErrors = true;
} );
builder.Services.AddResponseCompression( opts =>
{
    opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
        new[] { "application/octet-stream" } );
} );

var app = builder.Build();

app.UseResponseCompression();

app.MapHub<TestHub>( "/testhub" );

首先,我在浏览器中收到此消息:* 警告:Web浏览器不支持关闭WebSocket的输出端。CloseOutputAsync已关闭套接字并丢弃所有传入消息。*

krugob8w

krugob8w1#

经过密集的调试,我可以定位异常。
当用户在页面加载时首先返回时,调用了剃刀页面中的DisposeAsync,并且hubConnection被释放但不为null,然后调用OnInitializedAsync,在此创建并启动hubConnection。我还在启动hubConnection后调用了一个方法。因此,在启动hubConnection时抛出了第一个Exception:StartAsync中的OperationCanceledException。调用hub方法时抛出第二个Exception:因此,在这两个位置,我需要添加try/catches,正如jdweng所注意到的那样。
在方法调用中,我已经有了try/catch(参见第一段代码)。我只是在StartAsync中添加了另一个:

try
{
    await hubConnection.StartAsync();
}
catch ( OperationCanceledException ) { }

btw hubConnection.StopAsync不需要,因为hubConnection.DisposeAsync正在停止hubConnection。HubConnection SendCoreAsyncCore方法首先检查它是否被释放并抛出Exception,在100次调用后,它检查CancellationToken并带有注解“Bail early for cancellation”。

相关问题