在Asp.net Web API中,对业务数据的分页查询处理是一个非常常见的接口,我们需要在查询条件对象中,定义好相应业务的查询参数,排序信息,请求记录数和每页大小信息等内容,根据这些查询信息,我们在后端的Asp.net Web API中实现对这些数据的按需获取,并排序返回给客户端使用。本篇随笔介绍利用查询条件对象,在Asp.net Web API中实现对业务数据的分页查询处理。

1、Web API控制器基类关系

返利网 https://www.cpa5.cn/

为了更好的进行相关方法的封装处理,我们把一些常规的接口处理放在BaseApiController里面,而把基于业务表的操作接口放在BusinessController里面定义,如下所示。

在BaseApiController里面,我们使用了结果封装和异常处理的过滤器统一处理,以便简化代码,如下控制器类定义。

    /// <summary>/// 所有接口基类/// </summary>
    [ExceptionHandling][WrapResult]public class BaseApiController : ApiController

其中ExceptionHandling 和WrapResult的过滤器处理,可以参考我的随笔《利用过滤器Filter和特性Attribute实现对Web API返回结果的封装和统一异常处理》进行详细了解。

而业务类的接口通用封装,则放在了BusinessController控制器里面,其中使用了泛型定义,包括实体类,业务操作类,分页条件类等内容作为约束参数,如下所示。

    /// <summary>/// 本控制器基类专门为访问数据业务对象而设的基类/// </summary>/// <typeparam name="B">业务对象类型</typeparam>/// <typeparam name="T">实体类类型</typeparam>
    [ApiAuthorize]public class BusinessController<B, T, TGetAllInput> : BaseApiControllerwhere B : classwhere TGetAllInput : IPagedAndSortedResultRequestwhere T : BaseEntity, new()

2、分页处理接口

其中IPagedAndSortedResultRequest接口,是借鉴ABP框架中对于分页部分的处理,因此分页函数需要实现这个接口,这个接口包含了请求的数量,偏移量, 以及排序等属性定义的。

而BusinessController的分页查询处理函数GetAll定义如下所示。

        /// <summary>/// 分页获取记录/// </summary>/// <param name="input"></param>/// <returns></returns>
        [HttpGet]public virtual PagedResultDto<T> GetAll([FromUri] TGetAllInput input){var condition = GetCondition(input);var list = GetPagedData(condition, input);return list;}

其中 GetCondition 函数是给子类进行重写,以便处理不同的条件查询的。我们以UserController控制器为例进行说明。

    /// <summary>/// 用户信息的业务控制器/// </summary>public class UserController : BusinessController<User, UserInfo, UserPagedDto>

