Short version: does the following look thread safe to you?
The following pseudocode is simplified from working code. It updates a SQL database entry every 10 seconds, only if a change has been made to the content of an HTML editor (I use TinyMCE).
My question is this– when the original page’s conditional statement “erases” the instance of <MyEditor>
(when SelectedItem is set to null), what happens to that instance? Does it immediately go to Dispose, and make a clean break? Will the PeriodicTimer or async events potentially throw?
MyPage.razor
@if (SelectedItem is not null){
<MyEditor @bind-HTML=SelectedItem.HTML @OnDeselect="()=>SelectedItem = null" />
}
@code {
List<htmlItem> htmlItems = new(); // Assume I get these in init.
htmlItem? SelectedItem;
async Task SomeSelectionMethod(){
SelectedItem = htmlItems.Single(hi=> somecriteria);
}
}
MyEditor.razor
@implements IDisposable
<MyMCE @bind-HTML=ActiveItem HTML @bind-HTML:after=HandleChangedHTML />
<button @onclick=DeselectMe > Return </button>
@code {
[Parameter]
public htmlItem ActiveItem {get; set;}
[Parameter]
public EventCallback OnDeselect {get; set;}
private PeriodicTimer _timer;
private CancellationTokenSource _cts = new();
private bool NeedsSave;
private async Task DeselectMe()
{
await SaveContentAsync();
await OnDeselect.InvokeAsync();
}
protected override void OnInitialized()
{
_timer = new PeriodicTimer(TimeSpan.FromSeconds(10));
_ = SaveContentPeriodically();
}
private async Task SaveContentPeriodically()
{
try
{
while (await _timer.WaitForNextTickAsync(_cts.Token))
{
if (NeedsSave)
{
await SaveContentAsync();
NeedsSave = false;
}
}
}
catch (OperationCanceledException)
{
// Handle the cancellation
}
}
private async Task SaveContentAsync()
{
await TS.UpdateHtmlItemAsync(ActiveItem); // worried about this. . .
}
async Task HandleChangedHTML()
{
NeedsSave = true;
}
public void Dispose()
{
_cts.Cancel();
_timer.Dispose();
}
}