• ASP.NET Web Api 实现数据的分页(转载)


    转载地址:http://www.cnblogs.com/fzrain/p/3542608.html

    前言

    这篇文章我们将使用不同的方式实现手动分页(关于高端大气上档次的OData本文暂不涉及,但有可能会在系列的后期介绍,还没确定。。。),对于分页的结果,我们将采用2种不同的方式响应给客户端(1.将分页元数据封装在响应Body中2.在http响应报文头部添加分页信息)。

    众所周知,在服务器端一次性返回成百上千条数据是非常恐怖的,在我们设计Api的时候,对于Get方法我们应该以分页的方式返回。例如:每次响应给客户端10条数据,并且包含“上一页”和“下一页”的标签,这样用户就能去获得他想要的数据。

    Way1.封装分页元数据封装在响应Body中

    修改“CoursesController”的Get方法实现分页而不是一次性把所有数据返回,下面上代码:

    复制代码
    public Object Get(int page = 0, int pageSize = 10)
         {
             IQueryable<Course> query;
     
             query = TheRepository.GetAllCourses().OrderBy(c => c.CourseSubject.Id);
             var totalCount = query.Count();
             var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);
     
             var urlHelper = new UrlHelper(Request);
             var prevLink = page > 0 ? urlHelper.Link("Courses", new { page = page - 1 }) : "";
             var nextLink = page < totalPages - 1 ? urlHelper.Link("Courses", new { page = page + 1 }) : "";
     
             var results = query
                           .Skip(pageSize * page)
                           .Take(pageSize)
                           .ToList()
                           .Select(s => TheModelFactory.Create(s));
     
             return new
             {
                 TotalCount = totalCount,
                 TotalPages = totalPages,
                 PrevPageLink = prevLink,
                 NextPageLink = nextLink,
                 Results = results
             };
     
         }
    复制代码

    解释一下上面的代码:

        在Get方法上添加了2个有默认值的参数,这两个参数就是用来过滤我们查询结果集的——例如:我们想获取第2页的数据,那么对应的Get请求就应该是这种形式:http://localhost:{your_port}/api/courses/?page=1,注意:在这里我们只给了一个参数,那么pageSize就是默认值10.

    客户端收到的部分响应就应该是:

    复制代码
    {
        "totalCount": 32,
        "totalPages": 4,
        "prevPageLink": "http://localhost:3300/api/courses?page=0&pageSize=10",
        "nextPageLink": "http://localhost:3300/api/courses?page=2&pageSize=10",
        "results": [
            {
                "id": 11,
                "url": "http://localhost:3300/api/courses/11",
                "name": "English Education 2",
                "duration": 4,
                "description": "The course will talk in depth about: English Education 2",
                "tutor": {
                    "id": 4,
                    "email": "Kareem.Ismail@outlook.com",
                    "userName": "KareemIsmail",
                    "firstName": "Kareem",
                    "lastName": "Ismail",
                    "gender": 0
                },
                "subject": {
                    "id": 4,
                    "name": "English"
                }
            },
    复制代码

      Repository中GetAllCourses的返回值为IQueryable,因此在执行skip和take方法时并没有到SQL Server中执行SQL语句,最后查询的也是分页好的数据,体现出按需查询的特色。

    在我们返回给客户端的数据中,其中分页元数据中包含了totalCount, totalPages, prevPageLink, nextPageLink这些数据,对于客户端来说我们返回totalCount, totalPages这两条数据非常有用,这样就可以与一些Grid配合使用来绑定结果。

    通常来说我们会将分页元数据封装在响应Body中,对于开发者来说我们提供了所有分页信息。但有的API消费者因此只想获取它请求的数据而不需要分页元数据,那么他在解析响应结果是就会很费劲,因此这里出现了另一种方式来向客户端响应分页元数据——在响应报文头部附加分页元数据:Body部分只包含请求的资源,我们新增一个头部信息“X-Pagination”。

    Way2.封装分页元数据到响应Header中

    我们修改StudentsController来实现将分页元数据封装在Header中,使用这种方法后,需要分页元数据的客户端直接从Header部分获取,不需要的客户端直接解析响应的Body即可。

    实现起来也非常简单,下面上代码:

    复制代码
    public IEnumerable<StudentBaseModel> Get(int page = 0, int pageSize = 10)
            {
                IQueryable<Student> query;
    
                query = TheRepository.GetAllStudentsWithEnrollments().OrderBy(c => c.LastName);
    
                var totalCount = query.Count();
                var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);
    
                var urlHelper = new UrlHelper(Request);
                var prevLink = page > 0 ? urlHelper.Link("Students", new { page = page - 1, pageSize = pageSize }) : "";
                var nextLink = page < totalPages - 1 ? urlHelper.Link("Students", new { page = page + 1, pageSize = pageSize }) : "";
    
                var paginationHeader = new
                {
                    TotalCount = totalCount,
                    TotalPages = totalPages,
                    PrevPageLink = prevLink,
                    NextPageLink = nextLink
                };
    
                System.Web.HttpContext.Current.Response.Headers.Add("X-Pagination",
                                                                    Newtonsoft.Json.JsonConvert.SerializeObject(paginationHeader));
    
                var results = query
                            .Skip(pageSize * page)
                            .Take(pageSize)
                            .ToList()
                            .Select(s => TheModelFactory.CreateSummary(s));
    
                return results;
            }
    复制代码

    这里我们添加了一个Header,里面包含一个Json序列化的分页元数据,客户端收到的响应:

    QQ截图20140209221847

    总结

    2种分页技术各有优劣,感觉碰到具体应用的时候再做选择了

  • 相关阅读:
    Spring boot启动后没有生成日志文件问题排错
    keepalived 容器在宿主机重启后无法启动问题:报错:daemon is already running
    【转】iptables命令、规则、参数详解
    【转】VMwareCLI命令参考
    【转】通过ionice和nice降低shell脚本运行的优先级
    【转】dd命令详解及利用dd测试磁盘性能
    【转】Keepalived无法绑定VIP故障排查经历
    【转】浏览器Request Header和Response Header的内容
    【转】Spring Boot 日志配置(超详细)
    Spring数据访问和事务
  • 原文地址:https://www.cnblogs.com/yxlblogs/p/3673586.html
Copyright © 2020-2023  润新知