Asynchronous cancellation of a C # xamarin task

I have a user search function. I provided a text view, and the textview method has been changed on this. I am running a method to retrieve data from a web server. But I run into a problem when the user types a letter, because all api hits are executed in an asynchronous task. The service must be deleted after 100 milliseconds of waiting, which means that if the user types the letter "a", then he does not type 100 milliseconds, then we need to get into the service. But if the user enters "a", then "b", then "c", so for "abc" you should use one service, and not for all.

I followed the official link, but it doesn’t help me https://msdn.microsoft.com/en-us/library/jj155759.aspx

So basically here is my code

textview.TextChange+= (sender,e) =>{ CancellationTokenSource cts = new CancellationTokenSource(); await Task.Delay(500); // here some where I have to pass cancel token var lst = await APIClient.Instance.GetUserSearch("/user/get?searchTerm=" + newText, "application/json",cts); if (lst != null && lst.Count > 0){ lstSearch.AddRange(lst); } } 

Here is my GetUser method

  public async Task<JResponse> GetUserSearch<JResponse>(string uri, string contentType,CancellationToken cts) { try { Console.Error.WriteLine("{0}", RestServiceBaseAddress + uri); string url = string.Format("{0}{1}", RestServiceBaseAddress, uri); var request = (HttpWebRequest)WebRequest.Create(url); request.ContentType = contentType; if (Utility.CurrentUser != null && !string.IsNullOrWhiteSpace(Utility.CurrentUser.AuthToken)) { request.Headers.Add("api_key", Utility.CurrentUser.AuthToken); } request.Method = "POST"; var payload = body.ToString(); request.ContentLength = payload.Length; byte[] byteArray = Encoding.UTF8.GetBytes(body.ToString()); request.ContentLength = byteArray.Length; using (var stream = await request.GetRequestStreamAsync()) { stream.Write(byteArray, 0, byteArray.Length); stream.Close(); } using (var webResponse = await request.GetResponseAsync()) { var response = (HttpWebResponse)webResponse; using (var reader1 = new StreamReader(response.GetResponseStream())) { Console.WriteLine("Finished : {0}", uri); var responseStr = reader1.ReadToEnd(); var responseObj = JsonConvert.DeserializeObject<JResponse>( responseStr, new JsonSerializerSettings() { MissingMemberHandling = MissingMemberHandling.Ignore, NullValueHandling = NullValueHandling.Ignore }); return responseObj; } } } catch (System.Exception ex) { Utility.ExceptionHandler("APIClient", "ProcessRequestAsync", ex); } return default(JResponse); } 
+7
c # async-await xamarin
source share
3 answers

In your example, you create a CancellationTokenSource - you need to save a link to it so that the next search you can cancel the previous search. Here is an example of a console application that you can run, but the important part is in the handler.

 private CancellationTokenSource _cts; private async void TextChangedHandler(string text) // async void only for event handlers { try { _cts?.Cancel(); // cancel previous search } catch (ObjectDisposedException) // in case previous search completed { } using (_cts = new CancellationTokenSource()) { try { await Task.Delay(TimeSpan.FromSeconds(1), _cts.Token); // buffer var users = await _userService.SearchUsersAsync(text, _cts.Token); Console.WriteLine($"Got users with IDs: {string.Join(", ", users)}"); } catch (TaskCanceledException) // if the operation is cancelled, do nothing { } } } 

Be sure to pass the CancellationToken to all async methods, including those that execute the web request, so you signal a decline to the lowest level.

+7
source share

Try using a timer. The first time you change the text - you create it. Then you change the text after that - you start the timer. If you do not change the text within 700 milliseconds, the timer will start the PerformeSearch method. Use Timeout.Infinite for the timer period setting to prevent it from restarting.

 textview.TextChange += (sender,e) => { if (_fieldChangeTimer == null) _fieldChangeTimer = new Timer(delegate { PerformeSearch(); }, null, 700, Timeout.Infinite); else { _fieldChangeTimer.Change(700, Timeout.Infinite); } }; 
0
source share

Create an instance of CancellationTokenSource.

cts = new CancellationTokenSource (); Method example

 private void cancelButton_Click(object sender, RoutedEventArgs e) { if (cts != null) { cts.Cancel(); } } 
0
source share

All Articles