取消任务会导致ObjectDisposedException

时间:2015-06-24 07:59:15

标签: c# xamarin async-await task

在我的Xamarin iOS应用程序中,我有一种方法可以将用户配置文件数据和配置文件图像上传到服务器。它看起来像这样:

public async Task UploadProfileAndImage (ProfileInputModel profile, Image image, Action<bool, string> completion)
{
    if (AreProfileAndImageBeingUploaded ()) {
        CancelProfileAndImageUpload ();
    }

    if (completion != null) {
        _uploadCallbacks.Add (completion);
    }
    _uploadCancellationSource = new CancellationTokenSource ();

    var tasks = new List<Task<ApiResponse>> ();

    Task<ApiResponse> profileTask = null;
    if (profile != null) {
        profileTask = ProfileApi.UpdateProfile (profile, _uploadCancellationSource.Token);
        tasks.Add (profileTask);
    }

    Task<ApiResponse> imageTask = null;
    if (image.ImageBytes != null) {
        imageTask = ProfileApi.SetProfilePicture (image, _uploadCancellationSource.Token);
        tasks.Add (imageTask);
    }

    var both = Task.WhenAll (tasks.ToArray ());

    try {

        var responses = await both;
        var success = true;
        foreach (ApiResponse a in responses) {
            if (!a.IsSuccessful) {
                success = false;
                break;
            }
        }

        foreach (Action<bool, string> callback in _uploadCallbacks) {
            if (success) {
                callback (true, null);
            } else {
                callback (false, "Error occurred");
            }
        }
    } catch (OperationCanceledException) {
        foreach (Action<bool, string> callback in _uploadCallbacks) {
            callback (false, "Operation cancelled");
        }    
    } catch (Exception ex) {
        Debug.WriteLine (ex);
    } finally {
        _uploadCancellationSource.Dispose ();
        _uploadCancellationSource = null;
        _uploadCallbacks.Clear ();
    }
}

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

public async Task<ApiResponse> UpdateProfile(ProfileInputModel profile, CancellationToken cancellationToken)
{
    using (var client = CreateHttpClient())
    {
        var body = new JsonContent(profile);
        var response = await client.PutAsync ("profile", body, cancellationToken);
        if (!response.IsSuccessStatusCode) {
            return HandleFault<bool>(response);
        }

        return ApiResponse.Success();
    }
}

public async Task<ApiResponse> SetProfilePicture (Image picture, CancellationToken cancellationToken)
{
    using (var client = CreateHttpClient ())
    {
        var memoryStream = new MemoryStream (picture.ImageBytes);
        var content = new StreamContent (memoryStream);
        content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue (picture.MediaType);

        var response = await client.PostAsync ("profile/image", content, cancellationToken);
        if (!response.IsSuccessStatusCode) {
            return HandleFault<bool>(response);
        }

        return ApiResponse.Success();
    }
}

问题是当我在上一次上传仍在运行时调用UploadProfileAndImage时,会调用CancelProfileAndImageUpload,导致抛出异常。

System.ObjectDisposedException: The object was used after being disposed.  

使用的对象是System.Net.Sockets.NetworkStreamSystem.Net.WebConnection.EndWrite中会抛出异常。

有没有人经历过上述事情并知道我做错了什么?

更新

以下是Xamarin项目示例:

Download from Google Drive

在应用程序显示的按钮上多次单击快速时会抛出异常。该示例重用了此问题中发布的代码。

这是异常的堆栈跟踪:

    2015-06-25 00:35:11.075 Example[2713:111447] 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.Threading.Tasks.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.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.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.Tasks.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+ConfiguredTaskAwaiter.GetResult () [0x00000] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:477 
  at System.Net.Http.HttpClientHandler+<SendAsync>c__async0.MoveNext () [0x002f4] 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.Threading.Tasks.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.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.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.Tasks.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.CookieAwareMessageHandler+<SendAsync>c__async0.MoveNext () [0x00115] in /Users/mku/Documents/Private projects/Xamarin/Example/Shared/CookeAwareMessageHandler.cs:30 
--- 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.Threading.Tasks.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.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.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.Tasks.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+ConfiguredTaskAwaiter[System.Net.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+<SendAsyncWorker>c__async0.MoveNext () [0x000a9] 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.Threading.Tasks.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.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.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.Tasks.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+<SetProfilePicture>c__async0.MoveNext () [0x000df] in /Users/mku/Documents/Private projects/Xamarin/Example/Shared/ProfileApi.cs:23 
--- 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.Threading.Tasks.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.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.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.Tasks.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[Shared.ApiResponse[]].GetResult () [0x00000] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:372 
  at Shared.ProfileDownloader+<UploadProfileAndImage>c__async0.MoveNext () [0x0013e] in /Users/mku/Documents/Private projects/Xamarin/Example/Shared/ProfileDownloader.cs:57 
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.Threading.Tasks.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.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.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.Tasks.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+ConfiguredTaskAwaiter.GetResult () [0x00000] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:477 
  at System.Net.Http.HttpClientHandler+<SendAsync>c__async0.MoveNext () [0x002f4] 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.Threading.Tasks.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.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.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.Tasks.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.CookieAwareMessageHandler+<SendAsync>c__async0.MoveNext () [0x00115] in /Users/mku/Documents/Private projects/Xamarin/Example/Shared/CookeAwareMessageHandler.cs:30 
--- 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.Threading.Tasks.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.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.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.Tasks.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+ConfiguredTaskAwaiter[System.Net.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+<SendAsyncWorker>c__async0.MoveNext () [0x000a9] 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.Threading.Tasks.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.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.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.Tasks.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+<SetProfilePicture>c__async0.MoveNext () [0x000df] in /Users/mku/Documents/Private projects/Xamarin/Example/Shared/ProfileApi.cs:23 
--- 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.Threading.Tasks.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.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.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.Tasks.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[Shared.ApiResponse[]].GetResult () [0x00000] in /Users/builder/data/lanes/1503/e6ebd18b/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:372 
  at Shared.ProfileDownloader+<UploadProfileAndImage>c__async0.MoveNext () [0x0013e] in /Users/mku/Documents/Private projects/Xamarin/Example/Shared/ProfileDownloader.cs:57 

0 个答案:

没有答案