众所周知,ASP.NET MVC 通过Action接收用户请求,返回的是ActionResult.ActionResult包含很多种类,这里我搜集了一些常见类型的ActionResult及其相关的描述,见下表格,这里需要指出的是ActionResult也是有类的继承体系的,并不是单一的类,稍后会给出ActionResult的继承体系图。
如上所述,众多ActionResult的类型能够根据请求选择合适的返回类型。对于传统的ASP.NET,请求的是物理文件,根据文件后缀去选择相应的HttpHandler进行处理,HttpHandler对于开发者来说相对比较封闭,如果要对请求做额外的处理,需要重写某些方法。现在使用MVC,Action根据请求灵活选择返回的内容和方式,整个控制都交给开发者来做。回到正题,ActionResult的继承体系如下:
从上面的图不难看出,ActionResult只是众多返回类型的根,从ASP.NET MVC 过渡到 ASP.NET WebAPI,对于请求的解析变化不大,变化最大的是返回类型,返回的是Http的一些状态(删除,新建,更新),对于获取对象的方法,通过HttpResponseMessage
1)通过HttpResponseMessage包装的返回对象
public HttpResponseMessage PostProduct(Product product) {
this._dbContext.Save(product);
var result = new HttpResponseMessage(product, HttpStatusCode.Created);
var location = Url.Route(null, new { id = product.ProductID });
result.Headers.Location = new Uri(location);
return result;
}
2)直接返回实体
public IEnumerable GetAllProducts()
{
return products;
}
对于WebApi的请求,可以归纳为四类,Create 、 Update 、 Read 、 Delete,下面列举了相关的匹配情况
HTTP 的四个主要方法 (GET, PUT, POST, DELETE) 按照下列方式映射为 CURD 操作:
下面有一个实现的例子。
资源新建(Create)
public HttpResponseMessage PostProduct(Product product) {
this._dbContext.Save(product);
var result = new HttpResponseMessage(product, HttpStatusCode.Created);
var location = Url.Route(null, new { id = product.ProductID });
result.Headers.Location = new Uri(location);
return result;
}
资源更新
public HttpResponseMessage PutProduct(int id, Product product) {
if (!this._dbContext.Products.Any(p => p.ProductID == id)) {
throw new HttpResponseException(HttpStatusCode.NotFound);
}
product.ProductID = id;
this._dbContext.Update(product);
return new HttpResponseMessage(HttpStatusCode.OK);
}
资源删除
public HttpResponseMessage DeleteProduct(int id) {
var product = this._dbContext.Products.FirstOrDefault(p => p.ProductID == id);
this._dbContext.Delete(product);
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
说到这里,可以总结一下WebApi对于返回类型是如何转化为HttpResponse的。
1) Void类型
public class ValuesController : ApiController
{
public void Post()
{
}
}
客户端会收到如下信息
HTTP/1.1 204 No Content
Server: Microsoft-IIS/8.0
Date: Mon, 27 Jan 2014 02:13:26 GMT
2)HttpResponseMessage
public class ValuesController : ApiController
{
public HttpResponseMessage Get()
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, "value");
response.Content = new StringContent("hello", Encoding.Unicode);
response.Headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromMinutes(20)
};
return response;
}
}
这个请求只是返回了一个状态,大多数时候,我们都是一些内容的。如下:
public HttpResponseMessage Get()
{
// Get a list of products from a database.
IEnumerable products = GetProductsFromDB();
// Write the list to the response body.
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, products);
return response;
}
3)IHttpActionResult
这是WebApi2才引入的一个类型,这个接口定义了一个HttpResponseMessage的工厂,使用IHttpActionResult的好处主要有:
* 方便地写单元测试
* 封装了创建HttpResponse的细节
IHttpActionResult包含一个异步方法-ExecuteAsync,该方法创建一个HttpResponseMessage的实例。
public interface IHttpActionResult
{
Task ExecuteAsync(CancellationToken cancellationToken);
}
下面是一个使用IHttpActionResult的例子
public class TextResult : IHttpActionResult
{
string _value;
HttpRequestMessage _request;
public TextResult(string value, HttpRequestMessage request)
{
_value = value;
_request = request;
}
public Task ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage()
{
Content = new StringContent(_value),
RequestMessage = _request
};
return Task.FromResult(response);
}
}
4)其他返回类型
public class ProductsController : ApiController
{
public IEnumerable Get()
{
return GetAllProductsFromDB();
}
}
总结:ASP.NET MVC 到ASP.NET Api的过渡有很多值得思考的地方。这篇文章里面借鉴了官方的一些资料和博客园张志敏的部分内容,一并表示感谢。