上个月发布了一个WP8.1应用:NuGet Search,并在GitHub开了源:https://github.com/EdiWang/WP-NuGetSearch
NuGet的服务接口是个WCF OData Service,我尝试使用了跨Framework的PCI工程,结果no zuo no die了。和一般.NET类库不同,PCL有些tricky的地方要爆。下面是开荒成功的代码:
public async Task<Response<IEnumerable<V2FeedPackage>>> GetDataAsync(string searchTerm, int pageIndex, bool includePreRelease = false) { try { IDictionary<string, object> queryOptions = new Dictionary<string, object> { { "filter", "IsLatestVersion" }, { "searchTerm", "'" + UrlEncodeOdataParameter(searchTerm) + "'" }, { "includePrerelease", includePreRelease.ToString().ToLower() } }; if (pageIndex < 1) { pageIndex = 1; } int startRow = (pageIndex - 1) * PageSize; var nquery = context.CreateQuery<V2FeedPackage>("Search") .OrderByDescending(p => p.DownloadCount) .Skip(startRow) .Take(PageSize); var query = (DataServiceQuery<V2FeedPackage>)nquery; if (queryOptions.Any()) { query = queryOptions.Aggregate(query, (current, pair) => current.AddQueryOption(pair.Key, pair.Value)); } var taskFactory = new TaskFactory<IEnumerable<V2FeedPackage>>(); var result = await taskFactory.FromAsync(query.BeginExecute(null, null), query.EndExecute); var packages = result.ToList(); return new Response<IEnumerable<V2FeedPackage>>() { IsSuccess = true, Item = packages }; } catch (Exception e) { return new Response<IEnumerable<V2FeedPackage>>() { Message = e.Message }; } }
需要注意的:
1. 对于非标准的操作符,需要使用“AddQueryOption()”方法把它们撸进去,就像我代码里一样,用了个字典包装这些参数
IDictionary<string, object> queryOptions = new Dictionary<string, object> { { "filter", "IsLatestVersion" }, { "searchTerm", "'" + UrlEncodeOdataParameter(searchTerm) + "'" }, { "includePrerelease", includePreRelease.ToString().ToLower() } };
2. 由于OData Client的PCL版本只支持异步操作,但它又没暴露基于Task的异步方法(你TM在逗我?),我们只能用TaskFactory把IAsyncResult撸成awaitable的Task
var taskFactory = new TaskFactory<IEnumerable<V2FeedPackage>>(); var result = await taskFactory.FromAsync(query.BeginExecute(null, null), query.EndExecute);
3. 对于标准LINQ操作,OData库可以正确翻译到URL,所以可以放心写这样的查询语句:
var nquery = context.CreateQuery<V2FeedPackage>("Search") .OrderByDescending(p => p.DownloadCount) .Skip(startRow) .Take(PageSize);
翻译后的URL:
https://www.nuget.org/api/v2/Search()?$orderby=DownloadCount desc&$skip=0&$top=30
带参数字典的:
https://www.nuget.org/api/v2/Search()?$orderby=DownloadCount desc&$skip=0&$top=30&filter=IsLatestVersion&searchTerm=''&includePrerelease=false
4. Response格式的例子:
<?xml version="1.0" encoding="utf-8"?> <feed xml:base="https://www.nuget.org/api/v2/curated-feeds/microsoftdotnet/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"> <id>https://www.nuget.org/api/v2/curated-feeds/microsoftdotnet/Search</id> <title type="text">Search</title> <updated>2014-06-01T02:31:18Z</updated> <link rel="self" title="Search" href="Search" /> <entry> <id>https://www.nuget.org/api/v2/curated-feeds/microsoftdotnet/Packages(Id='EntityFramework',Version='6.1.0')</id> <category term="NuGetGallery.V2FeedPackage" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> <link rel="edit" title="V2FeedPackage" href="Packages(Id='EntityFramework',Version='6.1.0')" /> <title type="text">EntityFramework</title> <summary type="text">Entity Framework is Microsoft's recommended data access technology for new applications.</summary> <updated>2014-05-20T18:39:08Z</updated> <author> <name>Microsoft</name> </author> <link rel="edit-media" title="V2FeedPackage" href="Packages(Id='EntityFramework',Version='6.1.0')/$value" /> <content type="application/zip" src="https://www.nuget.org/api/v2/curated-feeds/package/EntityFramework/6.1.0" /> <m:properties> <d:Version>6.1.0</d:Version> <d:NormalizedVersion>6.1.0</d:NormalizedVersion> <d:Copyright m:null="true" /> <d:Created m:type="Edm.DateTime">2014-03-17T21:38:19.813</d:Created> <d:Dependencies></d:Dependencies> <d:Description>Entity Framework is Microsoft's recommended data access technology for new applications.</d:Description> <d:DownloadCount m:type="Edm.Int32">5345924</d:DownloadCount> <d:GalleryDetailsUrl>https://www.nuget.org/packages/EntityFramework/6.1.0</d:GalleryDetailsUrl> <d:IconUrl>http://go.microsoft.com/fwlink/?LinkID=386613</d:IconUrl> <d:IsLatestVersion m:type="Edm.Boolean">true</d:IsLatestVersion> <d:IsAbsoluteLatestVersion m:type="Edm.Boolean">false</d:IsAbsoluteLatestVersion> <d:IsPrerelease m:type="Edm.Boolean">false</d:IsPrerelease> <d:Language>en-US</d:Language> <d:Published m:type="Edm.DateTime">2014-03-17T21:38:19.877</d:Published> <d:PackageHash>u/M0OEfqxTUsL5BwzD66eBGm278/ozqdLK3JvMO6QwUxxc+z7ZUkTYm4suDhWRqzkc6mOhvXDQY5dZUwbldxyQ==</d:PackageHash> <d:PackageHashAlgorithm>SHA512</d:PackageHashAlgorithm> <d:PackageSize m:type="Edm.Int64">4222059</d:PackageSize> <d:ProjectUrl>http://go.microsoft.com/fwlink/?LinkID=320540</d:ProjectUrl> <d:ReportAbuseUrl>https://www.nuget.org/package/ReportAbuse/EntityFramework/6.1.0</d:ReportAbuseUrl> <d:ReleaseNotes m:null="true" /> <d:RequireLicenseAcceptance m:type="Edm.Boolean">true</d:RequireLicenseAcceptance> <d:Tags>Microsoft EF Database Data O/RM ADO.NET</d:Tags> <d:Title>EntityFramework</d:Title> <d:VersionDownloadCount m:type="Edm.Int32">345877</d:VersionDownloadCount> <d:MinClientVersion m:null="true" /> <d:LastEdited m:type="Edm.DateTime" m:null="true" /> <d:LicenseUrl>http://go.microsoft.com/fwlink/?LinkID=320539</d:LicenseUrl> <d:LicenseNames m:null="true" /> <d:LicenseReportUrl m:null="true" /> </m:properties> </entry> ..... ..... </feed>