Home > Mobile >  How to guard against double trigger of async method in Blazor wasm
How to guard against double trigger of async method in Blazor wasm

Time:04-08

I'm developing a blazor wasm application. I'm struggling with an async issue - that I find difficult to tackle, as the threading in the browser is not completely clear to me. I'm not using any async voids - everything is async Task.

From an API call (async) I get back two objects. One object I dispatch as an synchronous update to the fluxor store, and the other I have to do a async call on the local Indexdb, after which this one also enters the fluxor store.

The two fluxor store updates trigger via an event an update method of the view model. This update method is async, as it also get's some info from the IndexedDb. This async method fetches async some items from Indexdb, clears a dictionary, then enumerates over a property of the fluxor store to update the model.

This method get's called twice in quick succession, and as a result, starts interweaving.

The trouble is the first method call is paused during the enumeration over the state, next the second method call clears the dictionary, and starts it's own enumeration (and finishes), after which the first method resumes midst it's earlier started enumeration.

This results in errors - trying to add identical keys twice to the dictionary.

How can I guard against this? How can I prevent the same method call to interweave with itself in Blazor wasm? How can the (synchronous) enumeration part of the async update method be paused, allowing the full method to run, and next resuming the first call again?

public partial class DebugPage : BasePage, IDisposable
{


    [Inject] IState<MonthBalanceState> MonthBalanceState { get; set; }

    private Dictionary<IMonthBalanceAddress, int> DbCountDictionary = new Dictionary<IMonthBalanceAddress, int>();

    protected override async Task OnParametersSetAsync()
    {
        MonthBalanceState.StateChanged  = async (_, _) => await MonthBalanceState_StateChanged();
        Console.WriteLine($"Linkage made to Monthbalance State");
        await base.OnParametersSetAsync();
    }

//This method get's called twice quickly - starting the interweaving
    private async Task MonthBalanceState_StateChanged()
    {
        Console.WriteLine($"Update via Statechanged Monthbalance State");
        var result = await UpdateDictionaryAsync();
    }
    private async Task<bool> UpdateDictionaryAsync()
    {
        DbCountDictionary.Clear();
        Log.Debug("Debug dictionary updated");
        foreach (IMonthBalanceLoadable mb in MonthBalanceState.Value.MonthBalances.ToList())
        {
            Console.WriteLine($"Adding {mb.Address.ToString()}");
            DbCountDictionary.Add(mb.Address, await Db.GetCountByAddress(mb.Address));
        }
        return true;
    }

CodePudding user response:

If possible, you could use OnAfterRenderAsync(bool firstRender) instead if OnParametersSetAsync() and then only set you variables if it is the first render.

CodePudding user response:

     = async (_, _) => await MonthBalanceState_StateChanged();

This lambda is an async void wrapping your handler.

So it is not awaited and that is the source of your problem.

That StateChanged event should probably be an EventCallback property. Post the relevant code if you need more help.

  • Related