原文链接:https://www.cnblogs.com/landeanfen/p/5501487.html

正文

前言:已经有一个月没写点什么了,感觉心里空落落的。今天再来篇干货,想要学习Webapi的园友们速速动起来,跟着博主一起来学习吧。之前分享过一篇 C#进阶系列——WebApi接口传参不再困惑:传参详解 ,这篇博文内容本身很基础,没想到引起很多园友关注,感谢大家的支持。作为程序猿,我们都知道参数和返回值是编程领域不可分割的两大块,此前分享了下WebApi的传参机制,今天再来看看WebApi里面另一个重要而又基础的知识点:返回值。还是那句话:本篇针对初初使用WebApi的同学们,比较基础,有兴趣的且看看。

WebApi系列文章

  • C#进阶系列——WebApi接口测试工具:WebApiTestClient
  • C#进阶系列——WebApi 跨域问题解决方案:CORS
  • C#进阶系列——WebApi身份认证解决方案:Basic基础认证
  • C#进阶系列——WebApi接口传参不再困惑:传参详解
  • C#进阶系列——WebApi接口返回值不困惑:返回值类型详解
  • C#进阶系列——WebApi异常处理解决方案
  • C#进阶系列——WebApi区域Area使用小结

使用过Webapi的园友应该都知道,Webapi的接口返回值主要有四种类型

  • void无返回值
  • IHttpActionResult
  • HttpResponseMessage
  • 自定义类型

此篇就围绕这四块分别来看看它们的使用。

回到顶部

一、void无返回值

