ObjectDisposedException on postAsync canceled

I have two classes in my Xamarin app that I am using to upload an image to the server:

public class ProfileApi : IDisposable
{
    public Uri BaseUri { get; private set; }
    private HttpClientHandler _messageHandler;

    public ProfileApi (string baseUri, HttpClientHandler messageHandler)
    {
        BaseUri = new Uri (baseUri, UriKind.Absolute);
        _messageHandler = messageHandler;
    }

    protected HttpClient CreateHttpClient ()
    {
        var httpClient = new HttpClient (_messageHandler, true) {
            BaseAddress = BaseUri
        };
        return httpClient;
    }


    public async Task SetProfilePicture (Stream picture, CancellationToken cancellationToken)
    {
        using(var client = CreateHttpClient ())
        {
            using(var copy = new MemoryStream())
            {
                picture.Position = 0;
                picture.CopyTo(copy);
                copy.Position = 0;

                var content = new StreamContent (copy);
                content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue ("image/png");

                var response = await client.PostAsync ("post", content, cancellationToken);    

                Debug.WriteLine ("Finished!"); 
            }
        }
    }

    public void Dispose ()
    {
        _messageHandler.Dispose ();
        _messageHandler = null;
    }
}

public class ProfileDownloader
{
    static readonly Lazy<ProfileDownloader> lazy = new Lazy<ProfileDownloader> (() => 
        new ProfileDownloader ()
    );

    public static ProfileDownloader Instance {
        get {
            return lazy.Value;
        }
    }

    ProfileDownloader (){}

    CancellationTokenSource _uploadCancellationSource;

    public async Task UploadImage (Stream image)
    {
        if (AreProfileAndImageBeingUploaded ()) {
            CancelProfileAndImageUpload ();
            return;
        }

        _uploadCancellationSource = new CancellationTokenSource ();

        using (var ProfileApi = new ProfileApi ("http://httpbin.org", new NativeMessageHandler ())) 
        {
            var imageTask = ProfileApi.SetProfilePicture (image, _uploadCancellationSource.Token);

            try {

                await imageTask;
                _uploadCancellationSource = null;

            } catch (OperationCanceledException ex) {
                Debug.WriteLine (string.Format ("Cancelled! : {0}", ex.Message)); 

            } catch (Exception ex) {
                Debug.WriteLine (string.Format ("Exception! : {0}, {1}", ex.Message, ex.Source));
            }
        }
    }

    public bool AreProfileAndImageBeingUploaded ()
    {
        return _uploadCancellationSource != null;
    }

    public void CancelProfileAndImageUpload ()
    {
        if (_uploadCancellationSource != null) {
            _uploadCancellationSource.Cancel ();
            _uploadCancellationSource = null;
        }
    }
}

      

The method UploadImage

is called every time I click a button in the app UI.

var image = UIImage.FromFile ("Images/SpongeBob.png");
using (var stream = image.ToStream ()) {        
    ProfileDownloader.Instance.UploadImage (stream);
}

      

This is what I am doing:

  • Double click the button that calls twice UploadImage

    . The first time I run the download the second time, it is canceled and I get TaskCancelledException

    .
  • I press the button again. The first time the download starts, and the second one calls ObjectDisposedException

    .

Does anyone know why the exception described in 2 is thrown.

Update

Here is the stack trace of the exception. It is thrown on line with await imageTask

.

System.ObjectDisposedException: The object was used after being disposed. at System.Net.WebConnection.EndWrite (System.Net.HttpWebRequest request, Boolean throwOnError, IAsyncResult result) [0x0002c] in
//Library/Frameworks/Xamarin.iOS.framework/Versions/8.10.1.64/src/mono/mcs/class/System/System.Net/WebConnection.cs:1071 at System.Net.WebConnectionStream.WriteAsyncCB (IAsyncResult r) [ 0x00013] in 
//Library/Frameworks/Xamarin.iOS.framework/Versions/8.10.1.64/src/mono/mcs/class/System/System.Net/WebConnectionStream.cs:458 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threadks .Task task) [0x00047] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:201 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessoAndDebug.HandleNonSuccessAndDebug.ger .Task task) [0x0002e] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:170 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tas .Task task) [0x0000b] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:142 at System.Runtime.CompilerServices.ConfiguredTaskAwaitable + ConfiguredTaskxwaiter.Get000 ] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:477 at System.Net.Http.HttpClientHandler + c__async0.Move002f4 (] 0 in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs:344 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threadks .Task task) [0x00047] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:201 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessoAndDebug.HandleNonSuccessAndDebug.ger .Task task) [0x0002e] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:170 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tas .Task task) [0x0000b] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:142 at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1 + Configured SystemTaskAwaiter .Http.HttpResponseMessage] .GetResult () [0x00000] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:580 at System.Net.Http.HttpClient + c__async0.MoveNext () [0x000axt9 ] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/mcs/class/System.Net.Http/System.Net.Http/HttpClient.cs:274 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threadks .Task task) [0x00047] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:201 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessoAndDebug.HandleNonSuccessAndDebug.ger .Task task) [0x0002e] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:170 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tas .Task task) [0x0000b] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:142 at System.Runtime.CompilerServices.TaskAwaiter`1 [System.Net.Http .HttpResponseMessage] .GetResult () [0x00000] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:372 at Shared.ProfileApi + c__async0.MoveNext () [0x00114] in 
/ Users / mku / Documents / Private projects / Xamarin / Example / Shared / ProfileApi.cs: 46 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threadks .Task task) [0x00047] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:201 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessoAndDebug.HandleNonSuccessAndDebug.ger .Task task) [0x0002e] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:170 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tas .Task task) [0x0000b] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:142 at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in 
/Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:124 at Shared.ProfileDownloader + c__async0.MoveNext () [0x000b1] in 
/ Users / mku / Documents / Private projects / Xamarin / Example / Shared / ProfileDownloader.cs: 42
+3


source to share


2 answers


It turns out that this was actually a bug in Mono, which is now fixed and will be released in version 4.2.



Xamarin Bugzilla Bug Report Link

+1


source


You need to wait UploadImage

or the stream will be deleted immediately after calling it.

Try the following:



var image = UIImage.FromFile ("Images/SpongeBob.png");
using (var stream = image.ToStream ()) {        
    awaProfileDownloader.Instance.UploadImage (stream);
}

      

You will need to change the method containing this code to a method async

.

0


source







All Articles