Invoke StateHasChanged() only after asynchronous operation has completed

Referring to the code below:
private async void PublishDrawWithConfirmation()
{
var result = await DialogService.ShowMessageBox(
"Publish Draw",
"Once published, the draw will no longer be editable and will be open to entries. Are you sure?",
yesText: "Publish", cancelText: "Cancel");

if (result == null) return;

await DrawService.ActivateDraw(DrawId);
Snackbar.Add("Draw has been published!", Severity.Success);
StateHasChanged();
}
private async void PublishDrawWithConfirmation()
{
var result = await DialogService.ShowMessageBox(
"Publish Draw",
"Once published, the draw will no longer be editable and will be open to entries. Are you sure?",
yesText: "Publish", cancelText: "Cancel");

if (result == null) return;

await DrawService.ActivateDraw(DrawId);
Snackbar.Add("Draw has been published!", Severity.Success);
StateHasChanged();
}
My intent is to refresh the page after updating the database, in order to display the updated information. Based on the behaviour I am seeing, it looks as if StateHasChanged() is invoked before the database is updated with await DrawService.ActivateDraw(DrawId). What would be the correct way to refresh the page only after the await is complete?
12 Replies
Pobiega
Pobiega4mo ago
by making this method be async Task instead of async void and awaiting it async void means fire and forget, and you are on thin ice at that point
Maverick (Shaun)
What difference would that make? Not disputing it, just not following how that would affect things logically. The call to StateHasChanged is happening inside of this function, so surely just changing the return type wouldn't make a difference? if I move the call to StateHasChanged outside of the function and then await the function and call StateHasChanged, wouldn't I just get the same behaviour as I currently am?
Pobiega
Pobiega4mo ago
PublishDrawWithConfirmation must be awaited thats the problem you can't await an async void method
Maverick (Shaun)
I see. However, I am not seeing a change in behaviour when switching the method to async Task, when calling it with:
<MudButton Variant="Variant.Filled" Color="Color.Info" FullWidth="true" Class="my-4"
OnClick="@PublishDrawWithConfirmation">
Publish Draw
</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Info" FullWidth="true" Class="my-4"
OnClick="@PublishDrawWithConfirmation">
Publish Draw
</MudButton>
As far as I know, Blazor will detect that the method is asynchronous and handle it as such in the event handler above. I'm still not quite sure how awaiting PublishDrawWithConfirmation will affect the call to StateHasChanged within that method, but that's probably due to my lack of experience/in-depth understanding of asynchronicity
Pobiega
Pobiega4mo ago
No idea how this works in blazor Usually a good idea to open your question with such information btw,
Anu6is
Anu6is4mo ago
Based on the behaviour I am seeing, it looks as if StateHasChanged() is invoked before the database is updated with await DrawService.ActivateDraw(DrawId).
what behaviour
Maverick (Shaun)
I hadn't noticed I left Blazor out of the title/description, whoops - never done that before I guess a lack of behaviour would be a better description - nothing changes until I manually refresh the screen. I suppose there's a chance that StateHasChanged isn't actually refreshing the page as I'd expect, but it works everywhere else so I reckon my assumption that StateHasChanged is being invoked before the database is actually updated is more likely
Anu6is
Anu6is4mo ago
I doubt do you have a simple TryMud reproduction?
Maverick (Shaun)
I don't - surely any attempt to reproduce in TryMud would be worthless as I can't replicate EF Core functionality there?
Anu6is
Anu6is4mo ago
doesn't actually need your db, just a simulated delayed task
Joschi
Joschi4mo ago
You got a client in which a user updated some information. This is then saved to the DB right? So I guess that page already has all the updated information available. If that's the case you could just update it directly instead of doing a complete another roundtrip to the DB. Or maybe your update endpoint returns the updated resource and you can use that. No need to call StateHasChanged then.
Maverick (Shaun)
Ended up taking an alternative approach by navigating to the same page (essentially a reload) using NavigationManager with a forced refresh - thanks for the messages folks