Reputation: 5083
I have a Blazor page (server-side) that uses an async call to Azure Service Bus to get some data and print the result to the page. Everything works fine at first. However, if the user reloads the page, the page does not get re-rendered as intended.
Debugging with breakpoints shows that the model is updated, and the call to StateHasChanged
is executed after the page reload; it just simply doesn't do anything. I was under the impression that InvokeAsync
is supposed to always use the UI thread, but that doesn't seem to be the case after a page reload.
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
});
Additionally, I added a watch to the Model.Amount
property and it's exhibiting some weird behavior. If it's set to say 23 on initial page load, the watch will always show 23 on my breakpoint in the SaveAndGetAmount
method, as if it's never being updated by the MessageHandler
method.
Upvotes: 1
Views: 780
Reputation: 273179
WatchQueue does get called on each OnAfterRenderAsync; we ignore 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);
}
Just a guess here but this means every (Re)Render adds a messagehandler. That is wrong but goes unnoticed as long as you're on the same instance of the page.
After a reload your messages are still handled on the old (defunct) page. That is what I think you see happening in the debugger.
If I'm right the solution is two-fold:
@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
}
If you can't unhook that handler then it's at the wrong place.
Upvotes: 2