1.2Web API 2中的Action返回值
本主题描述 ASP.NET Web API 将返回值转换从一个控制器动作到 HTTP 响应消息。
一个 Web API 控制器动作可以返回下列任一操作 ︰
1.void
2.IHttpActionResult
3.HttpResponseMessage
4.一些其他类型
根据每种返回,Web API 使用一个不同的机制来创建 HTTP 响应。
返回类型 | Web API 如何创建响应 |
void | 返回空 204 (无内容) |
HttpResponseMessage | 直接将 HTTP 响应消息转换。 |
IHttpActionResult | 调用ExecuteAsync来创建HttpResponseMessage,然后转换到 HTTP 响应消息。 |
其他类型 | 序列化返回值写入响应正文;返回 200 (OK)。 |
一、Void
如果返回类型为void
,Web API 只是返回空的 HTTP 响应状态代码 204 (没有内容)。
示例控制器 ︰
1 public class ValuesController : ApiController 2 { 3 public void Post() 4 { 5 } 6 }
响应报文:
TTP/1.1 204 No Content Server: Microsoft-IIS/8.0 Date: Mon, 27 Jan 2014 02:13:26 GMT
二、HttpResponseMessage
如果该操作返回HttpResponseMessage,Web API 的返回值直接将转换为 HTTP 响应消息,使用HttpResponseMessage对象的属性来填充响应。
此选项使您大量的响应消息的控制权。例如,以下的控制器操作设置缓存控制标头。
1 public class ValuesController : ApiController 2 { 3 public HttpResponseMessage Get() 4 { 5 HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, "value"); 6 response.Content = new StringContent("hello", Encoding.Unicode); 7 response.Headers.CacheControl = new CacheControlHeaderValue() 8 { 9 MaxAge = TimeSpan.FromMinutes(20) 10 }; 11 return response; 12 } 13 }
响应报文:
HTTP/1.1 200 OK Cache-Control: max-age=1200 Content-Length: 10 Content-Type: text/plain; charset=utf-16 Server: Microsoft-IIS/8.0 Date: Mon, 27 Jan 2014 08:53:35 GMT
hello
如果你将一个域模型传递给CreateResponse方法,Web API 使用媒体格式化程序来序列化的模型写入响应正文。
1 public HttpResponseMessage Get() 2 { 3 // Get a list of products from a database. 4 IEnumerable<Product> products = GetProductsFromDB(); 5 6 // Write the list to the response body. 7 HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, products); 8 return response; 9 }
Web API 使用 Accept 标头在请求中选择格式化程序。
三、IHttpActionResult
IHttpActionResult接口是WebApi2才采用的。本质上,它定义了HttpResponseMessage工厂。下面是使用IHttpActionResult接口的一些优点 ︰
- 简化了单元测试您的控制器。
- 移动普通逻辑到单独的类创建 HTTP 响应。
- 使控制器动作更清晰,意图通过隐藏构建响应的低层细节。
IHttpActionResult包含一个单一的方法, ExecuteAsync,其中以异步方式创建一个HttpResponseMessage实例。
1 public interface IHttpActionResult 2 { 3 Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken); 4 }
如果一个控制器动作返回IHttpActionResult,Web API 调用ExecuteAsync方法来创建HttpResponseMessage。然后它将HttpResponseMessage转换成 HTTP 响应消息。
这里是IHttpActionResult ,创建纯文本响应简单实施 ︰
1 public class TextResult : IHttpActionResult 2 { 3 string _value; 4 HttpRequestMessage _request; 5 6 public TextResult(string value, HttpRequestMessage request) 7 { 8 _value = value; 9 _request = request; 10 } 11 public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) 12 { 13 var response = new HttpResponseMessage() 14 { 15 Content = new StringContent(_value), 16 RequestMessage = _request 17 }; 18 return Task.FromResult(response); 19 } 20 }
示例控制器中的操作 ︰
1 public class ValuesController : ApiController 2 { 3 public IHttpActionResult Get() 4 { 5 return new TextResult("hello", Request); 6 } 7 }
响应报文:
HTTP/1.1 200 OK Content-Length: 5 Content-Type: text/plain; charset=utf-8 Server: Microsoft-IIS/8.0 Date: Mon, 27 Jan 2014 08:53:35 GMT hello
更多时候,您将使用System.Web.Http.Results命名空间中定义的IHttpActionResult实现。ApiContoller类定义返回这些内置操作结果的帮助器方法。
在以下示例中,如果请求不匹配现有的产品 ID,控制器调用ApiController.NotFound来创建 404 (未找到) 响应。否则,控制器调用ApiController.OK,这将创建包含产品 200 (OK) 响应。
1 public IHttpActionResult Get (int id) 2 { 3 Product product = _repository.Get (id); 4 if (product == null) 5 { 6 return NotFound(); // Returns a NotFoundResult 7 } 8 return Ok(product); // Returns an OkNegotiatedContentResult 9 }
四、其他返回类型
对于所有其他返回类型,Web API 使用一个media formatter来序列化返回值。Web API 将序列化的值写入到响应正文。响应状态代码是 200 (OK)。
1 public class ProductsController : ApiController 2 { 3 public IEnumerable<Product> Get() 4 { 5 return GetAllProductsFromDB(); 6 } 7 }
这种方法的一个缺点是你不能直接返回错误代码,例如 404。然而,你可以抛出错误代码为HttpResponseException 。有关详细信息,请参见异常处理在 ASP.NET Web API.
Web API 使用 Accept 标头在请求中选择格式化程序。
请求报文:
GET http://localhost/api/products HTTP/1.1 User-Agent: Fiddler Host: localhost:24127 Accept: application/json
响应报文:
HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Server: Microsoft-IIS/8.0 Date: Mon, 27 Jan 2014 08:53:35 GMT Content-Length: 56 [{"Id":1,"Name":"Yo-yo","Category":"Toys","Price":6.95}]