C# 用于请求不同资源的可选分页列表的通用异步方法
我正在访问一个REST API,它返回JSON格式的资源列表:C# 用于请求不同资源的可选分页列表的通用异步方法,c#,json,generics,pagination,async-await,C#,Json,Generics,Pagination,Async Await,我正在访问一个REST API,它返回JSON格式的资源列表: { "products": [ { ... }, { ... } ] } 当列表很大(>50项)时,响应将被分页,并向返回的JSON的根节点添加一个额外的pagination项,如下所示: { "pagination": { "results" : 490, "page" : 1, "page_size" : 50,
{
"products": [
{ ... },
{ ... }
]
}
当列表很大(>50项)时,响应将被分页,并向返回的JSON的根节点添加一个额外的pagination
项,如下所示:
{
"pagination": {
"results" : 490,
"page" : 1,
"page_size" : 50,
"pages" : 10
},
"products": [
{ ... },
{ ... }
]
}
public class PaginatedList
{
[JsonProperty("pagination")]
public Pagination Pagination { get; set; }
}
public class ProductList : PaginatedList
{
[JsonProperty("products")]
public List<Product> Products { get; set; }
}
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; }
}
为了满足这一需求,我有一个paginedList
类(可能不是最好的名称),它看起来像:
{
"pagination": {
"results" : 490,
"page" : 1,
"page_size" : 50,
"pages" : 10
},
"products": [
{ ... },
{ ... }
]
}
public class PaginatedList
{
[JsonProperty("pagination")]
public Pagination Pagination { get; set; }
}
public class ProductList : PaginatedList
{
[JsonProperty("products")]
public List<Product> Products { get; set; }
}
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; }
}
一个ProductList
类,看起来像:
{
"pagination": {
"results" : 490,
"page" : 1,
"page_size" : 50,
"pages" : 10
},
"products": [
{ ... },
{ ... }
]
}
public class PaginatedList
{
[JsonProperty("pagination")]
public Pagination Pagination { get; set; }
}
public class ProductList : PaginatedList
{
[JsonProperty("products")]
public List<Product> Products { get; set; }
}
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;
}
public List GetProducts()
{
返回getResourceAsync(productsResourceName).Result.Products;
}
以及:
异步任务getResourceListAsync(字符串resourceName)
{
var url=string.Concat(BaseUrl,resourceName);
var凭证=新的网络凭证(用户名、密码);
var handler=newhttpclienthandler{Credentials=Credentials};
使用(var客户端=新的HttpClient(处理程序)){
var response=wait client.GetAsync(url);
var contentString=await response.Content.ReadAsStringAsync();
var resource=await JsonConvert.DeserializeObjectAsync(contentString);
返回资源;
}
}
在
GetProducts
方法中添加对分页的支持非常简单,但这意味着为每种类型的资源(产品、客户、供应商等)复制非常相似的代码。问题是,如何获得getResourceListAsync
方法,使其支持分页和非分页列表,并适用于不同的资源?我看到了您的问题。实际上是被困在同一辆车里。我最终做的是一个接口,我想让我的类实现这个接口。正如我在导出数据时所做的那样,它被称为IExportable。这个东西返回PagedResult并接受IPagedRequest
所以关键是我在任务中的代码只是使用接口,实际上不知道终端类型是什么。PagedResult是具有泛型的类型。
希望它能有所帮助,试着在没有来源的情况下从头开始写这篇文章。为了使这个场景成为可能:
// 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);
//支持这两种方案
var json=@“{'products':[{Id:1,名称:'A'},{Id:2,名称:'B'}]}”;
var results=Helper.ParseFromJsonResult(json);
var anotherJson=@“{‘分页’:{
“结果”:490,
“页面”:1,
“页面大小”:50,
“页数”:10页
},
“产品”:[
{Id:1,名称:'A'},{Id:2,名称:'B'}
]}";
var anotherResults=Helper.ParseFromJsonResult(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
}
}
公共静态类帮助器
{
私有静态只读多元化服务\u名称服务=
CreateService(新文化信息(“en-us”);
//提供复数名称[产品对应产品]
//为Product class确定结果(例如products)的名称
私有静态模块生成器_ModuleBuilder;
静态助手()
{
var asmName=新的AssemblyName();
asmName.Name=“MyHelpers”;
AssemblyBuilder asmBuilder=Thread.GetDomain().DefinedDynamicAssembly(asmName,AssemblyBuilderAccess.Run);
_ModuleBuilder=asmBuilder.DefinedDynamicModule(“MyHelpers”);
//程序集将运行时生成的类放入该程序集。
}
私有静态只读IDictionary_HelpersCache=new Dictionary();
公共静态列表ParseFromJsonResult(字符串json)
{
类型resultType=null;
var entityType=typeof(T);
var pluralName=_NameService.Pluralize(entityType.Name).ToLowerInvariant();
//产品类别的产品
if(_HelpersCache.ContainsKey(entityType))
{
//更好的性能
结果类型=_HelpersCache[entityType];
}
其他的
{
//需要另一个运行时生成的类吗
//结果:
/*公共类产品
{
公开上市产品;
}
*/
TypeBuilder结果TypeBuilder=\u ModuleBuilder.DefineType(pluralName,TypeAttributes.Public);
FieldBuilder field=resultTypeBuilder.DefineField(pluralName、typeof(List)、FieldAttributes.Public);
resultType=resultTypeBuilder.CreateType();
_添加(entityType,resultType);
}
Object result=JsonConvert.DeserializeObject(json,resultType);
return(List)resultType.GetField(pluralName).GetValue(result);//获取产品字段值
}
}
我希望这有帮助,如果你想了解更多信息,请告诉我
祝你好运为什么要异步等待异步方法?1.这毫无意义,你没有得到异步的任何好处。2.这几乎是在要求死锁发生。另外,你是否已经试图以某种方式解决你的问题?你试了什么?这是怎么失败的?@svick欢迎你用一个精巧的回答来解决你的问题。我刚刚开始使用异步,显然还没有对如何处理它有最好的理解。@svick我有一个基于RestSharp的运行良好的同步解决方案,但将其转换为异步使我完全陷入困境。非常感谢您的建议。请您提供更多详细信息,例如在
GetProducts中添加示例分页