剖析ASP.NET WebAPI 转化 ActionResult 为 HttpResponse的机制

        众所周知,ASP.NET MVC 通过Action接收用户请求,返回的是ActionResult.ActionResult包含很多种类,这里我搜集了一些常见类型的ActionResult及其相关的描述,见下表格,这里需要指出的是ActionResult也是有类的继承体系的,并不是单一的类,稍后会给出ActionResult的继承体系图。

    剖析ASP.NET WebAPI 转化 ActionResult 为 HttpResponse的机制_第1张图片

    如上所述,众多ActionResult的类型能够根据请求选择合适的返回类型。对于传统的ASP.NET,请求的是物理文件,根据文件后缀去选择相应的HttpHandler进行处理,HttpHandler对于开发者来说相对比较封闭,如果要对请求做额外的处理,需要重写某些方法。现在使用MVC,Action根据请求灵活选择返回的内容和方式,整个控制都交给开发者来做。回到正题,ActionResult的继承体系如下:

    剖析ASP.NET WebAPI 转化 ActionResult 为 HttpResponse的机制_第2张图片

从上面的图不难看出,ActionResult只是众多返回类型的根,从ASP.NET MVC 过渡到 ASP.NET WebAPI,对于请求的解析变化不大,变化最大的是返回类型,返回的是Http的一些状态(删除,新建,更新),对于获取对象的方法,通过HttpResponseMessage封装一个对象返回去,这个稍微特殊点。ApiController当然也支持返回对象,通常是程序内部使用。上述情形的代码Demo如下:

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,下面列举了相关的匹配情况

剖析ASP.NET WebAPI 转化 ActionResult 为 HttpResponse的机制_第3张图片

HTTP 的四个主要方法 (GET, PUT, POST, DELETE) 按照下列方式映射为 CURD 操作:

  • GET 用于获取 URI 资源的进行展示, GET 操作不应对服务端有任何影响;
  • PUT 用于更新 URI 上的一个资源, 如果服务端允许, PUT 也可以用于新建一个资源;
  • POST 用于新建 资源, 服务端在指定的 URI 上创建一个新的对象, 将新资源的地址作为响应消息的一部分返回;
  • DELETE 用于删除指定的 URI 资源。

下面有一个实现的例子。

资源新建(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的。

剖析ASP.NET WebAPI 转化 ActionResult 为 HttpResponse的机制_第4张图片

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的过渡有很多值得思考的地方。这篇文章里面借鉴了官方的一些资料和博客园张志敏的部分内容,一并表示感谢。



 



 

你可能感兴趣的:(ASP.NET,MVC)