[Blazor Server] Sould I catch OperationCanceledException in OnParametersSetAsync/LifeCycle methods when cancelling Tasks inside it?
Summary
I have a question:
I have a blazor component (aka razor component, aka MyPage.razor file) with a @page directive. I'll call the thing/object "page" from here on.
It needs to await a Task (HTTP request simulated with Task.Delay) inside its OnParametersSetAsync().
When the page is left (user navigates somehwere else), awaited Tasks must be cancelled, so that there is no ping-ping (with data access) when thew new page is loaded and the old pages's Task finally finishes delayed. This is the reason for Dipose().
Since the Framework calls OnParametersSetAsync() rather than my own code, I'm not sure if I should let the OperationCanceledException simply bubble up (at finally probably be ignore afaik as the master of async said) - or if I should catch it and return gracefully from OnParametersSetAsync().
Is Blazor handeling cancellation from LifeCycle methods properly or is this the recommended way? Sadly the docu is very sparse. The example offers an button event handler, but IDK if that also counts for LifeCycle methods. But at least it seems it doesnt hurt the event handler (LongRunningWork), that it is not catched in user code.
I have testes both scenarios, and it seems either way, both work seemingly...
What I've noticed, is that even if the async Task OnParametersSetAsync() completes but another page is already active the the Task belongs to an already disosed page, no children LifeCycle methods are called anymore. The big question here is, is it "only" the C# user code in the remaining body of OnParametersSetAsync() that is executed delayed after the page has already been disposed - or will the successful completion of OnParametersSetAsync() trigger some other framework methods/events, even if the page has already been disposed, resulting in highly unpredictable behaviour? I'd also like to know that answer.
In any case, even if this would not cause problems, cancellation might still be important, so that at the end of the user code in OnParametersSetAsync() does not do any operations (e.g. on some data in some injected service or sth like that) that shouldn't be done anymore after disposing. So what's the right way?
Edit: Stephen said:
Ideally, you want to observe all your Task exceptions.
which is not possible, since OnParametersSetAsync() is called from the framework not from the user code, so I can't observe it inside the caller!
// MyPage.razor
<Child SomePara=@SomePara></Child>
//@code{
// ...
//private CancellationTokenSource cts = new();
//object SomePara = new();
// catch it?
protected override async Task OnParametersSetAsync()
{
Debug.WriteLine($"OnParametersSetAsync Start");
// sync stuff...
// async stuff:
try
{
await Task.Delay(5000, cts.Token);
}
catch (Exception)
{
return; //??
throw; //??
}
//when cancel is requested, stop here, this component is being disposed and should do as little as possible, especially nothing async and should't inform children to render
// ??
//cts.Token.ThrowIfCancellationRequested();
Debug.WriteLine($"OnParametersSetAsync End");
// stuff I don't want do be done after cancelled
}
// let it bubble up?
protected override async Task OnParametersSetAsync()
{
Debug.WriteLine($"OnParametersSetAsync Start");
// sync stuff...
// async stuff:
await Task.Delay(5000, cts.Token);
//when cancel is requested, stop here, this component is being disposed and should do as little as possible, especially nothing async and should't inform children to render
// ??
//cts.Token.ThrowIfCancellationRequested();
Debug.WriteLine($"OnParametersSetAsync End");
// stuff I don't want do be done after cancelled
}
public void Dispose()
{
Debug.WriteLine($"Disposing");
cts.Cancel();
cts.Dispose();
}
//}
One could imagine also a pretty hacky idea, but thats prolly bad:
// Hacky option ?????
bool isCancelled = false;
protected override async Task OnParametersSetAsync()
{
Debug.WriteLine($"OnParametersSetAsync Start");
// sync stuff...
// async stuff:
await Task.Delay(5000);
//when cancel is requested, stop here, this component is being disposed and should do as little as possible, especially nothing async and should't inform children to render
if (isCancelled)
{
return;
}
Debug.WriteLine($"OnParametersSetAsync End");
// stuff I don't want do be done after cancelled
}
public void Dispose()
{
Debug.WriteLine($"Disposing");
isCancelled = true ;
}
Its also on SO: Sould I catch OperationCanceledException in OnParametersSetAsync/LifeCycle methods when cancelling Tasks inside it?
Motivation and goals
The docu refers to async event handlers for cancellation, but how about LifeCycle methods like OnParametersSetAsync()?
Should I catch the OperationCanceledException there or can I simply cancel them? What are the implications, or a reliable way to stop the execution of async LifeCycle methods, if they are no longer needed (primary use case: component is already disposed, but the async part of the methods still continues).
Maybe a notice can be added to the official docu about cancelling LifeCycle methods?!
##Sidenotes Sorry I don't know how to apply the appropriate labels for this issue. Probalby [Blazor] and [Question] ??
THANKS!