Category Archives: Blazor

[Blazor] await periodicTimer.WaitForNextTickAsync() – dobrý sluha, ale špatný pán

Pozor na await periodicTimer.WaitForNextTickAsync(). Tato metoda láká svojí asynchronní signaturou k pohodlnému uspořádání periodických úloha a zejména v Blazoru vás tak může zlákat k implementaci aktualizací UI:

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

private async Task StartTimerAsync()
{
    using var timer = new PeriodicTimer(TimeSpan.FromSeconds(10));
    while (await timer.WaitForNextTickAsync())
    {
        // do some UI updates here
    }
}

POZOR! Takovéto uspořádání sice neblokuje UI thread a díky async-await to jede dál, problém je však v tom, že metoda, z které se takovýto kód volá, nikdy neskončí.

Pokud tedy například takovýto StartTimeAsync() přímo zavolám z OnIntializeAsync/OnParametersSetAsync/OnAfterRenderAsync/action-callbacku, pak tato parent-metoda nikdy neskončí a může to mít dost nečekané následky. Například:

  • pokud to zavolám z HxButton.OnClick obsluhy tlačítka, zůstane mi tam viset spinner, který nikdy neskončí,
    • tlačítko navíc zůstane pod single-click-protection, disabled, nepoužitelné,
  • pokud to zavolám z override OnInitializedAsync(), nedojde v prvním roundtripu k zavolání OnParametersSet[Async]() a dokud nepřijde další roundtrip, tak se mi OnParametersSet[Async]() neprovedou,
  • pokud to zavolám z override OnParametersSetAsync(), zůstává mi viset nedokončený Task v ComponentBase.CallStateHasChangedOnAsyncCompletion(), navíc musím ošetřit, že se OnParametersSetAsync() volá opakovaně a nechci si timerů pustit více,
  • pokud to zavolám z override OnAfterRenderAsync(bool firstRender), mohu si tím zablokovat volání await base.OnAfterRenderAsync(firstRender), což mi může narušit funkčnost definovanou předkem při dědění (zejména pro firstRender = true, které se provádí jen jednou)

PeriodicTimer.WaitForNextTickAsync() se tedy hodí do scénářů, kdy je zaručeno, že volající kód nikam nepokračuje a mohu se na příslušném místě točit „do nekonečna“ (např. jsem v metodě Main a točím nějakou cyklickou úlohu v konzolové aplikaci, nebo jsem v BackgroundService.ExecuteAsync()). Obecně však je potřeba dovolit dokončení volající metody a tedy pro spouštění použít tradiční uspořádání s Task.Run(..), kdy umístíme timer (může to být i klasický Timer, asynchronní metoda WaitForNextTickAsync() zde již nehraje tak velkou roli) na ThreadPool a neawaitujeme v aktuální metodě jeho dokončení (fire & forget). V případě Blazoru si v takovém případě musíme ručně volat StateHasChanged(), popř. DispatchExceptionAsync().

public MyComponent : IDisposable
{
	private PeriodicTimer timer;

	protected override async Task OnInitializedAsync()
	{
		_ = Task.Run(StartTimerAsync);
	}

	private async Task StartTimerAsync()
	{
		timer = new PeriodicTimer(TimeSpan.FromSeconds(10));
		while (await timer.WaitForNextTickAsync())
		{
			// do some UI updates here
			StateHasChanged(); // as needed
		}
	}

	public void Dispose()
	{
		timer?.Dispose();
	}
}

Nesmíme samozřejmě zapomenout na úklid – timer.Dispose(), jinak nám Timer zůstane běžet i po zániku komponenty, vzniká resource-leak atd.

Viz též ASP.NET Core Blazor dokumentace:

Blazored.FluentValidations issue [Robert Haken, HAVIT Vzdělávací okénko. 24.10.2024]

Záznam ze Vzdělávacího okénka HAVIT ze 24. října 2024, kde jsem ukazoval problematické chování Blazored.FluentValidationsValidator při komplexním view-modelu a validaci fieldů na sub-modelech.

https://github.com/Blazored/FluentValidation/issues/235

Novinky v .NET 9 – záznam a slides [Robert Haken, WUG Days Brno, 5.9.2024]

Záznam ze Vzdělávacího okénka HAVIT z 5. září 2024, kde jsem telegraficky představoval novinky přicházející v „.NET 9 vlně“.

Slides

JavaScript pro Blazor vývojáře [Alex Hájek, HAVIT Vzdělávací okénko, 12.6.2024]

Záznam ze Vzdělávacího okénka HAVIT z 12. června 2024, kde Alex Hájek procházel JavaScript tipy a triky pro Blazor vývojáře.

Blazor Performance 2 – Many components/parameters/events [Robert Haken, HAVIT Vzdělávací okénko. 10.7.2024]

Záznam ze Vzdělávacího okénka HAVIT ze 10. července 2024, kde jsem prezentoval druhý díl série na téma výkonu Blazor aplikací.

Blazor Performance 1 – Expensive data reload [Robert Haken, HAVIT Vzdělávací okénko, 17.4.2024]

Záznam ze Vzdělávacího okénka HAVIT ze 17. dubna 2024, kde jsem prezentoval první díl série na téma výkonu Blazor aplikací.

Blazor NET8 – Životní cyklus komponent [Jiří Kanda, HAVIT Vzdělávací okénko, 28.3.2024]

Záznam ze Vzdělávacího okénka HAVIT z 28. března 2024, kde Jiří Kanda povídal o Blazoru – o životním cyklu komponent a jeho zákoutích – aktualizovaná podoba session z roku 2019.

Blazor – Komponenty [Jiří Kanda, HAVIT Vzdělávací okénko, 13.3.2024]

Záznam ze Vzdělávacího okénka HAVIT z 13. března 2024, kde Jiří Kanda povídal o Blazoru – o fungování jeho komponent – aktualizovaná podoba session z roku 2019.

Blazor – Úvod, hosting, modely [Jiří Kanda, HAVIT Vzdělávací okénko, 6.3.2024]

Záznam ze Vzdělávacího okénka HAVIT z 6. března 2024, kde Jiří Kanda povídal o Blazoru – jednalo se o úvod do hostingových modelů – aktualizovaná podoba session z roku 2019.

Blazor novinky v .NET 8 + Blazor Performance Tuning – záznam a slides [Robert Haken, WUG Dev Day, 4.2.2024]

Záznam ze Vzdělávacího okénka HAVIT z 8. listopadu 2023, kde jsem telegraficky představoval novinky přicházející v „.NET 8 vlně“.

Slides