【问题标题】:How can I stop IDisposable invokes while render the page in blazor server-side?如何在 blazor 服务器端呈现页面时停止 IDisposable 调用?
【发布时间】:2020-05-24 19:11:32
【问题描述】:

这是我的代码:

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

可以解决这个问题。

我试过了,但问题仍然存在。

我该如何解决这个问题?谢谢。

【问题讨论】:

    标签: asp.net-core .net-core blazor


    【解决方案1】:

    下面的代码 sn-p 和你的一模一样,它对我来说非常好用。 Dispose 方法仅在 Circuit 关闭时调用。我将在我使用的整个代码下方发布,复制并运行它,然后我会尝试帮助您解决其他问题。

    <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.cshtml

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

    请不要不报告...

    【讨论】:

    • 终于找到了问题所在。实际上,您的方法确实有效。问题是我使用 Visual Studio Code 来调试服务器计算机上的程序。我的代码中有一个错误,而 Visual Studio Code 在我使用 try&catch 之前从未报告过它。当程序运行到bug的代码行时,页面崩溃,并自动调用dispose方法。
    • 无论如何,我会接受你的回答,因为它可以帮助任何其他在页面加载时遇到 IDisposable 调用的人。
    • 还有,我想知道为什么在 RenderMode.ServerPrerendered 中加载页面时 IDisposable 会调用
    猜你喜欢
    • 1970-01-01
    • 2020-12-18
    • 1970-01-01
    • 2020-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-03
    • 1970-01-01
    相关资源
    最近更新 更多