【问题标题】:ObjectDisposedException when canceling postAsync取消 postAsync 时出现 ObjectDisposedException
【发布时间】:2015-06-26 21:57:08
【问题描述】:

我的 Xamarin 应用程序中有以下两个类,用于将图像上传到服务器:

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;
        }
    }
}

每当我在应用程序的 UI 中按下按钮时,都会调用 UploadImage 方法。

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

这就是我的工作:

  1. 按两次按钮,调用UploadImage 两次。第一次开始上传,第二次取消,我收到TaskCancelledException
  2. 我再次按下按钮两次。第一次开始上传,但第二次导致ObjectDisposedException

有人知道为什么会抛出2.中描述的异常吗?

更新

这是异常的堆栈跟踪。用await imageTask抛出就行了。

System.ObjectDisposedException:对象在被释放后被使用。在 System.Net.WebConnection.EndWrite(System.Net.HttpWebRequest 请求,布尔 throwOnError,IAsyncResult 结果)[0x0002c] 中 //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] 在 //Library/Frameworks/Xamarin.iOS.framework/Versions/8.10.1.64/src/mono/mcs/class/System/System.Net/WebConnectionStream.cs:458 --- 来自先前异常位置的堆栈跟踪结束抛出---在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()[0x0000b]中 /Users/builder/data/lanes/1503/e6ebd18b/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks .Task 任务)[0x00047] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:201 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks .Task 任务)[0x0002e] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:170 在 System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks .Task 任务)[0x0000b] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:142 在 System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () [0x00000 ] 在 /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:477 在 System.Net.Http.HttpClientHandler+c__async0.MoveNext () 0x002f4]在 /Users/builder/data/lanes/1503/e6ebd18b/source/mono/mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs:344 ---堆栈跟踪从先前位置结束异常被抛出 --- 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [0x0000b] 中 /Users/builder/data/lanes/1503/e6ebd18b/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks .Task 任务)[0x00047] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:201 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks .Task 任务)[0x0002e] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:170 在 System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks .Task 任务)[0x0000b] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:142 在 System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[System.Net .Http.HttpResponseMessage].GetResult () [0x00000] 中 /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:580 在 System.Net.Http.HttpClient+c__async0.MoveNext () [0x000a9 ] 在 /Users/builder/data/lanes/1503/e6ebd18b/source/mono/mcs/class/System.Net.Http/System.Net.Http/HttpClient.cs:274 ---堆栈跟踪从先前位置结束异常被抛出 --- 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [0x0000b] 中 /Users/builder/data/lanes/1503/e6ebd18b/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks .Task 任务)[0x00047] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:201 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks .Task 任务)[0x0002e] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:170 在 System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks .Task 任务)[0x0000b] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:142 在 System.Runtime.CompilerServices.TaskAwaiter`1[System.Net.Http .HttpResponseMessage].GetResult () [0x00000] 在 /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:372 在 Shared.ProfileApi+c__async0.MoveNext () [0x00114] /Users/mku/Documents/Private projects/Xamarin/Example/Shared/ProfileApi.cs:46 --- 从先前抛出异常的位置结束堆栈跟踪---在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] 在 /Users/builder/data/lanes/1503/e6ebd18b/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks .Task 任务)[0x00047] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:201 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks .Task 任务)[0x0002e] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:170 在 System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks .Task 任务)[0x0000b] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:142 在 System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] 中 /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:124 在 Shared.ProfileDownloader+c__async0.MoveNext () [0x000b1] /Users/mku/Documents/Private projects/Xamarin/Example/Shared/ProfileDownloader.cs:42

【问题讨论】:

    标签: c# xamarin async-await task-parallel-library dotnet-httpclient


    【解决方案1】:

    事实证明,这实际上是 Mono 中的一个错误,现已修复,并将在 4.2 版中发布。

    Link to bug report in Xamarin's Bugzilla

    【讨论】:

      【解决方案2】:

      您需要等待UploadImage,否则该流将在调用后立即释放。

      试试这个:

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

      您必须将包含该代码的方法更改为 async 方法。

      【讨论】:

      • 我在SetProfilePicture 中复制了流。只要网络请求正在运行,副本不应该是活动的吗?
      • 没有。您正在制作对堆上流的引用的副本。但它是同一个对象。
      • 我很确定 CopyTo() 方法确实复制了数据本身。
      • 如果正在复制的图像已经被释放,它会。但是您应该知道堆栈跟踪发生了什么。你试过我的建议了吗?
      • 我已经尝试过您的建议。不幸的是,我仍然收到ObjectDisposedException
      猜你喜欢
      • 1970-01-01
      • 2015-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多