Using Cancellation Tokens for Efficient SyncFusion SFGrid Data Rendering

A few weeks ago, I encountered an issue with SyncFusion SFGrid where it was rendering not the last request that was sent, but the last request that was completed. I was using a custom DataAdapter to render data, and when I quickly clicked on filters, the grid didn’t always show the latest result. I tried to find a solution using Debouncing technic, but it didn’t work for my case as I didn’t want to delay the selection of filters. The debounce technic is good for the autocomplete but not for the grid.

After some research, I found a solution using a cancellation token. If I sent multiple requests, I would cancel all of them and only display the last request on the grid. This allowed me to ensure that only the latest data was displayed. Since the DataAdapter was registered as scoped(registered once in scope of user session), I was able to modify it change as I need.

Here is the initial DataAdapter code:

public class MySuperGridDataAdaptor : DataAdaptor
{
    private readonly WeatherService _service;
    public MySuperGridDataAdaptor(WeatherService service)
    {
        _service = service;
    }
    public override async Task<object> ReadAsync(DataManagerRequest dataManagerRequest, string? key = null)
    {
        var countryCode =  (string)dataManagerRequest.Params["countryCode"];
        var weatherDto = await _service.GetWeatherByCountryCode(countryCode);
        return (object)weatherDto;
    }
}

And here is the DataAdaptor after I added the Cancellation Token:

public class MySuperGridDataAdaptor : DataAdaptor
{
    private readonly WeatherService _service;
    private CancellationTokenSource _cancellationTokenSource;		
    public MySuperGridDataAdaptor(WeatherService service)
    {
        _service = service;
        _cancellationTokenSource = new CancellationTokenSource();			
    }
    public override async Task<object> ReadAsync(DataManagerRequest dataManagerRequest, string? key = null)
    {
        var currentCancellationTokenSource = new CancellationTokenSource();
        var previousCancellationTokenSource = Interlocked.Exchange(ref _cancellationTokenSource, currentCancellationTokenSource);
        previousCancellationTokenSource.Cancel();
        
        var countryCode =  (string)dataManagerRequest.Params["countryCode"];
        
        var weatherDto = await _service.GetWeatherByCountryCode(countryCode, currentCancellationTokenSource.Token);
        return (object)weatherDto;
    }
}

 
A few comments on my code. Inside the ReadAsync method, a new CancellationTokenSource object is created and assigned to currentCancellationTokenSource. Then, Interlocked.Exchange method atomically replaces the _cancellationTokenSource variable with currentCancellationTokenSource and returns the previous value of _cancellationTokenSource.

The previous CancellationTokenSource object is then cancelled by calling its Cancel method. This is done to ensure that any previous requests are canceled and only the latest request is processed.

Thank you for your time. Let me know in the comments if you have questions. If I found that this article is useful I’ll create a full example with all steps. And here is also my guides related to the Blazor topic:

Leave a Comment