使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【七】——实现资源的分页

简介: 原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【七】——实现资源的分页系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 这篇文章我们将使用不同的方式实现手动分页(关于高端大气上档次的OData本文暂不涉及,但有可能会在系列的后期介绍,还没确定。
原文: 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【七】——实现资源的分页

系列导航地址http://www.cnblogs.com/fzrain/p/3490137.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种分页技术各有优劣,感觉碰到具体应用的时候再做选择了。下一章将介绍Web Api安全性,实现Basic authentication

说明:对于项目的代码,由于之前学习了一点Git,所以从这一章起,我已经托管在github上了,以后最新的代码就直接在github上更新

源码地址:https://github.com/fzrain/WebApi.eLearning

目录
相关文章
|
1月前
|
JSON API 数据库
解释如何在 Python 中实现 Web 服务(RESTful API)。
解释如何在 Python 中实现 Web 服务(RESTful API)。
24 0
|
2月前
|
IDE Java API
使用Java Web技术构建RESTful API的实践指南
使用Java Web技术构建RESTful API的实践指南
|
2月前
|
存储 开发框架 NoSQL
ASP.NET WEB——项目中Cookie与Session的用法
ASP.NET WEB——项目中Cookie与Session的用法
29 0
|
1月前
|
XML JSON API
通过Flask框架创建灵活的、可扩展的Web Restful API服务
通过Flask框架创建灵活的、可扩展的Web Restful API服务
|
1月前
|
缓存 监控 API
Python Web框架FastAPI——一个比Flask和Tornada更高性能的API框架
Python Web框架FastAPI——一个比Flask和Tornada更高性能的API框架
57 0
|
1月前
|
JSON API 数据格式
构建高效Python Web应用:Flask框架与RESTful API设计实践
【2月更文挑战第17天】在现代Web开发中,轻量级框架与RESTful API设计成为了提升应用性能和可维护性的关键。本文将深入探讨如何使用Python的Flask框架来构建高效的Web服务,并通过具体实例分析RESTful API的设计原则及其实现过程。我们将从基本的应用架构出发,逐步介绍如何利用Flask的灵活性进行模块化开发,并结合请求处理、数据验证以及安全性考虑,打造出一个既符合标准又易于扩展的Web应用。
629 4
|
1月前
|
存储 PHP 数据库
使用Net2FTP轻松打造免费的Web文件管理器并公网远程访问
使用Net2FTP轻松打造免费的Web文件管理器并公网远程访问
|
2月前
|
前端开发 JavaScript API
前端秘法番外篇----学完Web API,前端才能算真正的入门
前端秘法番外篇----学完Web API,前端才能算真正的入门
|
2月前
|
API 网络架构
解释 RESTful API,以及如何使用它构建 web 应用程序。
解释 RESTful API,以及如何使用它构建 web 应用程序。
87 0
|
2月前
|
存储 前端开发 搜索推荐
前端开发中值得关注的三个Web API
【2月更文挑战第4天】Web API是前端开发中非常重要的一部分,它们为开发者提供了众多的功能和特性,帮助我们构建更加高效、优美的Web应用。本文将介绍三个值得关注的Web API,包括Web Storage、Geolocation和Web Notifications,希望能够对前端开发者有所帮助。