Blazor 问题 - 进行异步调用后立即关闭 circuit\connection

Blazor question- close circuit\connection immediately after making async call

我有一个 blazor 集成,基本上,在一段不确定的时间后我看到这个屏幕:

有没有办法阻止这种情况的发生?我担心的是,在我从服务器端调用获得所需数据后,我可能不会关闭 circuits/connections。

我的 ComponentBase 中有这个 class:

  protected override async Task OnInitializedAsync()
    {
         await DoStuff();
    }

调用这个:

 private async Task DoStuff()
    {

        var results= await httpClient.GetJsonAsync<MyResultsClass>(someResultsUrl);
          ...  
        StateHasChanged();
    }

但我想知道事后是否需要一些东西(可能需要实现 IDisposable,对任何创建的电路有某种句柄,并立即处理它)以确保它被自动清理?该消息永远不会显示,并且在我获得所需结果后无需保持任何类型的连接打开。我只是不知道我需要什么样的 handler\object 来代表正在建立的 Blazorconnection。

我找到了 link 但是完成一件小事似乎很多。

编辑:在尝试建议的解决方案后,我发现行为略有不同,其中包含一条消息"Attempting to reconnect to server"。如果这不起作用,我会看到 "Could not reconnect to the server. Reload the page to restore functionality"。有没有办法自动执行此操作,或者至少无法通过自动关闭 connection\circuit (如果不需要)来完全阻止它?

编辑 2:如果自动重新连接也适用,if\where 可能 - 如果我长时间打开我的 blazor 页面,重新连接不会' 似乎工作。但是,如果它在失去连接的那一刻重新连接,我想它会有帮助吗?

编辑 3:如果页面自动刷新 而不是 重新连接,我会很高兴的另一种选择 - 这会起作用对我来说就好了。

编辑 4:(回应 )- 帮助很大,谢谢!我同意,试图强行关闭连接是一种黑客行为。我只是希望有一种方法可以优雅地关闭连接,因为我知道一旦 DoStuff() 完成了它需要做的事情,它就可以释放资源——而不是不必要地拖延。如果这是我必须忍受的 Blazor 的后果,那很好。我找到了一种方法来抑制出现的 "Hateful screen"(如您所说),这很棒,但如果我可以清理 "Error: Connection disconnected with error "Error: WebSocket closed with status code 就更好了: 1006().'我已经看到很多关于该错误的线程,它们大多倾向于强制自动刷新的解决方案。我实际上并不关心错误是否会发生,我只是想确保它最终会释放资源(如果它自动发生,那么我也很好。) - 理想情况下希望成为能够 catch\ignore 该错误消息,但如果这是我应该关心的事情,那么...我不想忽略它。此外,这个问题很容易重现,我不必回收我的网站应用程序池或类似的东西。

你也可以通过实现IDisposable/IAsyncDisposable来实现。参考 this github 问题。

但是,CircuitHandler相对于对象初始化和处置来说更清晰和更好。

我建议采用建议的解决方案

电路处理程序是通过从 CircuitHandler 派生并在应用程序的服务容器中注册 class 来实现的。以下电路处理程序示例跟踪打开的 SignalR 连接:

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

public class TrackingCircuitHandler : CircuitHandler
{
    private HashSet<Circuit> circuits = new HashSet<Circuit>();

    public override Task OnConnectionUpAsync(Circuit circuit, 
        CancellationToken cancellationToken)
    {
        circuits.Add(circuit);

        return Task.CompletedTask;
    }

    public override Task OnConnectionDownAsync(Circuit circuit, 
        CancellationToken cancellationToken)
    {
        circuits.Remove(circuit);

        return Task.CompletedTask;
    }

    public int ConnectedCircuits => circuits.Count;
}

Statup.cs

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSingleton<CircuitHandler, TrackingCircuitHandler>();
}

参考 this 了解更多详情。

I found this link but it seems like a lot to accomplish one little thing.

与你面对的 'issue' 无关。

Is there no way to prevent this from happening?

不,没有。此行为是设计使然。当与您的 Blazor 服务器应用程序的连接丢失并且无法自动重新建立时,就会发生这种情况,例如,在开发期间,您 运行 您的应用程序,更改代码并保存,但是你瞧,你看到带有消息的屏幕:正在尝试重新连接到服务器...,一段时间后它变为:无法重新连接到服务器。重新加载页面以恢复功能。

很明显,这是一个与服务器的连接丢失的例子,浏览器试图重新连接,但无济于事,因为服务器已经破坏了电路。如果您重新加载或刷新页面,服务器会创建一个空状态的新电路;也就是说,先前的状态(数据)丢失了。这相当于关闭并重新打开浏览器。

