Как я могу остановить вызовы IDisposable при рендеринге страницы на сервере Blazor? - PullRequest
0 голосов
/ 09 февраля 2020

Вот мой код:

@page "/"
@using Microsoft.AspNetCore.Components.Server.Circuits
@inject CircuitHandler circuitHandler
@implements IDisposable

<h1>Hello, world!</h1>

Welcome to your new app.

@code{
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            Console.WriteLine("123");//do something
        }
    }
    #region//circuitHandler
    protected override void OnInitialized()
    {
        // Subscribe to the event handler
        (circuitHandler as CircuitHandlerService).CircuitsChanged +=
             HandleCircuitsChanged;

    }


    public void HandleCircuitsChanged(object sender, EventArgs args)
    {
        Console.WriteLine("123");//do something
    }
    public void Dispose()
    {
        (circuitHandler as CircuitHandlerService).CircuitsChanged -=
          HandleCircuitsChanged;

    }
    #endregion
}

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

namespace BlazorApp2
{
    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);
        }
    }
}

Мне нужно CircuitHandler, чтобы узнать, закрыта ли страница. Теперь я столкнулся со странной проблемой. Когда страница загружена, IDisposable всегда вызывается, даже если страница не закрыта. Более того, в OnAfterRenderAsync есть несколько кодов. Когда вызывается IDisposable, коды в OnAfterRenderAsync, которые не были завершены, внезапно прекратят работу без каких-либо ошибок. Кто-то сказал мне, чтобы установить

@(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))

в _Host.cshtml на

@(await Html.RenderComponentAsync<App>(RenderMode.Server))

, чтобы решить эту проблему. Я пытался, но проблема все еще здесь. Как я могу решить это? Спасибо.

1 Ответ

2 голосов
/ 09 февраля 2020

фрагмент кода ниже точно такой же, как у вас, и он прекрасно работает для меня. Метод Dispose вызывается только тогда, когда цепь замкнута. Я опубликую ниже весь код, который я использую, скопируйте и запустите его, а затем постараюсь помочь с другими имеющимися у вас проблемами.

<app>
        @(await Html.RenderComponentAsync<App>(RenderMode.Server))
 </app>

Примечание: я публикую здесь весь контент файлов. Вам придется настроить пространства имен моего приложения с помощью своего.

Код для 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);
    }

 }
}

Код для Index.razor

@page "/"

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

@inject CircuitHandler circuitHandler
@implements IDisposable


<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)
{
    InvokeAsync(() => StateHasChanged());
}
}

Также Запуск класс

public void ConfigureServices(IServiceCollection services)
    {
        // Removed for brevity....

        services.AddSingleton<CircuitHandler>(new CircuitHandlerService());
    }

И, конечно, _Host.cs html

<app>
        @(await Html.RenderComponentAsync<App>(RenderMode.Server))
</app>

Пожалуйста, не забудьте сообщить ...

...