我创建了基本的Blazor服务器端聊天,但是从不调用OnDisconnectedAsync,即使关闭浏览器,连接仍保持活动状态。我在这里创建了一个仓库,并提供了一个最小的,可复制的示例:
https://github.com/francescocristallo/BlazorAppServerChat
OnDisconnectAsync方法位于ChatHub.cs内部:
public override async Task OnDisconnectedAsync(Exception exception)
{
Debug.WriteLine("Disconnected");
}
如果改用Blazor WebAssembly,则相同的代码有效。我不明白这是错误还是缺少的内容。
您的代码在使用客户端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());
}
}
希望它能奏效,这就是您应该如何创建聊天记录...
我弄清楚了为什么不调用OnDisconnect:
Blazor服务器处理该连接,但不处理必须手动处理的HubConnection。由于Blazor不支持IAsyncDisposable,因此不会等待对DisposeAsync的调用,也不要等待DisposeAsync:
@implements IDisposable
... rest of component code ...
@code {
public void Dispose()
{
_hubConnection.DisposeAsync();
}
}
这不仅适用于Blazor Server。如果Blazor WebAssembly上的集线器连接位于单个组件中,则也必须对其进行处置。