同样,可能还有其他原因都与连接丢失有关,并且从外部(UI 屏幕)看起来是一样的。之所以给出上面的例子,是因为它容易掌握,也很容易重现。

电路连接丢失的原因有很多:

  • 服务器不可用(被盗、被毁、着火、断电等)

  • 服务器必须在超时后释放断开的电路

  • 服务器内存不足。

  • 一些内部问题等

所有这些都与您编码的方式和内容无关。如果您进行 HTTP 调用并提供错误的 url,您将在页面底部收到消息 "An unhandled exception has occurred. See browser dev tools for details."。这是给你的,开发者。自然地,连接也丢失了。罪魁祸首是服务器,也是错误代码的原因,在这种情况下,您可以更新代码,然后重新 运行 您的应用程序。在生产场景中,当然应该处理异常,防止服务器关闭连接。

区分上述两种情况很重要。第一个大部分是你无法控制的,第二个不是......你应该编写健壮的代码......

But I'm wondering if I need something after the fact (maybe need to implement IDisposable, have some kind of a handle to any created circuits, and dispose of it immediately) to make sure that it gets automatically cleaned up?

只有在必须释放资源时才实施 IDisposable,尽管实施 您应用的每个组件中的 IDisposable 不会造成任何伤害。

为什么要破坏电路。你创造了他们,你想要摧毁他们!电路是保存您的连接、应用程序状态等的对象。它不是您创建的,您不应该尝试触摸它。创建 HttpClient 对象并访问 Web api 端点,可能会导致 运行 时间错误,并关闭与服务器的连接,除非您处理异常,但同样与可恶的屏幕……通常情况下,您什么都不做……比如 "to make sure that it gets automatically cleaned up"。你想清理什么?!

That message should never show, Remember, by design ?

and there is no need to keep any kind of connection open after I get the results I need.

什么关系?到服务器?到网络 Api ?你不应该做那种事。

I just don't know what sort of handler\object I need that represents the Blazorconnection that is being made.

在那种情况下,我的链接答案会有所帮助,但这不是问题的根源,您不应该玩弄连接对象。

Is there no way to automate this, or, at least, prevent it completely by automatically closing the connection\circuit (if it isn't needed)?

到现在为止,您应该了解服务器关闭连接会导致此消息,该消息由尝试重新连接到服务器的 JavaScript SignalR 代码生成。你不应该尝试那样做,你也不能那样做。伙计,不要破坏你的联系……如果可能的话,尝试解决相关问题,并接受这是预期的行为。这是您在使用 Blazor Server App (SinalR) 时必须支付的 "price"。

it would also be suitable if the reconnection happened automatically, if\where possible - if I leave my blazor page open for a long time, reconnection doesn't seem to work. But, if it were to reconnect at the moment it lost connection, I presume that it could help?

是的,here's a link 这样做,但请记住:这应该是一个临时解决方案,直到 Blazor 团队提出更好的解决方案。

refreshed instead of a reconnection

当您的页面刷新时,服务器会创建一个应用程序状态为空的新电路。当您的页面尝试重新连接时,意味着在不丢失应用程序状态和数据的情况下重新连接到服务器上断开连接的电路

请问您获得 'hateful screen' 的频率是否与查看给定页面有关,例如,每当您访问计数器页面并点击增加按钮等时。

希望这对您有所帮助...

I was just hoping there was a way to gracefully close the connection, knowing that once DoStuff() is done doing what it needs to do, it can release the resources - instead of unnecessarily lingering.

是,关闭连接的代码(JavaScript,SignalR):

  if (connection) {
    connection.stop();
  }

但是为什么要这样做呢?

这不是 windows 桌面应用,这是一个网络应用 运行 通过 SignalR,通过电路连接实现通信。请不要尝试这样编码。当用户关闭网页时,您的连接应该正常关闭。了解关闭连接然后打开新连接会导致丢失应用程序状态和为页面创建的数据。

DoStuff()有运行后,你想释放什么资源?您是否使用必须释放的外部资源?如果你这样做,这可以通过实现 IDisposable 接口轻松完成。这主要是为了防止内存占用 link,因为 Blazor 不断地创建和销毁组件。

but would be nice if I could clean up the "Error: Connection disconnected with error "Error: WebSocket closed with status code: 1006 ().'

我想这是可行的...

I've seen a lot of threads about that error, and they mostly lean to the solution of force an automatic refresh

正是...因为他们想要有源和带电的电路连接。但是你想终止你的连接。

I just want to make sure that it will eventually free up the resources

再次资源 ???我在试着理解你?您是指服务器使用的资源吗?也许是因为资源稀缺?如果是,那么我的回答是肯定的。这是来自文档:

The server can't retain a disconnected circuit forever. The server must release a disconnected circuit after a timeout or when the server is under memory pressure.

所以大家放心,资源会毫不留情的释放...