其中传入的User是BLL业务层类,用来操作数据库;UserInfo是实体类,用来传递记录信息;UserPagedDto 则是分页查询条件类。

    /// <summary>/// 用户信息的业务查询类/// </summary>public class UserPagedDto : PagedAndSortedInputDto, IPagedAndSortedResultRequest{/// <summary>/// 默认构造函数/// </summary>public UserPagedDto() : base() { }/// <summary>/// 参数化构造函数/// </summary>/// <param name="skipCount">跳过的数量</param>/// <param name="resultCount">最大结果集数量</param>public UserPagedDto(int skipCount, int resultCount) : base(skipCount, resultCount){}/// <summary>/// 使用分页信息进行初始化SkipCount 和 MaxResultCount/// </summary>/// <param name="pagerInfo">分页信息</param>public UserPagedDto(PagerInfo pagerInfo) : base(pagerInfo){}#region Property Members/// <summary>/// 所属角色ID/// </summary>public virtual int? Role_ID { get; set; }public virtual int? ID { get; set; }/// <summary>/// 用户编码/// </summary>public virtual string HandNo { get; set; }/// <summary>/// 用户名/登录名/// </summary>public virtual string Name { get; set; }/// <summary>/// 用户密码/// </summary>public virtual string Password { get; set; }/// <summary>/// 用户全名/// </summary>public virtual string FullName { get; set; }/// <summary>/// 移动电话/// </summary>public virtual string MobilePhone { get; set; }/// <summary>/// 邮件地址/// </summary>public virtual string Email { get; set; }/// <summary>/// 默认部门ID/// </summary>public virtual string Dept_ID { get; set; }/// <summary>/// 所属机构ID/// </summary>public virtual string Company_ID { get; set; }/// <summary>/// 父ID/// </summary>public virtual int? PID { get; set; }/// <summary>/// 用户呢称/// </summary>public virtual string Nickname { get; set; }/// <summary>/// 是否过期/// </summary>public virtual bool? IsExpire { get; set; }/// <summary>/// 过期日期/// </summary>public virtual DateTime? ExpireDateStart { get; set; }public virtual DateTime? ExpireDateEnd { get; set; }/// <summary>/// 职务头衔/// </summary>public virtual string Title { get; set; }/// <summary>/// 身份证号码/// </summary>public virtual string IdentityCard { get; set; }/// <summary>/// 办公电话/// </summary>public virtual string OfficePhone { get; set; }/// <summary>/// 家庭电话/// </summary>public virtual string HomePhone { get; set; }/// <summary>/// 住址/// </summary>public virtual string Address { get; set; }/// <summary>/// 办公地址/// </summary>public virtual string WorkAddr { get; set; }/// <summary>/// 性别/// </summary>public virtual string Gender { get; set; }/// <summary>/// 出生日期/// </summary>public virtual DateTime? BirthdayStart { get; set; }public virtual DateTime? BirthdayEnd { get; set; }/// <summary>/// QQ号码/// </summary>public virtual string QQ { get; set; }/// <summary>/// 个性签名/// </summary>public virtual string Signature { get; set; }/// <summary>/// 审核状态/// </summary>public virtual string AuditStatus { get; set; }/// <summary>/// 备注/// </summary>public virtual string Note { get; set; }/// <summary>/// 自定义字段/// </summary>public virtual string CustomField { get; set; }/// <summary>/// 默认部门名称/// </summary>public virtual string DeptName { get; set; }/// <summary>/// 所属机构名称/// </summary>public virtual string CompanyName { get; set; }/// <summary>/// 排序码/// </summary>public virtual string SortCode { get; set; }/// <summary>/// 创建人/// </summary>public virtual string Creator { get; set; }/// <summary>/// 创建人ID/// </summary>public virtual string Creator_ID { get; set; }/// <summary>/// 创建时间/// </summary>public virtual DateTime? CreateTimeStart { get; set; }public virtual DateTime? CreateTimeEnd { get; set; }/// <summary>/// 编辑人/// </summary>public virtual string Editor { get; set; }/// <summary>/// 编辑人ID/// </summary>public virtual string Editor_ID { get; set; }/// <summary>/// 编辑时间/// </summary>public virtual DateTime? EditTimeStart { get; set; }public virtual DateTime? EditTimeEnd { get; set; }/// <summary>/// 是否已删除/// </summary>public virtual bool? Deleted { get; set; }/// <summary>/// 当前登录IP/// </summary>public virtual string CurrentLoginIP { get; set; }/// <summary>/// 当前登录时间/// </summary>public virtual DateTime CurrentLoginTime { get; set; }/// <summary>/// 当前Mac地址/// </summary>public virtual string CurrentMacAddress { get; set; }/// <summary>/// 微信绑定的OpenId/// </summary>public virtual string OpenId { get; set; }/// <summary>/// 微信多平台应用下的统一ID/// </summary>public virtual string UnionId { get; set; }/// <summary>/// 公众号状态/// </summary>public virtual string Status { get; set; }/// <summary>/// 公众号/// </summary>public virtual string SubscribeWechat { get; set; }/// <summary>/// 科室权限/// </summary>public virtual string DeptPermission { get; set; }/// <summary>/// 企业微信UserID/// </summary>public virtual string CorpUserId { get; set; }/// <summary>/// 企业微信状态/// </summary>public virtual string CorpStatus { get; set; }#endregion}

它的基类属性包括了MaxResultCount,SkipCount,Sorting等分页排序所需的信息。

另外还包含了对条件查询的属性信息,如果是数值的,布尔类型的,则是可空类型,日期则有起始条件的范围属性等等,也可以根据自己需要定义更多属性用户过滤条件。

