如何在 Blazor 服务器端的 CircuitHandler 中调用方法?

Mel*_* NG 6 c# .net-core asp.net-core blazor blazor-server-side

我正在通过 Blazor 服务器端制作聊天室应用程序。我想显示每个用户的在线状态。

我在如何在 blazor 服务器端关闭页面时获取事件中询问了如何在关闭页面时获取事件的问题?

现在看来这CircuitHandler是最好的选择。

当用户关闭页面时,我想在数据库中设置一个用户状态从在线到离线。而且,每个用户的主键暂时存储在index.razor.

但是现在OnCircuitClosedAsync(Circuit, CancellationToken)跑完之后,不知道怎么调用方法来实现这个(无法获取到Blazor前端的变量,也无法调用前端的Blazor方法)。

PS:这里是后端的代码:

using Microsoft.AspNetCore.Components.Server.Circuits;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;


namespace BlazorCircuitHandler.Services
{
    public class CircuitHandlerService : CircuitHandler
    {
        public ConcurrentDictionary<string, Circuit> Circuits { get; set; }

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

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

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

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

        public override Task OnConnectionUpAsync(Circuit circuit, CancellationToken cancellationToken)
        {
            return base.OnConnectionUpAsync(circuit, cancellationToken);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是前端:

@page "/"

@using Microsoft.AspNetCore.Components.Server.Circuits
@inject CircuitHandler CircuitHandlerService

<h1>Hello, world!</h1>

Welcome to your new app.

<p>
    Number of Circuits: @((CircuitHandlerService as BlazorCircuitHandler.Services.CircuitHandlerService).Circuits.Count)

    <ul>
        @foreach (var circuit in (CircuitHandlerService as BlazorCircuitHandler.Services.CircuitHandlerService).Circuits)
        {
            <li>@circuit.Key</li>            
        }
    </ul>
    @{ 
        var PrimaryKey = "abcdefg";
    }
</p>
Run Code Online (Sandbox Code Playgroud)

你能帮我吗?谢谢你。

Isa*_*aac 6

这应该有效,我猜;)

CircuitHandlerService.cs

using Microsoft.AspNetCore.Components.Server.Circuits;
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;


namespace BlazorCircuitHandler.Services
{
    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)
      {
           Circuit circuitRemoved;
           Circuits.TryRemove(circuit.Id, out circuitRemoved);
           OnCircuitsChanged();
           return base.OnCircuitClosedAsync(circuit, 
                             cancellationToken);
      }

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

      public override Task OnConnectionUpAsync(Circuit circuit, 
                          CancellationToken cancellationToken)
      {
          return base.OnConnectionUpAsync(circuit, cancellationToken);
      }
   }
 }
Run Code Online (Sandbox Code Playgroud)

用法

@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()
   {
       // Subscribe to the event handler
    (circuitHandler as CircuitHandlerService).CircuitsChanged += 
         HandleCircuitsChanged;
    
    }

 public void Dispose()
 {
    // Unsubscribe the event handler when the component is disposed
    (circuitHandler as CircuitHandlerService).CircuitsChanged -= 
      HandleCircuitsChanged;
   
 }

 public void HandleCircuitsChanged(object sender, EventArgs args)
 {
    // notify the component that its state has changed 
    // Important: You must use InvokeAsync
    InvokeAsync(() => StateHasChanged());
 }
}
Run Code Online (Sandbox Code Playgroud)

启动文件

public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
            services.AddServerSideBlazor();

            services.AddSingleton<CircuitHandler>(new CircuitHandlerService());
        }
Run Code Online (Sandbox Code Playgroud)

注意:要验证它是否正常运行,请运行该应用程序。然后再打开两个标签。现在,关闭您打开的第一个选项卡(从左到右),然后关闭第二个选项卡。请注意活动电路数量的显示...

  • 此方法看起来很适合确定用户何时与服务器断开连接。我想知道确定“哪个”用户与服务器断开连接是否也有用。例如,是否可以将 CircuitKey 与给定用户相关联?在我的应用程序中,我有兴趣知道给定用户何时断开连接,因此我可以将它们从数据库中删除。 (2认同)