一种通用异步方法,用于请求不同资源的可选分页列表
本文关键字:资源 列表 分页 请求 用于 一种 异步方法 | 更新日期: 2023-09-27 18:29:44
我正在访问一个REST API,它返回JSON格式的资源列表:
{
"products": [
{ ... },
{ ... }
]
}
当列表很大(>50个项目)时,响应将变为分页,并向返回的JSON的根节点添加一个额外的pagination
项目,如下所示:
{
"pagination": {
"results" : 490,
"page" : 1,
"page_size" : 50,
"pages" : 10
},
"products": [
{ ... },
{ ... }
]
}
为了满足这一点,我有一个PaginatedList
类(可能不是最好的名称),它看起来像:
public class PaginatedList
{
[JsonProperty("pagination")]
public Pagination Pagination { get; set; }
}
一个看起来像这样的ProductList
类:
public class ProductList : PaginatedList
{
[JsonProperty("products")]
public List<Product> Products { get; set; }
}
像这样的Pagination
类:
public class Pagination
{
[JsonProperty("results")]
public int Results { get; set; }
[JsonProperty("page")]
public int Page { get; set; }
[JsonProperty("page_size")]
public int PageSize { get; set; }
[JsonProperty("pages")]
public int Pages { get; set; }
}
要检索我的资源,我使用:
public List<Product> GetProducts()
{
return getResourceAsync<ProductList>(productsResourceName).Result.Products;
}
和:
async Task<T> getResourceListAsync<T>(string resourceName)
{
var url = string.Concat(BaseUrl, resourceName);
var credentials = new NetworkCredential(Username, Password);
var handler = new HttpClientHandler { Credentials = credentials };
using (var client = new HttpClient(handler)) {
var response = await client.GetAsync(url);
var contentString = await response.Content.ReadAsStringAsync();
var resource = await JsonConvert.DeserializeObjectAsync<T>(contentString);
return resource;
}
}
在GetProducts
方法中添加对分页的支持非常容易,但这意味着要为每种类型的资源(产品、客户、供应商等)复制非常相似的代码。问题是,如何获得getResourceListAsync
方法,使其支持分页和非分页列表and适用于不同的资源
要使这种情况成为可能:
// supports both scenarios
var json = @"{ 'products': [ { Id : 1 , Name : 'A' }, { Id : 2 , Name : 'B' } ] }";
var results = Helper.ParseFromJsonResult<Product>(json);
var anotherJson = @"{ 'pagination': {
'results' : 490,
'page' : 1,
'page_size' : 50,
'pages' : 10
},
'products': [
{ Id : 1 , Name : 'A' }, { Id : 2 , Name : 'B' }
]}";
var anotherResults = Helper.ParseFromJsonResult<Product>(anotherJson);
您可以使用以下代码:
public static class Helper
{
private static readonly PluralizationService _NameService =
PluralizationService.CreateService(new CultureInfo("en-us"));
// Provides Plural names [ products for Product ]
// to determinate the name of the result for example products for Product class
private static ModuleBuilder _ModuleBuilder;
static Helper()
{
var asmName = new AssemblyName();
asmName.Name = "MyHelpers";
AssemblyBuilder asmBuilder = Thread.GetDomain().DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
_ModuleBuilder = asmBuilder.DefineDynamicModule("MyHelpers");
// Assembly to put runtime generated classes to that.
}
private static readonly IDictionary<Type, Type> _HelpersCache = new Dictionary<Type, Type>();
public static List<T> ParseFromJsonResult<T>(String json)
{
Type resultType = null;
var entityType = typeof(T);
var pluralName = _NameService.Pluralize(entityType.Name).ToLowerInvariant();
// products for Product class
if (_HelpersCache.ContainsKey(entityType))
{
// better performance
resultType = _HelpersCache[entityType];
}
else
{
// need another runtime generated class
// result :
/* public class products
{
public List<Product> products;
}
*/
TypeBuilder resultTypeBuilder = _ModuleBuilder.DefineType(pluralName, TypeAttributes.Public);
FieldBuilder field = resultTypeBuilder.DefineField(pluralName, typeof(List<T>), FieldAttributes.Public);
resultType = resultTypeBuilder.CreateType();
_HelpersCache.Add(entityType, resultType);
}
Object result = JsonConvert.DeserializeObject(json, resultType);
return (List<T>)resultType.GetField(pluralName).GetValue(result); // get products field value
}
}
我希望这能有所帮助,如果你想了解更多信息,请告诉我
祝好运
我看到你的问题了。实际上是被困在同一个。我最终做的是一个接口,我的类想要实现它。因为我这样做是为了导出数据,所以它被称为IExportable。这个东西返回一个PagedResult并获取一个IPagedRequest。
关键是,我在任务中的代码只是处理接口,实际上并不知道结束类型是什么。PagedResult是一个带有泛型的类型。希望它能有所帮助,试着在没有来源的情况下从头开始写这篇文章。