如对于出生日期,我们定义一个区间范围来进行查询。

        /// <summary>/// 出生日期/// </summary>public virtual DateTime? BirthdayStart { get; set; }public virtual DateTime? BirthdayEnd { get; set; }

最后,我们根据需要进行判断,获得查询条件即可。

        /// <summary>/// 获取查询条件并转换为SQL/// </summary>/// <param name="input">查询条件</param>protected override string GetCondition(UserPagedDto input){//根据条件,构建SQL条件语句SearchCondition condition = new SearchCondition();if (!input.Role_ID.HasValue){condition.AddCondition("ID", input.ID, SqlOperator.Equal).AddCondition("IdentityCard", input.IdentityCard, SqlOperator.Equal).AddCondition("Name", input.Name, SqlOperator.Like).AddCondition("Note", input.Note, SqlOperator.Like).AddCondition("Email", input.Email, SqlOperator.Like).AddCondition("MobilePhone", input.MobilePhone, SqlOperator.Like).AddCondition("Address", input.Address, SqlOperator.Like).AddCondition("HandNo", input.HandNo, SqlOperator.Like).AddCondition("HomePhone", input.HomePhone, SqlOperator.Like).AddCondition("Nickname", input.Nickname, SqlOperator.Like).AddCondition("OfficePhone", input.OfficePhone, SqlOperator.Like).AddCondition("OpenId", input.OpenId, SqlOperator.Like).AddCondition("Password", input.Password, SqlOperator.Like).AddCondition("PID", input.PID, SqlOperator.Like).AddCondition("QQ", input.QQ, SqlOperator.Equal).AddCondition("DeptPermission", input.DeptPermission, SqlOperator.Like).AddCondition("AuditStatus", input.AuditStatus, SqlOperator.Equal).AddCondition("FullName", input.FullName, SqlOperator.Like).AddCondition("Gender", input.Gender, SqlOperator.Equal).AddCondition("CustomField", input.CustomField, SqlOperator.Like).AddCondition("IsExpire", input.IsExpire, SqlOperator.Equal).AddCondition("Signature", input.Signature, SqlOperator.Like).AddCondition("SortCode", input.SortCode, SqlOperator.Like).AddCondition("Status", input.Status, SqlOperator.Equal).AddCondition("CorpStatus", input.CorpStatus, SqlOperator.Equal).AddCondition("CorpUserId", input.CorpUserId, SqlOperator.Equal).AddCondition("UnionId", input.UnionId, SqlOperator.Equal).AddCondition("WorkAddr", input.WorkAddr, SqlOperator.Equal).AddCondition("SubscribeWechat", input.SubscribeWechat, SqlOperator.Equal).AddCondition("Title", input.Title, SqlOperator.Like).AddCondition("CurrentLoginIP", input.CurrentLoginIP, SqlOperator.Like).AddCondition("CurrentMacAddress", input.CurrentMacAddress, SqlOperator.Like).AddCondition("Dept_ID", input.Dept_ID, SqlOperator.Equal).AddCondition("DeptName", input.DeptName, SqlOperator.Like).AddCondition("CompanyName", input.CompanyName, SqlOperator.Like).AddCondition("Company_ID", input.Company_ID, SqlOperator.Equal).AddCondition("Editor_ID", input.Editor_ID, SqlOperator.Equal).AddCondition("Editor", input.Editor, SqlOperator.Equal).AddCondition("Creator_ID", input.Creator_ID, SqlOperator.Equal).AddCondition("Creator", input.Creator, SqlOperator.Equal).AddDateCondition("CreateTime", input.CreateTimeStart, input.CreateTimeEnd).AddDateCondition("EditTime", input.EditTimeStart, input.EditTimeEnd).AddDateCondition("ExpireDate", input.ExpireDateStart, input.ExpireDateEnd).AddDateCondition("Birthday", input.BirthdayStart, input.BirthdayEnd);}return condition.BuildConditionSql().Replace("Where", "");}

