取消 postAsync 时出现 ObjectDisposedException
ObjectDisposedException when canceling postAsync
我的 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);
}
我就是这样做的:
- 按两次按钮,调用
UploadImage
两次。第一次开始上传,第二次取消,我得到 TaskCancelledException
.
- 我又按了两次按钮。第一次开始上传,但第二次导致
ObjectDisposedException
.
有谁知道为什么会抛出2.中描述的异常?
更新
这是异常的堆栈跟踪。它被抛到 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.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+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.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+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+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.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.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
您需要等待 UploadImage
否则流将在调用后立即处理。
试试这个:
var image = UIImage.FromFile ("Images/SpongeBob.png");
using (var stream = image.ToStream ()) {
awaProfileDownloader.Instance.UploadImage (stream);
}
您必须将包含该代码的方法更改为 async
方法。
原来这实际上是Mono中的一个错误,现在已经修复并将在4.2版本中发布。
我的 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);
}
我就是这样做的:
- 按两次按钮,调用
UploadImage
两次。第一次开始上传,第二次取消,我得到TaskCancelledException
. - 我又按了两次按钮。第一次开始上传,但第二次导致
ObjectDisposedException
.
有谁知道为什么会抛出2.中描述的异常?
更新
这是异常的堆栈跟踪。它被抛到 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.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+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.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+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+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.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.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
您需要等待 UploadImage
否则流将在调用后立即处理。
试试这个:
var image = UIImage.FromFile ("Images/SpongeBob.png");
using (var stream = image.ToStream ()) {
awaProfileDownloader.Instance.UploadImage (stream);
}
您必须将包含该代码的方法更改为 async
方法。
原来这实际上是Mono中的一个错误,现在已经修复并将在4.2版本中发布。