页面重新加载后 SignalR 事件监听器是否正确处理?

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

我有一个页面组件,我在其中添加了 SignalR

HubConnection
:

@page "/test"
@using System.Diagnostics
@using Microsoft.AspNetCore.SignalR.Client
@rendermode InteractiveServer

@implements IAsyncDisposable

<PageTitle>Test</PageTitle>

<button @onclick="SendMessage">Send Message</button>

@foreach(var m in _messages)
{
    <p>@m</p>
}

@code {
    private readonly List<string> _messages = [];
    private HubConnection? _hubConnection;

    protected override async Task OnInitializedAsync()
    {
        _hubConnection = new HubConnectionBuilder()
            .WithUrl("http://localhost:5200/message")
            .WithAutomaticReconnect()
            .Build();

        _hubConnection.On<string>("OnMessage", GetMessage);

        await _hubConnection.StartAsync();

        await base.OnInitializedAsync();
    }

    private void GetMessage(string message)
    {
        _messages.Add(message);
        Debug.WriteLine(message);
        InvokeAsync(StateHasChanged);
    }

    public async ValueTask DisposeAsync()
    {
        if (_hubConnection is not null)
        {
            _hubConnection.Remove("OnMessage");
            await _hubConnection.StopAsync();
            await _hubConnection.DisposeAsync();
        }
    }

    private async Task SendMessage()
    {
        await _hubConnection.SendAsync("SendMessage", "Hello");
    }

}

使用此代码,您可以通过单击按钮发送消息,每个连接的客户端都会收到此消息。

在服务器上我只是将消息转发给所有客户端

public async Task SendMessage(string message)
{
    await Clients.All.SendAsync("OnMessage", message);
}

在我的

GetMessage
函数中,我将消息写入输出窗口
Debug.WriteLine(message);

当我打开页面并单击发送按钮时,消息将在我的页面上显示一次,并在输出窗口中显示一次。 但是,如果我刷新页面并再次单击,该消息将在我的页面上显示一次,但在我的输出窗口中显示两次,就好像第一个事件侦听器仍然已注册,尽管它应该已被处理,不是吗?

如果您跟踪当前电路并将其也放入输出中,您可以看到

GetMessage
函数从两个电路(刷新之前的电路和刷新之后的电路)中调用(我没有将其放入代码中)为了简单起见)。

事件处理程序是否没有正确处理?当集线器连接关闭并处置时,它如何工作?我在这里误解了什么?

c# blazor signalr blazor-server-side
1个回答
0
投票

问题似乎与 Blazor 组件的生命周期和 SignalR 连接未得到正确管理或处置有关。在开始新电路之前,请确保完全处理掉之前的电路。

试试这个代码:

@page "/test"
@using System.Diagnostics
@using Microsoft.AspNetCore.SignalR.Client
@rendermode InteractiveServer

@implements IAsyncDisposable

<PageTitle>Test</PageTitle>

<button @onclick="SendMessage">Send Message</button>

@foreach(var m in _messages)
{
    <p>@m</p>
}

@code {
    private readonly List<string> _messages = new();
    private HubConnection? _hubConnection;
    private CancellationTokenSource _cancellationTokenSource = new();

    protected override async Task OnInitializedAsync()
    {
        _hubConnection = new HubConnectionBuilder()
            .WithUrl("http://localhost:5200/message")
            .WithAutomaticReconnect()
            .Build();

        _hubConnection.On<string>("OnMessage", GetMessage);

        _cancellationTokenSource = new CancellationTokenSource();
        await _hubConnection.StartAsync(_cancellationTokenSource.Token);

        await base.OnInitializedAsync();
    }

    private void GetMessage(string message)
    {
        _messages.Add(message);
        Debug.WriteLine($"Circuit ID: {CircuitHandler.Current?.CircuitId}, Message: {message}");
        InvokeAsync(StateHasChanged);
    }

    public async ValueTask DisposeAsync()
    {
        _cancellationTokenSource.Cancel();
        
        if (_hubConnection is not null)
        {
            _hubConnection.Remove("OnMessage");
            await _hubConnection.StopAsync();
            await _hubConnection.DisposeAsync();
        }
    }

    private async Task SendMessage()
    {
        if (_hubConnection != null)
        {
            await _hubConnection.SendAsync("SendMessage", "Hello");
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.