一种通用异步方法,用于请求不同资源的可选分页列表

本文关键字:资源 列表 分页 请求 用于 一种 异步方法 | 更新日期: 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是一个带有泛型的类型。希望它能有所帮助,试着在没有来源的情况下从头开始写这篇文章。