Как я могу вызвать метод в CircuitHandler на стороне сервера Blazor? - PullRequest
3 голосов
/ 31 января 2020

Я делаю приложение для чата на стороне сервера 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);
        }
    }
}

А вот интерфейс:

@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>

Не могли бы вы мне помочь? Спасибо.

Ответы [ 2 ]

3 голосов
/ 31 января 2020

Это должно работать, я думаю;)

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);
      }
   }
 }

Использование

@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());
 }
}

Примечание: Чтобы убедиться, что это работает, запустите приложение. Затем откройте еще две вкладки. Теперь закройте первую открытую вкладку (слева направо), затем вторую. Обратите внимание на отображение количества активных цепей ...

0 голосов
/ 31 января 2020

Вы можете просто представить событие в вашем обработчике схемы:

public class CircuitHandlerService : CircuitHandler
{
    public event EventHandler CircuitsChanged;

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

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

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

И затем, в вашем компоненте Razor, вы можете подписаться на это событие и обновить sh пользовательский интерфейс при необходимости:

@implements IDisposable
@inject CircuitHandler circuitHandler

<ul>
    @foreach (var circuit in Circuits)
    {
        <li>@circuit.Key</li>
    }
</ul>

@code {
    private IDictionary<string, Circuit> Circuits
        => (circuitHandler as CircuitHandlerService).Circuits;

    protected override void OnInitialized()
    {
        // register event handler
        (circuitHandler as CircuitHandlerService).CircuitsChanged += HandleCircuitsChanged;
    }

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

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