利用Async CTP改造Live SDK for WP7
最近在开发Windows Phone8应用中用到了Live SDK for WP8,但是在将该应用的WP8版本移植到WP7的时候却发生了许多问题,无法直接将项目进行移植。具体原因是因为Live SDK for WP8利用了Async特性,但是WP7默认是不支持Async特性的,所以微软在Live SDK for WP7中还是采用回调函数的方式,这就给代码的移植造成了很大的困难,当时我在想是否要重写一遍后台代码,虽然这个方案可行,但是以后2套代码进行维护的时候,又极度麻烦,我最后还是决定扩展Live SDK for WP7来实现Async特性。
首先必须下载Async CTP可以参考Windows Phone开发经验谈(16)-使用Async CTP简化异步编程,准备工作做完了,我们就可以开工了
建立类EAPCommon和AsyncExtensions用于对Live SDK原始方法的扩展
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ExpressWP.Extensions { internal static class EAPCommon { internal static void HandleProgress<T, E>(TaskCompletionSource<T> tcs, ProgressChangedEventArgs eventArgs, Func<E> getProgress, IProgress<E> callback) { if (eventArgs.UserState == tcs) { callback.Report(getProgress.Invoke()); } } internal static void HandleCompletion<T>(TaskCompletionSource<T> tcs, bool requireMatch, AsyncCompletedEventArgs e, Func<T> getResult, Action unregisterHandler) { if (requireMatch) { if (e.UserState != tcs) { return; } } try { unregisterHandler.Invoke(); } finally { if (e.Cancelled) { tcs.TrySetCanceled(); } else { if (e.Error != null) { tcs.TrySetException(e.Error); } else { tcs.TrySetResult(getResult.Invoke()); } } } } } }
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using Microsoft.Live; using ExpressWP.Util; namespace ExpressWP.Extensions { public static class AsyncExtensions { private static Uri GetUri(this WebClient webClient, string path) { string baseAddress = webClient.BaseAddress; Uri address; if (!string.IsNullOrEmpty(baseAddress)) { if (!Uri.TryCreate(new Uri(baseAddress), path, out address)) { return webClient.GetUri(Path.GetFullPath(path)); } } else { if (!Uri.TryCreate(path, UriKind.Absolute, out address)) { return webClient.GetUri(Path.GetFullPath(path)); } } return webClient.GetUri(address); } private static Uri GetUri(this WebClient webClient, Uri address) { if (address == null) { throw new ArgumentNullException("address"); } Uri result = address; if (!address.IsAbsoluteUri && !string.IsNullOrEmpty(webClient.BaseAddress) && !Uri.TryCreate(new Uri(webClient.BaseAddress), address, out result)) { return address; } return result; } public static Task<Stream> OpenReadTaskAsync(this WebClient webClient, string address) { return webClient.OpenReadTaskAsync(webClient.GetUri(address)); } public static Task<Stream> OpenReadTaskAsync(this WebClient webClient, Uri address) { TaskCompletionSource<Stream> tcs = new TaskCompletionSource<Stream>(address); OpenReadCompletedEventHandler handler = null; handler = delegate(object sender, OpenReadCompletedEventArgs e) { EAPCommon.HandleCompletion<Stream>(tcs, true, e, () => e.Result, delegate { webClient.OpenReadCompleted -= (handler); }); }; webClient.OpenReadCompleted += (handler); try { webClient.OpenReadAsync(address, tcs); } catch { webClient.OpenReadCompleted -= (handler); throw; } return tcs.Task; } public static Task<LoginCompletedEventArgs> LoginTaskAsync(this LiveAuthClient liveAuthClient, IEnumerable<string> scopes) { TaskCompletionSource<LoginCompletedEventArgs> tcs = new TaskCompletionSource<LoginCompletedEventArgs>(scopes); EventHandler<LoginCompletedEventArgs> handler = null; handler = delegate(object sender, LoginCompletedEventArgs e) { EAPCommon.HandleCompletion<LoginCompletedEventArgs>(tcs, true, e, () => e, delegate { liveAuthClient.LoginCompleted -= (handler); }); }; liveAuthClient.LoginCompleted += (handler); try { liveAuthClient.LoginAsync(scopes, tcs); } catch { liveAuthClient.LoginCompleted -= (handler); throw; } return tcs.Task; } public static Task<LiveOperationCompletedEventArgs> GetTaskAsync(this LiveConnectClient liveConnectClient, string path) { TaskCompletionSource<LiveOperationCompletedEventArgs> tcs = new TaskCompletionSource<LiveOperationCompletedEventArgs>(path); EventHandler<LiveOperationCompletedEventArgs> handler = null; handler = delegate(object sender, LiveOperationCompletedEventArgs e) { EAPCommon.HandleCompletion<LiveOperationCompletedEventArgs>(tcs, true, e, () => e, delegate { liveConnectClient.GetCompleted -= (handler); }); }; liveConnectClient.GetCompleted += (handler); try { liveConnectClient.GetAsync(path, tcs); } catch { liveConnectClient.GetCompleted -= (handler); throw; } return tcs.Task; } public static Task<LiveOperationCompletedEventArgs> PostTaskAsync(this LiveConnectClient liveConnectClient, string path, IDictionary<string, object> body) { TaskCompletionSource<LiveOperationCompletedEventArgs> tcs = new TaskCompletionSource<LiveOperationCompletedEventArgs>(path); EventHandler<LiveOperationCompletedEventArgs> handler = null; handler = delegate(object sender, LiveOperationCompletedEventArgs e) { EAPCommon.HandleCompletion<LiveOperationCompletedEventArgs>(tcs, true, e, () => e, delegate { liveConnectClient.PostCompleted -= (handler); }); }; liveConnectClient.PostCompleted += (handler); try { liveConnectClient.PostAsync(path, body, tcs); } catch { liveConnectClient.PostCompleted -= (handler); throw; } return tcs.Task; } public static Task<LiveOperationCompletedEventArgs> UploadTaskAsync(this LiveConnectClient liveConnectClient, string path, Uri uri, OverwriteOption over) { TaskCompletionSource<LiveOperationCompletedEventArgs> tcs = new TaskCompletionSource<LiveOperationCompletedEventArgs>(path); EventHandler<LiveOperationCompletedEventArgs> handler = null; handler = delegate(object sender, LiveOperationCompletedEventArgs e) { EAPCommon.HandleCompletion<LiveOperationCompletedEventArgs>(tcs, true, e, () => e, delegate { liveConnectClient.UploadCompleted -= (handler); }); }; liveConnectClient.UploadCompleted += (handler); try { var stream = FileOperation.GetStreamFromISF(uri); liveConnectClient.UploadAsync(path, "packages.xml", stream, over, tcs); } catch(Exception ex) { liveConnectClient.UploadCompleted -= (handler); throw; } return tcs.Task; } public static Task<LiveDownloadCompletedEventArgs> DownloadTaskAsync(this LiveConnectClient liveConnectClient, string path) { TaskCompletionSource<LiveDownloadCompletedEventArgs> tcs = new TaskCompletionSource<LiveDownloadCompletedEventArgs>(path); EventHandler<LiveDownloadCompletedEventArgs> handler = null; handler = delegate(object sender, LiveDownloadCompletedEventArgs e) { EAPCommon.HandleCompletion<LiveDownloadCompletedEventArgs>(tcs, true, e, () => e, delegate { liveConnectClient.DownloadCompleted -= (handler); }); }; liveConnectClient.DownloadCompleted += (handler); try { liveConnectClient.DownloadAsync(path, tcs); } catch { liveConnectClient.DownloadCompleted -= (handler); throw; } return tcs.Task; } } }
其实代码并不复杂,我主要为Live SDK扩展了下面4个方法,让它们实现了Async的特性
DownloadTaskAsync
UploadTaskAsync
GetTaskAsync
LoginTaskAsync
最后给大家看看实现后的效果。
这样就不需要嵌套多个回调函数,改善了编程体验,也不需要再维护2套代码了,好了,就说到这里,欢迎大家留言讨论。
分类:
Windows Phone
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器