【发布时间】:2012-04-04 12:31:24
【问题描述】:
从我所看到的关于将 Async CTP 与事件异步模式一起使用的情况来看,我这里的代码应该可以正常工作,var result1 = await tcs1.Task 会阻塞直到clientGetFileList.GetCompleted 触发。然而,最终发生的事情是,我在 return GetRestoreStreamAwait().Result 上被退回到 GetRestoreStream,它永远不会返回 - 相反,我的应用程序几乎锁定了我。
有人可以向我解释我做错了什么吗?
protected override Stream GetRestoreStream()
{
if (SkyDriveFolderId != null)
return GetRestoreStreamAwait().Result;
return Stream.Null;
}
private async Task<Stream> GetRestoreStreamAwait()
{
LiveConnectClient clientGetFileList = new LiveConnectClient(_session);
TaskCompletionSource<LiveOperationCompletedEventArgs> tcs1 = new TaskCompletionSource<LiveOperationCompletedEventArgs>();
EventHandler<LiveOperationCompletedEventArgs> d1 = (o, e) => { tcs1.TrySetResult(e); };
clientGetFileList.GetCompleted += d1;
clientGetFileList.GetAsync(SkyDriveFolderId + "/files");
var result1 = await tcs1.Task;
clientGetFileList.GetCompleted -= d1;
// ... method continues for a while
}
更新: 这段代码似乎一直在移动,但是task.Start() 抛弃了InvalidOperationException,所以我实际上从来没有在最后得到流。将它包装在 try/catch 中也不会改变任何东西——如果没有 try/catch,InvalidOperationException 会被进一步捕获到堆栈中,而操作会愉快地运行,而不会知道它的结果将永远不会被使用;有了它,task.Result 可以像上面的代码一样可靠地冻结事物。
protected override Stream GetRestoreStream()
{
if (SkyDriveFolderId != null)
{
var task = GetRestoreStreamImpl();
task.Start();
return task.Result;
}
return Stream.Null;
}
private async Task<Stream> GetRestoreStreamImpl()
{
var getResult = await GetTaskAsync(SkyDriveFolderId + "/files");
List<object> data = (List<object>)getResult["data"];
foreach (IDictionary<string, object> dictionary in data)
{
if (dictionary.ContainsKey("name") && (string)dictionary["name"] == BackupFileName)
{
if (dictionary.ContainsKey("id"))
{
SkyDriveFileId = (string)dictionary["id"];
break;
}
}
}
if (String.IsNullOrEmpty(SkyDriveFileId))
{
MessageBox.Show("Restore failed: could not find backup file", "Backup", MessageBoxButton.OK);
return Stream.Null;
}
return await DownloadTaskAsync(SkyDriveFileId + "/content");
}
private Task<IDictionary<string,object>> GetTaskAsync(string path)
{
var client = new LiveConnectClient(_session);
var tcs = new TaskCompletionSource<IDictionary<string, object>>();
client.GetCompleted += (o, e) =>
{
if (e.Error != null)
tcs.TrySetException(e.Error);
else if (e.Cancelled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(e.Result);
};
client.GetAsync(path);
return tcs.Task;
}
private Task<Stream> DownloadTaskAsync(string path)
{
var client = new LiveConnectClient(_session);
var tcs = new TaskCompletionSource<Stream>();
client.DownloadCompleted += (o, e) =>
{
if (e.Error != null)
tcs.TrySetException(e.Error);
else if (e.Cancelled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(e.Result);
};
client.DownloadAsync(path);
return tcs.Task;
}
【问题讨论】:
-
似乎微软已经有一个用于 Live Connect SDK 的
async/await示例,我的 Google-fu 需要一些工作。该示例位于github.com/liveservices/LiveSDK/tree/master/Samples/…,其做的事情与我尝试的有所不同。
标签: c# asynchronous windows-phone-7.1 live-connect-sdk