Greetings everyone, first time poster here looking for some advice.
I'm developing an App in Xamarin.Android that uses HttpClient. Occasionally I was experiencing freezes and/or crashes with my App that I didn't understand, especially since it seemed pretty random. I think I may have found the cause, although I've thought so many times before: Sometimes when calling HttpClient.SendAsync() I get a System.ObjectDisposedException from System.Threading.CancellationTokenSource:
$exception {System.ObjectDisposedException: The object was used after being disposed.
at System.Threading.CancellationTokenSource.CheckDisposed () [0x00000] in <filename unknown>:0
at System.Threading.CancellationTokenSource.Cancel (Boolean throwOnFirstException) [0x00000] in <filename unknown>:0
at System.Threading.CancellationTokenSource.Cancel () [0x00000] in <filename unknown>:0
at System.Threading.CancellationTokenSource.<CancellationTokenSource>m__0 (System.Object token) [0x00000] in <filename unknown>:0
at System.Threading.Timer+Scheduler.TimerCB (System.Object o) [0x00000] in <filename unknown>:0 } System.ObjectDisposedException
Bug 17256 seems related, but I don't know why this exception comes up when calling SendAsync() or how to deal with it. Apparently it has to do with how HttpClient deals with timeouts. Here's a code sample that triggers the exception most of the time. Sometimes it just silently dies, sometimes it doesn't happen at all, but usually it gets thrown immediately, both on an emulator and on a Galaxy Tab 3:
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
namespace CancellationTokenSourceExceptionTest
{
[Activity (Label = "CancellationTokenSourceExceptionTest", MainLauncher = true)]
public class MainActivity : Activity
{
protected override void OnStart ()
{
base.OnStart ();
int taskCount = 3;
for (int i = 0; i < taskCount; i++) {
Task.Run (async () => {
await DoHttpGetAsync();
});
}
}
async Task DoHttpGetAsync() {
HttpClient clientToUse = new HttpClient () { Timeout = new System.TimeSpan (0, 0, 0, 1, 0), };
HttpRequestMessage request = new HttpRequestMessage (HttpMethod.Get, "http://www.google.de");
HttpResponseMessage responseMessage = null;
try {
responseMessage = await clientToUse.SendAsync (request, HttpCompletionOption.ResponseHeadersRead);
}
catch (System.ObjectDisposedException ex) {
// shouldn't this catch the exception? apparently it doesn't...
Console.WriteLine ("exception: " + ex.Message);
}
}
}
}
I'm running 3 async tasks that create their own HttpClient-Object, set the timeout to one Second and then call SendAsync() inside a try/catch-block. The exception also happens when starting and awaiting just one task, but happens more often with more than one. Using ConfigureAwait(false) on SendAsync() doesn't seem to make a difference. If you leave the timeout-value of HttpClient alone (default is 140 seconds) or set a higher value the exception can still happen if you put in a Thread.Sleep() after awaiting SendAsync() or just stop at a breakpoint for some time when debugging.
Is this an expected behavior of HttpClient or shouldn't it throw a TaskCanceledException instead? What am I missing?