ASP.NET Web API中的Routing(路由)

[译]Routing in ASP.NET Web API

单击此处查看原文

本文阐述了ASP.NET Web API是如何将HTTP requests路由到controllers的。

如果你对ASP.NET MVC非常的熟悉,那你将感受到Web API routing与MVC routing是非常的相似的。主要的不同点在于Web API选择action的时候,使用的是HTTP method,并非URI path。当然,你也可以在Web API中使用MVC风格的routing。以下,本文将不出现任何ASP.NET MVC的相关知识。

Routing Tables

在ASP.NET Web API中,一个controller是一个类,用于处理HTTP requests。其中public方法被称为 action methods 。当Web API框架接收到一个request,它会将这条request路由到对应的一个action。

Web API框架使用了 route table 来决定调用哪一个action。Visual Studio项目模板为Web API创建了一个默认路由:

routes.MapHttpRoute(
    name: "API Default",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

这条路由被定义在App_Start文件夹下的WebApiConfig.cs文件中。

这里写图片描述

关于WebApiConfig类的更多详情,参见Configuring ASP.NET Web API

如果你托管了Web API服务,那么必须在HttpSelfHostConfiguration对象中直接设置好routing table。更多详情,参见Self-Host a Web API

routing table中的每一个入口都包含了一个 route template 。Web API的默认route template是"api/{controller}/{id}"。在这个template中,"api"是不变的路径段,{controller}和{id}是两个占位符。

当Web API框架接受到了一个HTTP request,它会尝试将URI和route table中的route templates进行匹配。如果没有路由被命中,客户端将会收到一个404错误。

下面的URIs会匹配到默认路由:

/api/contacts
/api/contacts/1
/api/products/gizmo1

下面的URI无法进行匹配,因为它缺少了api段:

/contacts/1

注意:在api路由中使用"api"路径段的原因是为了避免跟ASP.NET MVC的路由撞在一起。这样你就可以将"/contacts"匹配到一个MVC controller,将"/api/contacts"匹配到一个Web API controller。当然咯,如果你不喜欢这种约定,你可以去修改默认route table。

一旦一个路由被匹配到,Web API就选择了对应的controller和action:

  • 为了找到controller,Web API会将"Controller"添加到{controller}变量中。
  • 为了找到action,Web API会根据HTTP method,去action里面找,直到找到一个名称由那个HTTP method开头action。例如,一个Get request,Web API会去找一个名为“Get...”的action,比如"GetContact"或"GetAllContacts"。这个约定只对GET、POST、PUT、DELETE方法。你可以在你的controller上使用特性来允许其他的HTTP method,后面会说到这一点。
  • route template中的其他的占位符变量,比如{id},会映射到action的parameters(参数)。

现在看一个例子:

public class ProductsController : ApiController
{
    public void GetAllProducts() { }
    public IEnumerable<Product> GetProductById(int id) { }
    public HttpResponseMessage DeleteProduct(int id){ }
}

下面是是一些可能的HTTP requests,以及将会被调用到的action。

HTTP Method URI Path Action Parameter
Get api/products GetAllProducts (none)
Get api/products/4 GetProductById 4
DELETE api/products/4 DeleteProduct 4
POST api/products (no match)

注意URI中 {id} 部分如果出现,将会被映射到action的 id 参数。在这个例子中,控制器定义了两个Get method,一个带有 id 参数,另一个没有参数。

同时,请注意Post request将会失败。因为控制器并没有定义一个"Post..."的方法。

Routing变化

上一节我们说到了ASP.NET Web API的基础routing机制。本节将会阐述其他的变化形式。

HTTP Methods

你可以使用HttpGet、HttpPut、HttpPost、HttpDelete特性为一个action显示指定HTTP method,用于替代原本的HTTP methods命名约定。

下面的例子中,FindProduct方法会被Get requests映射到:

public class ProductsController : ApiController
{
    [HttpGet]
    public Product FindProduct(id) {}
}

如果想要为一个action允许多个HTTP methods,或者除了Get、PUT、POST、DELETE之外的HTTP methods,你可以使用AcceptVerbs特性,它提供了一系列的HTTP methods。

public class ProductsController : ApiController
{
    [AcceptVerbs("GET", "HEAD")]
    public Product FindProduct(id) { }

    // WebDAV method
    [AcceptVerbs("MKCOL")]
    public void MakeCollection() { }
}

带有Action Name的Routing

通过默认route template,Web API使用HTTP method来选择调用哪个action。不过你也可以新建一个route,将action名字包含进URI中:

routes.MapHttpRoute(
    name: "ActionApi",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

在这个route template中,{action} 参数对应controller中的action method名字。这种风格的routing,使用特性来指定允许哪一个HTTP methods。例如,假设你的代码是如下的写法:

public class ProductsController : ApiController
{
    [HttpGet]
    public string Details(int id);
}

在这种情况下,一个Get request:"api/products/details/1"将会映射到具体的方法。这种routing跟ASP.NET MVC的非常相似,并且可能也是适用于一个RPC-style API的。

你可以通过ActionName特性来重写action name。在下面的例子中,有两个actions会被"api/products/thumbnail/id"映射到。一个支持GET,另一个支持POST。

public class ProductsController : ApiController
{
    [HttpGet]
    [ActionName("Thumbnail")]
    public HttpResponseMessage GetThumbnailImage(int id);

    [HttpPost]
    [ActionName("Thumbnail")]
    public void AddThumbnailImage(int id);
}

Non-Actions

为了防止一个方法被当做action来调用,可以使用NonAction特性。这个信号告诉框架此方法不是一个action,即使它匹配到了某一条路由规则。

// Not an action method.
[NonAction]  
public string GetPrivateData() { ... }

其他

本文从全局阐述了routing。更多详情,参见Routing and Action Selection,它确切地阐述了框架如何去将URI匹配到route,再如何选择controller,最后如何选择一个action来调用。

posted @ 2017-01-12 23:04  JoiT  阅读(3126)  评论(0编辑  收藏  举报