编程语言
首页 > 编程语言> > Ultimate ASP.NET CORE 6.0 Web API --- 读书笔记(16)

Ultimate ASP.NET CORE 6.0 Web API --- 读书笔记(16)

作者:互联网

16 Paging

本文内容来自书籍: Marinko Spasojevic - Ultimate ASP.NET Core Web API - From Zero To Six-Figure Backend Developer (2nd edition)

分页的意思是,只是返回部分结果的API,返回所有结果不仅仅是非常无效的,而且对应用和硬件有着毁灭性的影响。还有客户端的资源一般都是有限的,必须限制展示的数据

16.2 Paging Implementation

我们不希望改变base repository的逻辑或者实现任何业务逻辑在控制器当中

我们希望URI是这样的
https://localhost:5001/api/companies/companyId/employees?pageNumber=2&pageSize=2

而且,即使客户端的请求是:
https://localhost:5001/api/companies/companyId/employees

我们也要约束我们的API,而不是返回所有的数据

所以现在我们开始修改controller

我们需要一个包装着查询参数的DTO

// 首先创建一个分页参数的基类
public abstract class RequestParameters
{
    private const int MaxPageSize = 50;
    public int PageNumber { get; set; } = 1;
    private int _pageSize = 10;

    public int PageSize
    {
        get => _pageSize;
        set => _pageSize = value > MaxPageSize ? MaxPageSize : value;
    }
}

public class EmployeeParameters : RequestParameters
{
}
[HttpGet]
public async Task<IActionResult> GetEmployeesForCompany(Guid companyId,
    [FromQuery] EmployeeParameters employeeParameters)
{
    var employees = await _service.EmployeeService.GetEmployeesAsync(companyId,
        trackChanges: false);
    return Ok(employees);
}

可以对分页的参数进一步封装

public class MetaData
{
    public int CurrentPage { get; set; }
    public int TotalPages { get; set; }
    public int PageSize { get; set; }
    public int TotalCount { get; set; }
    public bool HasPrevious => CurrentPage > 1;
    public bool HasNext => CurrentPage < TotalPages;
}

public class PagedList<T> : List<T>
{
    public MetaData MetaData { get; set; }

    public PagedList(IEnumerable<T> items, int count, int pageNumber, int pageSize)
    {
        MetaData = new MetaData
        {
            TotalCount = count,
            PageSize = pageSize,
            CurrentPage = pageNumber,
            TotalPages = (int)Math.Ceiling(count / (double)pageSize)
        };
        AddRange(items);
    }

    public static PagedList<T> ToPagedList(IEnumerable<T> source, int pageNumber, int
        pageSize)
    {
        var enumerable = source.ToList();
        
        var count = enumerable.Count;
        
        var items = enumerable
            .Skip((pageNumber - 1) * pageSize)
            .Take(pageSize).ToList();
        return new PagedList<T>(items, count, pageNumber, pageSize);
    }
}

然后在响应的时候,需要将这个元数据也一并返回

[HttpGet]
    public async Task<IActionResult> GetEmployeesForCompany(Guid companyId,
        [FromQuery] EmployeeParameters employeeParameters)
    {
        var pagedResult =
            await _service.EmployeeService.GetEmployeesAsync(companyId, employeeParameters, trackChanges: false);

        Response.Headers.Add("X-Pagination", JsonSerializer.Serialize(pagedResult.metaData));

        return Ok(pagedResult.employees);
    }

但是上面的方案,存在一个性能问题,当数据库的数据达到千万级别的时候,就会很慢,因为在分页之前,首先是获取的ID相关的数据,也就是某一个ID的全部数据,然后再创建分页实体,过滤数据;当面对很多数据的时候,我们需要在数据库查询的时候,就已经做出过滤的动作,使得筛选放到数据库,而不是APP中,这样的性能会好很多

还有就是,我们需要让客户端读取我们的新的响应头X-Pagination,我们需要更改CORS的配置

public static void ConfigureCors(this IServiceCollection services) =>
        services.AddCors(options =>
        {
            options.AddPolicy("CorsPolicy", builder =>
                builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .WithExposedHeaders("X-Pagination"));
        });

标签:CORE,ASP,pageSize,读书笔记,int,get,set,pageNumber,public
来源: https://www.cnblogs.com/huangwenhao1024/p/16383191.html