本文是本人翻译自官方资料,如果翻译的不好请指正。
本文介绍WebApi2如何将action中的结果返回至Http输出中。
一个WebApi Controller可以返回以下任意一种类型:
1.void
2.HttpReponseMessage
3.IHttpActionResult
4.其他类型
依据不同返回类型,WebApi会选择不同的机制来创建Http Reponse
Return type | How Web API creates the response |
void | Return empty 204 (No Content) 返回无内容 |
HttpResponseMessage | Convert directly to an HTTP response message. 直接转换为一个Http Reponse消息。 |
IHttpActionResult | Call ExecuteAsync to create an HttpResponseMessage, then convert to an HTTP response message. 调用ExecuteAsync先创建一个HttpReponseMessage,在转换为Http Reponse输出。 |
Other type | Write the serialized return value into the response body; return 200 (OK). 序列化后的信息返回到消息体中。 |
例子:
1.void
WebApi会简单的返回空消息,状态码为204
public class ValuesController :ApiController
{
public void Post()
{
}
}
HTTP返回:
HTTP/1.1 204 NoContent
Server: Microsoft-IIS/8.0
Date: Mon, 27 Jan 2014 02:13:26 GMT
2.HttpResponseMessage
WepApi会直接将值写入到Http响应中去。你可以使用一些选项在输出之前对http响应做一些控制,例如,可以控制Cache-Control头。
public class ValuesController :ApiController
{
public HttpResponseMessageGet()
{
HttpResponseMessage response =Request.CreateResponse(HttpStatusCode.OK,"value");
response.Content =new StringContent("hello",Encoding.Unicode);
response.Headers.CacheControl =new CacheControlHeaderValue()
{
MaxAge =TimeSpan.FromMinutes(20)
};
returnresponse;
}
}
Response:
HTTP/1.1200 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
如果你将一个领域模型对象传递给CreateReponse方法,WebApi会自动调用media formatter将模型序列化后写入到Http响应中。
public HttpResponseMessage Get()
{
// Get a list of products from adatabase.
IEnumerable<Product>products =GetProductsFromDB();
// Writethe list to the response body.
HttpResponseMessageresponse =Request.CreateResponse(HttpStatusCode.OK, products);
return response;
}
WebApi根据Http请求中的Accept头来选择具体使用哪个序列化器,更多信息参见 Content Negotiation.
3.IHttpActionResult
该接口本质上,定义了一个HttpReponseMessage工厂,使用IHttpActionResult有一些优势如下:
- 简化Controller的单元测试 unit testing
- 将创建Http响应的通用逻辑移动到单独的类中(Moves common logic for creating HTTP responses into separate classes)
- 通过隐藏创建响应的底层代码,使Controller、aciton的变得更清晰。
该接口定义了一个方法ExecuteAsync,用来创建HttpReponseMessage实例
public interface IHttpActionResult
{
Task<HttpResponseMessage>ExecuteAsync(CancellationToken cancellationToken);
}
所以,当Action返回一个IHttpActionResult接口的时候,WebApi会调用ExecuteAsync方法生成HttpReponseMessage实例,然后HttpReponseMessage实例会将信息写入到Http响应中返回给用户。
下面是一个简单的继承IHttpActionResult接口,返回给客户端一个文本信息的例子:
继承:
public class TextResult :IHttpActionResult
{
string_value;
HttpRequestMessage _request;
public TextResult(string value, HttpRequestMessage request)
{
_value = value;
_request = request;
}
public Task<HttpResponseMessage>ExecuteAsync(CancellationToken cancellationToken)
{
var response =new HttpResponseMessage()
{
Content =new StringContent(_value),
RequestMessage = _request
};
return Task.FromResult(response);
}
}
Controller:
public class ValuesController :ApiController
{
public IHttpActionResultGet()
{
return new TextResult("hello",Request);
}
}
Response:
HTTP/1.1 200OK
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实现类。并且ApiController的一些内建辅助类可以返回这些实现类。
在下面的例子中,如果没有找到对应的产品ID,则会调用ApiController.NotFound返回一个404的IHttpActionResult的实例。否则的话,调用ApiController.OK返回一个包含产品信息的200状态的结果。
public IHttpActionResult Get (int id)
{
Productproduct = _repository.Get (id);
if(product ==null)
{
return NotFound();// Returns a NotFoundResult
}
return Ok(product); // Returns an OkNegotiatedContentResult
}
4.Other Return Types其他返回类型
对于其他返回类型,WepApi会调用media formatter来序列化对象,还记得前面讲的吗,WebApi会根据请求中ACCEPT头来自动选择formatter(Content Negotiation)。然后将序列化结果写入到响应信息中。
public class ProductsController :ApiController
{
public IEnumerable<Product>Get()
{
return GetAllProductsFromDB();//将会序列化
}
}
注意:因为返回的是自定义类型,所以你不能直接指定返回错误状态404等,但是你可以通过抛出HttpResponseException 异常来指定错误代码,更多信息请看
Exception Handling in ASP.NETWeb API.
请求信息:
GET http://localhost/api/products HTTP/1.1
User-Agent: Fiddler
Host: localhost:24127
Accept: application/json
相应信息:
HTTP/1.1200 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}]