上个月发布了一个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>