前面介绍到,我们BusinessController基类定义了常规的分页查询GetAll函数,如下所示。

        /// <summary>/// 分页获取记录/// </summary>/// <param name="input"></param>/// <returns></returns>
        [HttpGet]public virtual PagedResultDto<T> GetAll([FromUri] TGetAllInput input){var condition = GetCondition(input);var list = GetPagedData(condition, input);return list;}

其中 GetCondition 是由子类进行重写处理,生成具体的查询条件的。

由于这里的Sorting信息是一个字符串的排序信息,如 Name DESC或者Name ASC类似的信息,前者是字段名,后者是排序降序还是升序的标识,我们在业务里面,需要拆分一下进行组合条件,如下拆分。

            //分页查询条件string sortName = null; //排序字段bool isDesc = true;if (!string.IsNullOrEmpty(input.Sorting)){var sortInput = input as ISortedResultRequest;if (sortInput != null){if (!string.IsNullOrWhiteSpace(sortInput.Sorting)){List<string> strNames = sortInput.Sorting.ToDelimitedList<string>(" ");sortName = (strNames.Count > 0) ? strNames[0] : null;isDesc = sortInput.Sorting.IndexOf("desc", StringComparison.OrdinalIgnoreCase) > 0;}}}

这样我们或者SortName,以及是否降序的判断。

然后根据获得分页信息,并调用业务类的接口函数获取对应记录,构建为分页所需的JSON对象返回。

            //构建分页对象var pagerInfo = new PagerInfo() { CurrenetPageIndex = currentPage, PageSize = pageSize };if (!string.IsNullOrWhiteSpace(sortName)){list = baseBLL.FindWithPager(condition, pagerInfo, sortName, isDesc);}else{list = baseBLL.FindWithPager(condition, pagerInfo);}if (list != null){foreach (var item in list){ConvertDto(item);//对Dto部分内容进行转义
                }}//返回常用分页对象var result = new PagedResultDto<T> { TotalCount = totalCount, Items = list };return result;

