How can I stop IDisposable invokes while render the page in blazor server-side?

我怕爱的太早我们不能终老 提交于 2020-03-26 03:53:57

问题


Here is my code:

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



I need the CircuitHandler to get to know whether the page is closed.

Now I met a strange problem. When the page is loaded, the IDisposable always invoke even the page is not closed.

What's more, there are several codes in OnAfterRenderAsync. When the IDisposable invokes, the codes in OnAfterRenderAsync which not runs finished will suddenly break without any error.

Someone told me to set the

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

in _Host.cshtml to

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

can solve this.

I tried, but the problem still here.

How can I solve this? Thank you.


回答1:


the code snippet below is exactly like yours, and it works for me perfectly fine. The Dispose method is called only when a Circuit is closed. I'll post below the entire code I use, copy and run it, then I'll try to help with other issues you have.

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

Note: I'm posting here entire files' content. You'll have to adjust the namespaces of my app with yours.

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

 }
}

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

Also Startup class

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

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

And of course _Host.cshtml

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

Please, don't fail to report ...



来源:https://stackoverflow.com/questions/60133938/how-can-i-stop-idisposable-invokes-while-render-the-page-in-blazor-server-side

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!