【问题标题】:Blazor InvokeAsync no longer working after page reload页面重新加载后 Blazor InvokeAsync 不再工作
【发布时间】:2022-01-19 04:23:14
【问题描述】:

我有一个 Blazor 页面(服务器端),它使用对 Azure 服务总线的异步调用来获取一些数据并将结果打印到页面。一开始一切正常。但是,如果用户重新加载页面,则页面不会按预期重新呈现。

断点调试显示模型更新,页面重载后调用StateHasChanged;它只是没有做任何事情。我的印象是InvokeAsync 应该始终使用 UI 线程,但在页面重新加载后似乎并非如此。

protected override async Task OnAfterRenderAsync(bool firstRender)
{
  // On page load. Service bus watcher is hooked up here
  await serviceBusHandler.WatchQueue("servicebus-queue", MessageHandler, async _ => await Task.CompletedTask);
}

// "request" method; calls a Service Bus method get a new value for our model
private async Task SaveAndGetAmount()
{
  IsLoading = true;

  // creation of Service Bus message omitted
  // post to "servicebus-queue" with message here
}

private async Task MessageHandler(ProcessSessionMessageEventArgs args)
{
  var result = ... // parsing of "args" message omitted

  await args.CompleteMessageAsync(args.Message); // mark Azure Functions message received
  
  await InvokeAsync(() =>
  {
    IsLoading = false;
    Model.Amount = result.Amount; // update page model here
    StateHasChanged(); // indicate to UI that the model has changed, and the page must re-render
  });

此外,我在Model.Amount 属性中添加了一个手表,它表现出一些奇怪的行为。如果在初始页面加载时设置为 23,则手表将始终在 SaveAndGetAmount 方法中的断点处显示 23,就好像它永远不会被 MessageHandler 方法更新一样。

【问题讨论】:

  • InvokeAsync 没有损坏。问题出在其他地方。最好的是minimal reproducible example,但至少显示 MessageHandler 是如何被调用的。图中有async void方法吗?
  • 谢谢;我添加了对 MessageHandler 的调用。它是服务总线连接的一部分。
  • 有人添加了几个async void 方法,但我认为它们与此代码没有直接关系。当我用async Task 替换它们时,它破坏了我的加载微调器(我的问题中的IsLoading 变量),烦人。
  • 你应该在每个 OnAfterRenderAsync 上调用 WatchQueue,就在 firstRender 为真时。亨克霍尔特曼是对的。问题出在其他地方。您发布的代码有效
  • 我不确定我是否遵循; WatchQueue 确实 被每个OnAfterRenderAsync 调用;我们忽略firstRender

标签: c# async-await blazor blazor-server-side .net-6.0


【解决方案1】:

WatchQueue 在每个 OnAfterRenderAsync 上都会被调用;我们忽略 firstRender

protected override async Task OnAfterRenderAsync(bool firstRender)
{
  // On page load. Service bus watcher is hooked up here
  await serviceBusHandler.WatchQueue("servicebus-queue", MessageHandler, async _ => await Task.CompletedTask);
}

这里只是一个猜测,但这意味着每个 (Re)Render 都会添加一个消息处理程序。这是错误的,但只要您在页面的同一实例上,就会被忽视。

重新加载后,您的消息仍会在旧(已失效)页面上处理。这就是我认为您在调试器中看到的情况。

如果我是对的,解决方案有两个:

@implements IDisposable

protected override async Task OnAfterRenderAsync(bool firstRender)
{
  if (firstRender)  // only once per page
  {
    // On page load. Service bus watcher is hooked up here
    await serviceBusHandler.WatchQueue("servicebus-queue", MessageHandler, async _ => await Task.CompletedTask);
  }
}

public void Dispose()
{
  // somehow undo the WatchQueue 
}

如果你不能解开那个处理程序,那么它就在错误的地方。

【讨论】:

  • 是的,就是这样。我猜我们在页面加载时创建了太多这样的处理程序。
  • 您是否有理由将serviceBusHandler 连接到OnAfterRenderAsync 而不是OnInitialisedAsync
  • @MrCakaShaunCurtis 如果我们这样做,页面将无法正常工作。我收到类似“...启用预渲染时,JavaScript 互操作调用只能在 OnAfterRenderAsync 生命周期方法期间执行”之类的错误。
  • @Andrew。没问题,如果您使用的是 JSInterop,那么您将被 OnAfterRenderfirstRender 卡住。
猜你喜欢
  • 2022-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-08
  • 1970-01-01
  • 2017-07-24
  • 2020-04-21
  • 1970-01-01
相关资源
最近更新 更多