Autocomplete and CancellationToken In the mobile application I have a search page. As user types search keywords I display autocomplete entries.
On each keystroke I initiate autocomplete lookup, and I am using CancellationToken to cancel lookups if user keeps typing.

I am new to using CancellationTokens, so please review my code and recommend changes as needed.

// ViewModel code is below.

// Search service is injected in ctor.
private readonly ISearchService _searchService;
private CancellationTokenSource _cancellationTokenSource;

// From the UI accept user input and get autocomplete search results.
public async Task GetAutocompleteSearchResultsAsync(string searchText)
{   
    try
    {
        if (_cancellationTokenSource != null)
        {
            _cancellationTokenSource.Cancel();
            _cancellationTokenSource.Dispose();
            _cancellationTokenSource = new CancellationTokenSource();
        }
        else
        {
            _cancellationTokenSource = new CancellationTokenSource();
        }

        var autocomplete = await _searchService.GetAutocomplete(searchText, _cancellationTokenSource.Token);
        // Assign result to property to display results in UI.
        AutocompleteSearchResults = autocomplete;
    }
    finally
    {
        if (_cancellationTokenSource != null)
        {
            _cancellationTokenSource.Dispose();
            _cancellationTokenSource = null;
        }
    }
}


And inside the ISearchService implementation I have the following code.

public async Task&lt;ObservableCollection&lt;AutocompleteSearchResult&gt;&gt; GetAutocomplete(
string input, CancellationToken cancellationToken)
{
    try
    {
        string endpoint = $"/autocomplete/{input}";
        // _client is HttpClient instance. It's initialized in ctor.
        using (var response = await _client.GetAsync(endpoint, cancellationToken))
        {
            if (cancellationToken.IsCancellationRequested) return null;

            if (response.IsSuccessStatusCode)
            {
                string json = await response.Content.ReadAsStringAsync();
                var data = await Task.Run(() =&gt;
                        JsonConvert.DeserializeObject&lt;IEnumerable&lt;AutocompleteSearchResult&gt;&gt;(json),
                    cancellationToken);
                return data.ToObservableCollection();
            }
        }

        return null;
    }
    catch (Exception)
    {
        return null;
    }
}
Just a small suggestion.

Typical typing rate is 40 WPM (with keyboard). It means more or less one character every 300ms. With mobile phone (and a good virtual keyboard) rate is typically slower (around 20/30 WPM).

Assuming:


You can start a request in few milliseconds.
User will have a useful result after few typed characters.


It means that for each user and for each typed word you will start few HTTP connections with your server (in the best case where user will pick something from the autocomplete). Multiply for all the searched words for all your user base and you will see that you add a useless load to your server (and you consume mobile bandwidth...)

Do not start lookup while typing but AFTER user stopped typing for a short period, let's say 300 ms for mobile devices but you may tune this value with some usage statistics. Network latency, server response time and UX fluidity need to be considered to find a trade-off.

Note that this may be done also with a simple Task.Delay(300) inside GetAutocomplete(), before calling _client.GetAsync(). It has the advantage to keep GetAutocompleteSearchResultsAsync() unchanged.

await Task.Delay(DebouncingDelayInMilliseconds, cancellationToken);