C# WebApi 接口返回值不困惑:返回值類型詳解
前言:已經(jīng)有一個(gè)月沒寫點(diǎn)什么了,感覺心里空落落的。今天再來篇干貨,想要學(xué)習(xí)Webapi的園友們速速動(dòng)起來,跟著博主一起來學(xué)習(xí)吧。之前分享過一篇C#進(jìn)階系列——WebApi接口傳參不再困惑:傳參詳解,這篇博文內(nèi)容本身很基礎(chǔ),沒想到引起很多園友關(guān)注,感謝大家的支持。作為程序猿,我們都知道參數(shù)和返回值是編程領(lǐng)域不可分割的兩大塊,此前分享了下WebApi的傳參機(jī)制,今天再來看看WebApi里面另一個(gè)重要而又基礎(chǔ)的知識(shí)點(diǎn):返回值。還是那句話:本篇針對(duì)初初使用WebApi的同學(xué)們,比較基礎(chǔ),有興趣的且看看。
使用過Webapi的園友應(yīng)該都知道,Webapi的接口返回值主要有四種類型
- void無返回值
- IHttpActionResult
- HttpResponseMessage
- 自定義類型
此篇就圍繞這四塊分別來看看它們的使用。
一、void無返回值
void關(guān)鍵字我們都不陌生,它申明方法沒有返回值。它的使用也很簡(jiǎn)單,我們來看一個(gè)示例就能明白。
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)
{
//處理業(yè)務(wù)邏輯
}
}
在Web里面調(diào)用
$(function () {
$.ajax({
type: 'post',
url: 'http://localhost:21528/api/Order/SaveOrder',
data: { ID: "aaa", NAME: "test" },
success: function (data, status) {
alert(data);
}
});
});
得到結(jié)果
可以看到,使用void申明的方法,在success方法里面得不到返回值,并且會(huì)返回http狀態(tài)碼204,告訴客戶端此請(qǐng)求沒有返回值。
二、IHttpActionResult
IHttpActionResult類型是WebApi里面非常重要的一種返回值類型。下面博主就根據(jù)平時(shí)在項(xiàng)目里面使用最多的幾種方式來講解下這種類型的返回值的一些用法。
1、Json<T>(T content)
使用MVC開發(fā)過的朋友一定記得,在MVC里面,請(qǐng)求數(shù)據(jù)的接口的返回值類型大部分使用的是JsonResult,在MVC里面你一定也寫過類似這樣的接口:
public JsonResult GetResult()
{
return Json(new { }, JsonRequestBehavior.AllowGet);
}
那么,在WebAPI里面是否也存在類似的用法呢。呵呵,在這點(diǎn)上面,微軟總是貼心的。在WebApi的ApiController這個(gè)抽象類里面,為我們封裝了Json<T>(T content)這個(gè)方法,它的用法和MVC里面的JsonResult基本類似。我們通過一個(gè)例子來說明它的用法:
[HttpGet]
public IHttpActionResult GetOrder()
{
var lstRes = new List<ORDER>();
//實(shí)際項(xiàng)目中,通過后臺(tái)取到集合賦值給lstRes變量。這里只是測(cè)試。
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);
}
看到這個(gè)代碼,有人就疑惑了,我們定義的返回值類型是IHttpActionResult類型,直接返回Json<T>(T content)這樣可行么?我們將Json轉(zhuǎn)到定義看看:
protected internal JsonResult<T> Json<T>(T content);
我們繼續(xù)將JsonResult<T>轉(zhuǎn)到定義
原來JsonResult<T>是實(shí)現(xiàn)了IHttpActionResult接口的,難怪可以直接返回呢。
知道了這個(gè),我們直接在Web里面通過ajax請(qǐng)求來調(diào)用:
$(function () {
$.ajax({
type: 'get',
url: 'http://localhost:21528/api/Order/GetOrder',
data: {},
success: function (data, status) {
alert(data);
}
});
});
來看結(jié)果:
既然實(shí)體類可以直接這樣傳遞,那么如果我們想要傳遞一些匿名類型呢,因?yàn)楹芏嗲闆r下,我們需要返回到前端的對(duì)象都沒有對(duì)應(yīng)的實(shí)體來對(duì)應(yīng),如果我們想要返回匿名對(duì)象怎么辦呢?我們知道,這里的Json<T>(T content)必須要傳一個(gè)對(duì)應(yīng)的泛型類型,如果是匿名類型這里肯定不好傳。還好有我們的object類型,當(dāng)然你可以使用dynamic,我們來試一把。
[HttpGet]
public IHttpActionResult GetOrder()
{
return Json<dynamic>(new { AA = "", BB = "cc" });
}
同樣的來看測(cè)試結(jié)果:
2、Ok()、Ok<T>(T content)
除了Json<T>(T content),在ApiController里面還有另外一個(gè)比較常用的方法:Ok()。同樣,我們將Ok()轉(zhuǎn)到定義
protected internal virtual OkResult Ok();
OkResult轉(zhuǎn)到定義
有了這個(gè)作為基礎(chǔ),我們就可以放心大膽的使用了。
[HttpGet]
public IHttpActionResult GetOKResult()
{
return Ok();
}
得到結(jié)果
如果返回Ok(),就表示不向客戶端返回任何信息,只告訴客戶端請(qǐng)求成功。
除了Ok()之外,還有另外一個(gè)重載Ok<T>(T content)。
[HttpGet]
public IHttpActionResult GetOKResult(string name)
{
return Ok<string>(name);
}
這種用法和Json<T>(T content)比較類似,如果你非要問這兩者有什么區(qū)別,或者說怎么選擇兩者。那么我的理解是如果是返回實(shí)體或者實(shí)體集合,建議使用Json<T>(T content),如果是返回基礎(chǔ)類型(如int、string等),使用Ok<T>(T content)。
3、NotFound()
當(dāng)需要向客戶端返回找不到記錄時(shí),有時(shí)需要用到NotFound()方法。
protected internal virtual NotFoundResult NotFound();
來看看它的使用場(chǎng)景
[HttpGet]
public IHttpActionResult GetNotFoundResult(string id)
{
var lstRes = new List<ORDER>();
//實(shí)際項(xiàng)目中,通過后臺(tái)取到集合賦值給lstRes變量。這里只是測(cè)試。
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);
}
}
得到結(jié)果
NotFound()方法會(huì)返回一個(gè)404的錯(cuò)誤到客戶端。
4、其他
其他還有一些方法,都有它特定的用途。在此貼出來。
4.1、Content<T>(HttpStatusCode statusCode, T value)
[HttpGet]
public IHttpActionResult GetContentResult()
{
return Content<string>(HttpStatusCode.OK, "OK");
}
向客戶端返回值和http狀態(tài)碼。
4.2、BadRequest()
[HttpGet]
public IHttpActionResult GetBadRequest(ORDER order)
{
if (string.IsNullOrEmpty(order.ID))
return BadRequest();
return Ok();
}
向客戶端返回400的http錯(cuò)誤。
4.3、Redirect(string location)
[HttpGet]
public IHttpActionResult RedirectResult()
{
return Redirect("http://localhost:21528/api/Order/GetContentResult");
}
將請(qǐng)求重定向到其他地方。
5、自定義IHttpActionResult接口的實(shí)現(xiàn)
上面介紹了一些系統(tǒng)內(nèi)置的常用的實(shí)現(xiàn)IHttpActionResult接口的方法。如果我們需要自定義IHttpActionResult的返回呢?
在介紹之前,我們有必要先來看看IHttpActionResult類型的定義,將IHttpActionResult轉(zhuǎn)到定義可以看到:
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.
//
// 參數(shù):
// cancellationToken:
// The token to monitor for cancellation requests.
//
// 返回結(jié)果:
// A task that, when completed, contains the System.Net.Http.HttpResponseMessage.
Task<System.Net.Http.HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken);
}
}
這個(gè)接口包含唯一的一個(gè)方法ExecuteAsync(),此方法將以異步方式創(chuàng)建一個(gè)HttpResponseMessage實(shí)例返回給客戶端。
有了這個(gè)作為基礎(chǔ),下面,我們自定義一個(gè)bootstrapTable服務(wù)端分頁(yè)的子類去展示自定義IHttpActionResult的用法。
首先,自定義一個(gè)實(shí)現(xiàn)類
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對(duì)象
[HttpGet]
public IHttpActionResult GetPageRow(int limit, int offset)
{
var lstRes = new List<ORDER>();
//實(shí)際項(xiàng)目中,通過后臺(tái)取到集合賦值給lstRes變量。這里只是測(cè)試。
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調(diào)用
$(function () {
$.ajax({
type: 'get',
url: 'http://localhost:21528/api/Order/GetPageRow',
data: { limit:1,offset:1},
success: function (data, status) {
alert(data);
}
});
});
得到結(jié)果
三、HttpResponseMessage
在上文自定義IHttpActionResult返回類型的時(shí)候,提到過HttpResponseMessage這個(gè)對(duì)象。它表示向客戶端返回一個(gè)http響應(yīng)的消息對(duì)象(包含http狀態(tài)碼和需要返回客戶端的消息)。這個(gè)對(duì)象也有它獨(dú)特的使用場(chǎng)景:需要向客戶端返回HttpResponse時(shí)就要用到這個(gè)對(duì)象。以導(dǎo)出為例,由于需要將導(dǎo)出的Excel文件輸出到客戶端瀏覽器,Webapi的服務(wù)端需要向Web的客戶端輸出文件流,這個(gè)時(shí)候一般的IHttpActionResult對(duì)象不方便解決這個(gè)問題,于是HttpReponseMessage派上了用場(chǎng)。我們來看看它的使用示例。
public HttpResponseMessage Export()
{
//取數(shù)據(jù)
var lstRes = OrderBLL.Export();
//向Excel里面填充數(shù)據(jù)
HSSFWorkbook workbook = new HSSFWorkbook();
CreateAndFillSheet(workbook, lstRes);
//保存到服務(wù)
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對(duì)象里面,然后輸出到瀏覽器。在瀏覽器端即可將Excel輸出。
四、自定義類型
以上幾種返回值類型能解決我們大部分返回值的問題,當(dāng)然,你也可以將webapi的接口和普通方法一樣,返回任意的類型,WebApi會(huì)自動(dòng)序列化你自定義任何返回類型,然后將序列化的值寫到響應(yīng)正文里,狀態(tài)碼統(tǒng)一返回200。比如:
[HttpGet]
public object GetOther()
{
var lstRes = new List<ORDER>();
//實(shí)際項(xiàng)目中,通過后臺(tái)取到集合賦值給lstRes變量。這里只是測(cè)試。
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;
}
得到結(jié)果
和上面的Json、Ok等用法在效果上面沒有太大區(qū)別。
五、總結(jié)
以上通過四個(gè)方面詳細(xì)分享了下WebApi里面返回值的常見用法,不能說哪種方式最好,因?yàn)槊糠N方式都有其特定的使用場(chǎng)景。博主覺得為了規(guī)范WebApi接口,對(duì)于一般接口的返回值,盡量使用IHttpActionResult類型作為返回值,畢竟是微軟內(nèi)置的東西,可能為我們考慮了很多我們考慮不到的東西。當(dāng)然,你可能會(huì)覺得麻煩,你可能會(huì)說直接和普通方法一樣來使用不是更爽,博主當(dāng)初也有這種想法,可是學(xué)習(xí)微軟的東西多了之后發(fā)現(xiàn)很多東西還是遵守一定的標(biāo)準(zhǔn)比較好,至少維護(hù)起來方便。這就像博主最近正在努力學(xué)習(xí)的WebApi+oData一樣,為什么要搞這么一套標(biāo)準(zhǔn)性的東西,還不是為了更加方便地規(guī)范Restful風(fēng)格。也希望大家多多支持我們。
上一篇:C# 嵌入dll 的方法
欄 目:C#教程
下一篇:C# 使用相同權(quán)限調(diào)用 cmd 傳入命令的方法
本文標(biāo)題:C# WebApi 接口返回值不困惑:返回值類型詳解
本文地址:http://www.jygsgssxh.com/a1/C_jiaocheng/5141.html
您可能感興趣的文章
- 01-10C#接口實(shí)現(xiàn)方法實(shí)例分析
- 01-10使用C#代碼獲取存儲(chǔ)過程返回值
- 01-10日常收集C#接口知識(shí)(知識(shí)全面)
- 01-10詳解C#中的接口屬性以及屬性訪問器的訪問限制
- 01-10結(jié)合.net框架在C#派生類中觸發(fā)基類事件及實(shí)現(xiàn)接口事件
- 01-10深入解析C#中的泛型類與泛型接口
- 01-10基于C#實(shí)現(xiàn)手機(jī)號(hào)碼歸屬地接口調(diào)用
- 01-10C#隱式/顯示實(shí)現(xiàn)接口方法詳解
- 01-10C#進(jìn)階系列 WebApi身份認(rèn)證解決方案推薦:Basic基礎(chǔ)認(rèn)證
- 01-10C#微信公眾平臺(tái)開發(fā)之高級(jí)群發(fā)接口


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁(yè)無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻播放器左下角滾動(dòng)新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10delphi制作wav文件的方法
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 04-02jquery與jsp,用jquery
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子