其中 PagedResultDto 是一个标准的分页数据返回的对象,定义如下所示。

    [Serializable]public class PagedResultDto<T> : ListResultDto<T>, IPagedResult<T>{/// <summary>/// Total count of Items./// </summary>public int TotalCount { get; set; }
    [Serializable]public class ListResultDto<T> : IListResult<T>{/// <summary>/// List of items./// </summary>public IReadOnlyList<T> Items{get { return _items ?? (_items = new List<T>()); }set { _items = value; }}private IReadOnlyList<T> _items;

最后返回的结果集合类似如下所示:

展开单条记录明细如下所示。

这个对象使用了Camel样式的属性处理,所以返回的属性全部是Camel的格式。

    /// <summary>/// 统一处理Json的格式化信息/// </summary>public static class JsonFomatterHelper{/// <summary>/// 获取JSON的格式化信息/// </summary>/// <returns></returns>public static JsonMediaTypeFormatter GetFormatter(){var formatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;formatter.SerializerSettings = new JsonSerializerSettings{Formatting = Formatting.Indented,ContractResolver = new CamelCasePropertyNamesContractResolver(),DateFormatHandling = DateFormatHandling.IsoDateFormat,DateFormatString = "yyyy-MM-dd HH:mm:ss",};return formatter;}}

关于统一结果返回的封装处理,这里采用了WrapResultAttribute进行处理,详细可以参考我的随笔《利用过滤器Filter和特性Attribute实现对Web API返回结果的封装和统一异常处理》进行详细了解。

            // 重新封装回传格式actionExecutedContext.Response = new HttpResponseMessage(statusCode){Content = new ObjectContent<AjaxResponse>(new AjaxResponse(content), JsonFomatterHelper.GetFormatter())};

利用查询条件对象,在Asp.net Web API中实现对业务数据的分页查询处理相关推荐

  1. ASP.NET Web API中的Controller

    虽然通过Visual Studio向导在ASP.NET Web API项目中创建的 Controller类型默认派生与抽象类型ApiController,但是ASP.NET Web API框架本身只要 ...

  2. (四)Asp.net web api中的坑-【api的返回值】

    (四)Asp.net web api中的坑-[api的返回值] 原文:(四)Asp.net web api中的坑-[api的返回值] void无返回值 IHttpActionResult HttpRe ...

  3. ASP.NET Web API中的参数绑定总结

    ASP.NET Web API中的action参数类型可以分为简单类型和复杂类型. HttpResponseMessage Put(int id, Product item) id是int类型,是简单 ...

  4. 监控系统简介(二):使用 App Metrics 在 ASP.NET Web API 中记录指标

    回顾 在<监控系统简介:使用 Prometheus 与 Grafana>一文中,我们了解了什么是监控系统,Prometheus 这一监控工具及它提供的数据类型.PromQL 以及 Graf ...

  5. 【ASP.NET Web API教程】5.5 ASP.NET Web API中的HTTP Cookie

    5.5 HTTP Cookies in ASP.NET Web API 5.5 ASP.NET Web API中的HTTP Cookie 本文引自:http://www.asp.net/web-api ...

  6. ASP.NET Web API中实现版本

    一般来说,api 接口是提供给其他系统或是其他公司使用,不能随意频繁的变更.然而,需求和业务不断变化,接口和参数也会发生相应的变化.如果直接对原来的接口进行修改,势必会影响线其他系统的正常运行.这就必 ...

  7. ASP.NET Web API中实现版本的几种方式

    在ASP.NET Web API中,当我们的API发生改变,就涉及到版本问题了.如何实现API的版本呢? 1.通过路由设置版本 最简单的一种方式是通过路由设置,不同的路由,不同的版本,不同的contr ...

  8. 在ASP.NET Web API中返回错误的最佳实践

    本文翻译自:Best practice to return errors in ASP.NET Web API I have concerns on the way that we returns e ...

  9. 在ASP.NET Web API中使用OData的Action和Function

    本篇体验OData的Action和Function功能.上下文信息参考"ASP.NET Web API基于OData的增删改查,以及处理实体间关系".在本文之前,我存在的疑惑包括: ...

最新文章

  1. 又来搞事情了,这次女友让我研究如何实现一个文件系统
  2. 凸包Graham Scan算法实现
  3. 十四、爬取天气气温,制作最低气温排行榜
  4. 如何看Cortex-M系列处理器差异与共性?技术老司机Joseph带你飞
  5. lucene全文搜索之三:生成索引字段,创建索引文档(给索引字段加权)基于lucene5.5.3...
  6. c语言用递归法判断回文字符串,递归方式判断一个字符串是否为回文字符串
  7. 用Jackson进行Java JSON处理
  8. Spark性能调优-RDD算子调优篇
  9. oracle 添加登陆文件路径
  10. 最小化功能区:显露无遗
  11. Android -- TabHost
  12. python添加环境变量代码_Maya中的PYTHONPATH 环境变量
  13. MATLAB平台学习(9)信道模型
  14. DP入门系列-DP入门指导
  15. eNSP实验记录(一):路由器与交换机
  16. 论学习过程中“结构化”的思维必要作用
  17. 大学计算机专业英语期末考试,河南大学计算机专业英语试题
  18. js 获得明天0点时间戳_开群通知!昨日提示厦门信达、申通地铁、国林科技、隆盛科技全部涨停!明天这只龙头股有望继续涨停!...
  19. 华为鸿蒙系统建立生态链的环境,华为自研操作系统,怎么构建生态?感觉太难了?...
  20. Python PySpark 大数据时代

热门文章

  1. Android关于Sqlite的操作方法详细
  2. 持安零信任 | 改变攻防不对称的局面
  3. intel+漏洞+linux内核,彻彻底底的垃圾!Linux之父评Intel的CPU漏洞修复方法
  4. mag6000变送器怎么使用_哈尔滨信号隔离模块怎么选-泰华仪表
  5. 电商类web原型制作分享——美丽说【附源文件】
  6. [编程题]微信红包-TreeMap in Java
  7. lammps教程:推荐一个不同单位下压强自动转换网站
  8. 1+X云计算平台运维与开发认证(中级)样卷E-过程与答案
  9. 彩虹云秒赞首页模板 星辰美化
  10. c语言shape函数,几何特征系列:Shape Diameter Function(形状直径函数)