void关键字我们都不陌生,它申明方法没有返回值。它的使用也很简单,我们来看一个示例就能明白。

   public class ORDER{public string ID { get; set; }public string NO { get; set; }public string NAME { get; set; }public string DESC { get; set; }}

   public class OrderController : ApiController{[HttpPost]public void SaveOrder(ORDER name){ //处理业务逻辑}}

在Web里面调用

$(function () {$.ajax({type: 'post',url: 'http://localhost:21528/api/Order/SaveOrder',data: { ID: "aaa", NAME: "test" },success: function (data, status) {alert(data);}});
});

得到结果

可以看到,使用void申明的方法,在success方法里面得不到返回值,并且会返回http状态码204,告诉客户端此请求没有返回值。

回到顶部

二、IHttpActionResult

IHttpActionResult类型是WebApi里面非常重要的一种返回值类型。下面博主就根据平时在项目里面使用最多的几种方式来讲解下这种类型的返回值的一些用法。

回到顶部

1、Json<T>(T content)

使用MVC开发过的朋友一定记得,在MVC里面,请求数据的接口的返回值类型大部分使用的是JsonResult,在MVC里面你一定也写过类似这样的接口:

     public JsonResult GetResult(){return Json(new { }, JsonRequestBehavior.AllowGet);}

那么,在WebAPI里面是否也存在类似的用法呢。呵呵,在这点上面,微软总是贴心的。在WebApi的ApiController这个抽象类里面,为我们封装了Json<T>(T content)这个方法,它的用法和MVC里面的JsonResult基本类似。我们通过一个例子来说明它的用法:

     [HttpGet]public IHttpActionResult GetOrder(){var lstRes = new List<ORDER>(); //实际项目中,通过后台取到集合赋值给lstRes变量。这里只是测试。lstRes.Add(new ORDER() { ID = "aaaa", NO = "111", NAME = "111", DESC = "1111" });lstRes.Add(new ORDER() { ID = "bbbb", NO = "222", NAME = "222", DESC = "2222" });return Json<List<ORDER>>(lstRes);}

看到这个代码,有人就疑惑了,我们定义的返回值类型是IHttpActionResult类型,直接返回Json<T>(T content)这样可行么?我们将Json转到定义看看:

        protected internal JsonResult<T> Json<T>(T content); 

我们继续将JsonResult<T>转到定义

原来JsonResult<T>是实现了IHttpActionResult接口的,难怪可以直接返回呢。

知道了这个,我们直接在Web里面通过ajax请求来调用:

$(function () {$.ajax({type: 'get',url: 'http://localhost:21528/api/Order/GetOrder',data: {},success: function (data, status) {alert(data);}});
});

来看结果:

既然实体类可以直接这样传递,那么如果我们想要传递一些匿名类型呢,因为很多情况下,我们需要返回到前端的对象都没有对应的实体来对应,如果我们想要返回匿名对象怎么办呢?我们知道,这里的Json<T>(T content)必须要传一个对应的泛型类型,如果是匿名类型这里肯定不好传。还好有我们的object类型,当然你可以使用dynamic,我们来试一把。

        [HttpGet]public IHttpActionResult GetOrder(){return Json<dynamic>(new { AA = "", BB = "cc" });}

同样的来看测试结果:

回到顶部

2、Ok()、 Ok<T>(T content)

除了Json<T>(T content),在ApiController里面还有另外一个比较常用的方法:Ok()。同样,我们将Ok()转到定义

protected internal virtual OkResult Ok();

OkResult转到定义

有了这个作为基础,我们就可以放心大胆的使用了。

        [HttpGet]public IHttpActionResult GetOKResult(){return Ok();}

得到结果

如果返回Ok(),就表示不向客户端返回任何信息,只告诉客户端请求成功。

除了Ok()之外,还有另外一个重载Ok<T>(T content)。

        [HttpGet]public IHttpActionResult GetOKResult(string name){return Ok<string>(name);}

这种用法和Json<T>(T content)比较类似,如果你非要问这两者有什么区别,或者说怎么选择两者。那么我的理解是如果是返回实体或者实体集合,建议使用Json<T>(T content),如果是返回基础类型(如int、string等),使用Ok<T>(T content)。

回到顶部

3、NotFound()

当需要向客户端返回找不到记录时,有时需要用到NotFound()方法。

protected internal virtual NotFoundResult NotFound();

来看看它的使用场景

        [HttpGet]public IHttpActionResult GetNotFoundResult(string id){var lstRes = new List<ORDER>();//实际项目中,通过后台取到集合赋值给lstRes变量。这里只是测试。lstRes.Add(new ORDER() { ID = "aaaa", NO = "111", NAME = "111", DESC = "1111" });lstRes.Add(new ORDER() { ID = "bbbb", NO = "222", NAME = "222", DESC = "2222" });var oFind = lstRes.FirstOrDefault(x => x.ID == id) ;if (oFind == null){return NotFound();}else{return Json<ORDER>(oFind);}}

$(function () {$.ajax({type: 'get',url: 'http://localhost:21528/api/Order/GetNotFoundResult',data: { id :"cccc" },success: function (data, status) {alert(data);}});
});

得到结果

NotFound()方法会返回一个404的错误到客户端。

回到顶部

4、其他

其他还有一些方法,都有它特定的用途。在此贴出来。

4.1、Content<T>(HttpStatusCode statusCode, T value)

        [HttpGet]public IHttpActionResult GetContentResult(){return Content<string>(HttpStatusCode.OK, "OK");}

向客户端返回值和http状态码。

4.2、BadRequest()

        [HttpGet]public IHttpActionResult GetBadRequest(ORDER order){if (string.IsNullOrEmpty(order.ID))return BadRequest();return Ok();}

向客户端返回400的http错误。

4.3、Redirect(string location)

        [HttpGet]public IHttpActionResult RedirectResult(){return Redirect("http://localhost:21528/api/Order/GetContentResult");}

将请求重定向到其他地方。

回到顶部

5、自定义IHttpActionResult接口的实现

上面介绍了一些系统内置的常用的实现IHttpActionResult接口的方法。如果我们需要自定义IHttpActionResult的返回呢?

在介绍之前,我们有必要先来看看IHttpActionResult类型的定义,将IHttpActionResult转到定义可以看到:

namespace System.Web.Http
{// 摘要: //     Defines a command that asynchronously creates an System.Net.Http.HttpResponseMessage.public interface IHttpActionResult{// 摘要: //     Creates an System.Net.Http.HttpResponseMessage asynchronously.//// 参数: //   cancellationToken://     The token to monitor for cancellation requests.//// 返回结果: //     A task that, when completed, contains the System.Net.Http.HttpResponseMessage.Task<System.Net.Http.HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken);}
}

这个接口包含唯一的一个方法ExecuteAsync(),此方法将以异步方式创建一个HttpResponseMessage实例返回给客户端。

有了这个作为基础,下面,我们自定义一个bootstrapTable服务端分页的子类去展示自定义IHttpActionResult的用法。

首先,自定义一个实现类

   public class PageResult : IHttpActionResult{object _value;HttpRequestMessage _request;public PageResult(object value, HttpRequestMessage request){_value = value;_request = request;}public Task<HttpResponseMessage> ExecuteAsync(System.Threading.CancellationToken cancellationToken){var response = new HttpResponseMessage(){Content = new ObjectContent(typeof(object), _value, new JsonMediaTypeFormatter()),RequestMessage = _request};return Task.FromResult(response);}}

然后,在API接口里面返回PageResult对象

     [HttpGet]public IHttpActionResult GetPageRow(int limit, int offset){var lstRes = new List<ORDER>();//实际项目中,通过后台取到集合赋值给lstRes变量。这里只是测试。lstRes.Add(new ORDER() { ID = "aaaa", NO = "111", NAME = "111", DESC = "1111" });lstRes.Add(new ORDER() { ID = "bbbb", NO = "222", NAME = "222", DESC = "2222" });var oData = new { total = lstRes.Count, rows = lstRes.Skip(offset).Take(limit).ToList() };return new PageResult(oData, Request);}

最好,ajax调用

$(function () {$.ajax({type: 'get',url: 'http://localhost:21528/api/Order/GetPageRow',data: { limit:1,offset:1},success: function (data, status) {alert(data);}});
});

得到结果

回到顶部

三、HttpResponseMessage

在上文自定义IHttpActionResult返回类型的时候,提到过HttpResponseMessage这个对象。它表示向客户端返回一个http响应的消息对象(包含http状态码和需要返回客户端的消息)。这个对象也有它独特的使用场景:需要向客户端返回HttpResponse时就要用到这个对象。以导出为例,由于需要将导出的Excel文件输出到客户端浏览器,Webapi的服务端需要向Web的客户端输出文件流,这个时候一般的IHttpActionResult对象不方便解决这个问题,于是HttpReponseMessage派上了用场。我们来看看它的使用示例。

    public HttpResponseMessage Export(){//取数据var lstRes = OrderBLL.Export();//向Excel里面填充数据HSSFWorkbook workbook = new HSSFWorkbook();CreateAndFillSheet(workbook, lstRes);//保存到服务var fileName = "Excel" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xls";var strPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Data\" + fileName);using (FileStream fs = new FileStream(strPath, FileMode.Create)){workbook.Write(fs);using (MemoryStream ms = new MemoryStream()){workbook.Write(ms);}}//输出到浏览器try{var stream = new FileStream(strPath, FileMode.Open);HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);response.Content = new StreamContent(stream);response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"){FileName = fileName};return response;}catch{return new HttpResponseMessage(HttpStatusCode.NoContent);}}

将文件流保存在StreamContent对象里面,然后输出到浏览器。在浏览器端即可将Excel输出。

回到顶部

四、自定义类型

以上几种返回值类型能解决我们大部分返回值的问题,当然,你也可以将webapi的接口和普通方法一样,返回任意的类型,WebApi会自动序列化你自定义任何返回类型,然后将序列化的值写到响应正文里,状态码统一返回200。比如:

        [HttpGet]public object GetOther(){var lstRes = new List<ORDER>();//实际项目中,通过后台取到集合赋值给lstRes变量。这里只是测试。lstRes.Add(new ORDER() { ID = "aaaa", NO = "111", NAME = "111", DESC = "1111" });lstRes.Add(new ORDER() { ID = "bbbb", NO = "222", NAME = "222", DESC = "2222" });return lstRes;}

得到结果

和上面的Json、Ok等用法在效果上面没有太大区别。

回到顶部

五、总结

以上通过四个方面详细分享了下WebApi里面返回值的常见用法,不能说哪种方式最好,因为每种方式都有其特定的使用场景。博主觉得为了规范WebApi接口,对于一般接口的返回值,尽量使用IHttpActionResult类型作为返回值,毕竟是微软内置的东西,可能为我们考虑了很多我们考虑不到的东西。当然,你可能会觉得麻烦,你可能会说直接和普通方法一样来使用不是更爽,博主当初也有这种想法,可是学习微软的东西多了之后发现很多东西还是遵守一定的标准比较好,至少维护起来方便。这就像博主最近正在努力学习的WebApi+oData一样,为什么要搞这么一套标准性的东西,还不是为了更加方便地规范Restful风格。如果本文能帮到你,不妨推荐下,您的推荐是博主继续总结的动力!


欢迎大家关注我的微信号公众号,公众号名称:Bootstrap前端交流。扫下面的二维码或者收藏下面的二维码关注吧(长按下面的二维码图片、并选择识别图中的二维码)
分类: C#
标签: WebApi
好文要顶 关注我 收藏该文  

懒得安分
关注 - 22
粉丝 - 2862

+加关注

关注一下楼主吧
172
1

« 上一篇:JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(二)
» 下一篇:C#进阶系列——WebApi 路由机制剖析:你准备好了吗?

posted @ 2016-05-19 12:24 懒得安分 阅读(64607) 评论(60) 编辑 收藏

< Prev12
回复引用

#51楼 2017-11-22 15:59 okjulien

如果是匿名类型这里肯定不好传。还好有我们的object类型
--我也正需要这个。
支持(0)反对(1)

回复引用

#52楼 2017-11-30 17:26 okjulien

楼主下面这句话讲错了:

如果你非要问这两者有什么区别,或者说怎么选择两者。那么我的理解是如果是返回实体或者实体集合,建议使用Json<T>(T content),如果是返回基础类型(如int、string等),使用Ok<T>(T content)。

支持(0)反对(0)

回复引用

#53楼 2017-12-05 19:38 兴趣就是天赋

点赞 不错
支持(0)反对(0)

回复引用

#54楼 2017-12-22 14:43 hidekk

讲些挺好的,学习到了 楼主辛苦
支持(0)反对(0)

回复引用

#55楼 2018-01-04 17:14 ahdung

@ okjulien
类型推断你跟博主都不知道吗,直接Json(new {xx})就行,根本不用填T
支持(0)反对(0)

回复引用

#56楼 2018-01-16 08:40 孤心自泪

支持(0)反对(0)

回复引用

#57楼[楼主] 2018-03-01 11:33 懒得安分

@ ahdung
引用@okjulien
类型推断你跟博主都不知道吗,直接Json(new {xx})就行,根本不用填T
今天正好在整理api的接口规范。看到你的这条留言,说说我的看法。
确实,Json()方法确实可以不用T。但是否需要类型推断,是否可以不用填T,我觉得需要分情况对待,不能一概而论。我的看法是:
(1)如果返回的强类型,比如普通的class对象,集合对象等等。这里的T最好是写上。这样的好处至少有两点:一是一目了然,别人看代码就知道这个方法的返回值的类型;二是可以提高序列化的效率,在序列化的时候不用再走一遍类型推断的过程;
(2)如果是object或者匿名类型,这里的T可以填,也可以不填。为了代码规范统一,填上我觉得也无伤大雅;不填也行,至少可以少写一点代码吧。取决于实际项目的规范。
支持(0)反对(0)

回复引用

#58楼 2018-06-15 17:47 轩辕七

@ 懒得安分
楼主是对的,如果遇到值类型 如果不填写T 会发生装箱的,
支持(0)反对(0)

回复引用

#59楼 2018-07-12 16:34 .乌鸦

你这适合当教材 不适合实际的情景
支持(0)反对(0)

回复引用

#60楼 2019-01-22 15:46 lanboss

mark web api
支持(0)反对(0)

< Prev12

发表评论

昵称:

评论内容:
     

退出 订阅评论

[Ctrl+Enter快捷键提交]

【推荐】超50万VC++源码: 大型组态工控、电力仿真CAD与GIS源码库!
【推荐】基于 HTML5 的 WebGL 楼宇自控 3D 可视化监控

相关博文:
· WebApi接口返回值不困惑:返回值类型详解
· WebApi 接口返回值不困惑:返回值类型详解。IHttpActionResult、void、HttpResponseMessage、自定义类型
· json接口返回值
· WebApi 接口返回值类型详解 ( 转 )
· C#接口-接口作为返回值

最新新闻
· 彭博:猫眼娱乐IPO定价在14.80港元 位于招股区间低端
· 亚马逊人脸识别技术Rekognition被爆种族歧视
· 手机触屏竟成混合现实?苹果指戴式设备拿下专利
· 格力投资50亿做洗衣机,为何没能引发高度关注
· 李彦宏眼中没有用户,百度成信息流平台
» 更多新闻...

喜欢请打赏

  • 支付宝
  • 微信

扫描二维码打赏

了解更多

转载于:https://www.cnblogs.com/wangdongying/p/10329988.html

(转)C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解相关推荐

  1. C#进阶系列——WebApi 接口参数不再困惑:传参详解

    看这边文章时的疑惑是:WebApi中的参数加了[FromBody],不知所以然,就百度了下,看到了以下文章,和大家分享下: 原文链接:http://www.cnblogs.com/landeanfen ...

  2. 【转】C#进阶系列——WebApi 接口参数不再困惑:传参详解

    阅读目录 一.get请求 1.基础类型参数 2.实体作为参数 3.数组作为参数 4."怪异"的get请求 二.post请求 1.基础类型参数 2.实体作为参数 3.数组作为参数 4 ...

  3. sC#进阶系列——WebApi 接口参数不再困惑:传参详解

    原文:http://www.cnblogs.com/landeanfen/p/5337072.html 一.get请求 对于取数据,我们使用最多的应该就是get请求了吧.下面通过几个示例看看我们的ge ...

  4. WebApi接口传参不再困惑:传参详解

    一.get请求 对于取数据,我们使用最多的应该就是get请求了吧.下面通过几个示例看看我们的get请求参数传递. 1.基础类型参数 [HttpGet] public string GetAllChar ...

  5. C#进阶系列——WebApi 身份认证解决方案:Basic基础认证

    阅读目录 一.为什么需要身份认证 二.Basic基础认证的原理解析 1.常见的认证方式 2.Basic基础认证原理 三.Basic基础认证的代码示例 1.登录过程 2./Home/Index主界面 3 ...

  6. C#进阶系列——WebApi 接口测试工具:WebApiTestClient

    正文 前言:这两天在整WebApi的服务,由于调用方是Android客户端,Android开发人员也不懂C#语法,API里面的接口也不能直接给他们看,没办法,只有整个详细一点的文档呗.由于接口个数有点 ...

  7. C#进阶系列——WebApi 异常处理解决方案

    原文:C#进阶系列--WebApi 异常处理解决方案 前言:上篇C#进阶系列--WebApi接口传参不再困惑:传参详解介绍了WebApi参数的传递,这篇来看看WebApi里面异常的处理.关于异常处理, ...

  8. WebApi 接口参数不再困惑:传参详解

    阅读目录 一.get请求 1.基础类型参数 2.实体作为参数 3.数组作为参数 4."怪异"的get请求 二.post请求 1.基础类型参数 2.实体作为参数 3.数组作为参数 4 ...

  9. C#进阶系列——WebApi 跨域问题解决方案:CORS

    C#进阶系列--WebApi 跨域问题解决方案:CORS 参考文章: (1)C#进阶系列--WebApi 跨域问题解决方案:CORS (2)https://www.cnblogs.com/landea ...

最新文章

  1. SlickGrid控件最后一行触数据更新条件
  2. c语言有重复元素全排列,【求助】全排列 不重复 由小到大 输出 代码
  3. GitHub趋势榜第一:超强PyTorch目标检测库Detectron2,训练更快,支持更多任务
  4. 创建Vue实例传入的options||Vue的生命周期
  5. MyBatis-20MyBatis高级结果映射【一对一映射(4种方式)】
  6. Ribbon的初始化源码
  7. mysql主从-读写分离
  8. 描述文件安装失败无法连接到服务器_打开steam为什么提示无法连接至steam网络?...
  9. matlab-lsqcurvefit函数 初始值选取
  10. 自动化所宗成庆研究员:108页PPT干货读懂NLP的过去与现在!(附教材PPT)
  11. 论文翻译:2021_Performance optimizations on deep noise suppression models
  12. 联邦学习(Federated Learning)
  13. navicat连接数据库出错,但是SQLyog可以正常连接
  14. 六一小学生计算机创新活动总结,小学科技创新活动总结4篇
  15. Android高手笔记-D8, R8编译优化
  16. 【知识点总结】【CSP考前复习】图论大杂烩【未完】
  17. MATLAB学习0基础
  18. 商业模式新生代_精读商业模式新生代之“多边平台式商业模式”
  19. 移动App下载量SEO优化
  20. 整车下线流程(EOL)测试解决方案介绍

热门文章

  1. 瘟神的尾行 -- Rootkit技术发展史 (转载)
  2. 常见测试工具总结:LR、Selenium
  3. Mac上安装R语言运行环境及RStudio [超详细!~]
  4. 解方程(二分法) HDU
  5. 计算机认识新朋友教案,认识新朋友教案
  6. css字体样式渐变导致360浏览器vue兼容性问题
  7. Android之获取外部存储空间解释
  8. 程序员裸辞三个月,终于拿到大厂offer!网友:不应该!
  9. 极路由4增强版编译aria2-1.34
  10. System.IO.FileNotFoundException: Could not load file or assembly ‘xx.dll‘ or one of its dependencies