Blazor服务器端的Asp.Net Core SignalR从不调用OnDisconnectedAsync

问题描述 投票:0回答:2

我创建了基本的Blazor服务器端聊天,但是从不调用OnDisconnectedAsync,即使关闭浏览器,连接仍保持活动状态。我在这里创建了一个仓库,并提供了一个最小的,可复制的示例:

https://github.com/francescocristallo/BlazorAppServerChat

OnDisconnectAsync方法位于ChatHub.cs内部:

public override async Task OnDisconnectedAsync(Exception exception)
    {
        Debug.WriteLine("Disconnected");
    }

如果改用Blazor WebAssembly,则相同的代码有效。我不明白这是错误还是缺少的内容。

signalr blazor blazor-server-side asp.net-core-signalr
2个回答
0
投票

您的代码在使用客户端SignalR的Blazor WebAssembly应用程序上运行良好,但是在Blazor Server Apps上则有所不同。

[在Blazor服务器中已经有一个用于启用Blazor Server App的客户端部分和服务器部分之间的通信的连接时,为什么必须创建SignalR连接...

我曾经在Blazor部分回答了一个问题,当服务器端Blazor中编写的聊天应用程序中的用户突然关闭浏览器时,我们希望如何处理,例如保存与他有关的数据,等等。您可以在我的答案中查找。抱歉,但我不记得它的位置。但是,我拥有此代码,因此可以指导您正确的方向:

原则上,您需要实现一个从CircuitHandler服务派生的服务:

public class CircuitHandlerService : CircuitHandler 
{
    public ConcurrentDictionary<string, Circuit> Circuits { get; set; }
    public event EventHandler CircuitsChanged;

    protected virtual void OnCircuitsChanged()
    => CircuitsChanged?.Invoke(this, EventArgs.Empty);

    public CircuitHandlerService()
    {
        Circuits = new ConcurrentDictionary<string, Circuit>();
    }

    public override Task OnCircuitOpenedAsync(Circuit circuit, CancellationToken cancellationToken)
    {
        Circuits[circuit.Id] = circuit;
        OnCircuitsChanged();
        return base.OnCircuitOpenedAsync(circuit, cancellationToken);
    }

    public override Task OnCircuitClosedAsync(Circuit circuit, CancellationToken cancellationToken)
    {
        Console.WriteLine("OnCircuitClosedAsync");
        Circuit circuitRemoved;
        Circuits.TryRemove(circuit.Id, out circuitRemoved);
        OnCircuitsChanged();
        return base.OnCircuitClosedAsync(circuit, cancellationToken);
    }

    public override Task OnConnectionDownAsync(Circuit circuit, CancellationToken cancellationToken)
    {
        Console.WriteLine("OnConnectionDownAsync");
        return base.OnConnectionDownAsync(circuit, cancellationToken);
    }

    public override Task OnConnectionUpAsync(Circuit circuit, CancellationToken cancellationToken)
    {
        return base.OnConnectionUpAsync(circuit, cancellationToken);
    }

}

这就是您使用服务的方式:

@page "/"

@using Microsoft.AspNetCore.Components.Server.Circuits
@using BlazorCircuitHandler.Services

@inject CircuitHandler circuitHandler
@implements IDisposable



<h1>Hello, world!</h1>

Welcome to your new app.

<p>
Number of Circuits: @((circuitHandler as 
    BlazorCircuitHandler.Services.CircuitHandlerService).Circuits.Count)
<ul>
    @foreach (var circuit in (circuitHandler as 
       BlazorCircuitHandler.Services.CircuitHandlerService).Circuits)
    {
        <li>@circuit.Key</li>
    }
</ul>
</p>

@code {

protected override void OnInitialized()
{
    (circuitHandler as CircuitHandlerService).CircuitsChanged += 
     HandleCircuitsChanged;

}

public void Dispose()
{

    (circuitHandler as CircuitHandlerService).CircuitsChanged -= 
    HandleCircuitsChanged;

}

public void HandleCircuitsChanged(object sender, EventArgs args)
{
    // notify the UI that the state has changed
       InvokeAsync(() => StateHasChanged());
}
}

希望它能奏效,这就是您应该如何创建聊天记录...


0
投票

我弄清楚了为什么不调用OnDisconnect:

Blazor服务器处理该连接,但不处理必须手动处理的HubConnection。由于Blazor不支持IAsyncDisposable,因此不会等待对DisposeAsync的调用,也不要等待DisposeAsync:

@implements IDisposable

... rest of component code ...

@code {
    public void Dispose()
    {
        _hubConnection.DisposeAsync();
    }
}

这不仅适用于Blazor Server。如果Blazor WebAssembly上的集线器连接位于单个组件中,则也必须对其进行处置。

© www.soinside.com 2019 - 2024. All rights reserved.