本文档翻译自网页:http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api中的内容,属于微软的ASP.NET Web API 教程中的一篇。
这篇文档主要描述了在ASP.NET Web API 框架中是如何将HTTP请求路由到指定的控制器。
如果你对ASP.NET MVC有所了解,你就会发现Web API中的路由机制与其有很多类似的地方。其中主要的不同在于在Web API中是通过HTTP请求方法来选择响应动作,而在MVC中则采用的是URI路径。当然,你也可以在Web API中采用MVC式的路由机制。这篇文章假定你对ASP.NET MVC没有任何了解。
路由表
在ASP.NET Web API中,控制器代表着一个类,用来处理HTTP请求。在控制器中的公开方法被称为处理方法(action methods)或简称为处理(actions)。当Web API框架接收到一个请求时,就将其路由到一个指定的处理方法中。
框架采用路由表来确定引发哪一个处理方法。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对象中直接设置路由表。关于这些知识可以参见
Self-Host a Web API
在路由表中的每个入口都包含一个路由模板。Web API中的默认模板为:“api/{conrtoller}/{id}”。在这个模板中,"api"是显然具有字面意义的路径字段,{controller}和{id}都是占位符变量。
当Web API框架获取到一个HTTP请求之后,它就会尝试将这个URI跟路由表中的路由模板进行匹配。如果匹配失败,则会返回404错误。比如,如下的URI都能跟上文讲到的默认路由模板匹配:
/api/contacts
/api/contacts/1
/api/products/gizmo1
然而,一个缺少"api/"字段的URI则不会被匹配:
/contacts/1
注意:在路由中使用"api/"的原因是为了避免与ASP.NET MVC中的路由相混淆。如此,我们就可以用"/contacts/1"只想一个MVC控制器,而"api/contacts/1"则用来只想一个Web API控制器。当然,如果你对这样的安排感到不满意的话,你完全可以自定义自己的路由表。
一旦一个路由被匹配,Web API就会开始选择控制器和处理方法:
- 为了找到控制器,Web API会在占位符变量{controller}的值后面加上单词"Controller",以此来构成控制器的名称;
- 为了找到HTTP请求“希望”的处理方法,Web API首先查看这个HTTP请求是哪一类型的请求,然后在控制器类的方法列表中检索以这个请求类型开头的方法。举例来说,当这个HTTP请求是Get请求时,Web API就会检索那些以“Get...”开头的方法,就像"GetContact"或"GetAllContacts"这样。这种约定仅仅针对GET,POST,PUT和DELETE方法。你可以通过在你的控制器中增加特性的方式将其他HTTP方法也包括进来,接下来我们会看到这样的例子。
- 路由模板中的其他占位符变量(例如"{id}")则会被当做处理方法的传入参数。
接下来我们来看一个例子。假设我们定义了如下的控制器类:
public class ProductsController : ApiController
{
<pre> public void GetAllProducts() { }
public IEnumerable<Product> GetProductById(int id) { } public HttpResponseMessage DeleteProduct(int id){ }}
下面是一些HTTP请求,和与其对应的URI,以及处理方法、处理方法的传入参数对照表:
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) |
其他路由方式
目前为止我们谈论的都是基本的路由机制。下面我们来谈谈一些变数。
HTTP方法
除了采用针对HTTP请求方式所做的命名约定,你也可以直接在控制器的处理方法上加上
HttpGet、
HttpPut、
HttpPost或者
HttpDelete属性,以此来与相应的HTTP请求相匹配。
在下面的例子中,FindProduct方法就会与Http Get请求对应:
public class ProductsController : ApiController
{
[HttpGet]
public Product FindProduct(id) {}
}
为了使一个控制器方法能够对不止一种HTTP请求作出响应,或者对除GET,PUT,POST,DELETE之外的HTTP请求作出响应,可以使用AcceptVerbs属性指定一系列的HTTP请求。正如下面代码所示:
public class ProductsController : ApiController
{
[AcceptVerbs("GET", "HEAD")]
public Product FindProduct(id) { }
// WebDAV method
[AcceptVerbs("MKCOL")]
public void MakeCollection() { }
}
通过添加处理方法名进行路由
在默认的路由模板中,Web API通过HTTP请求方法来选择相应的处理方法。然而,你也可以创建一个将处理方法的名称包含在URI里的路由模板:
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
设置了这样的路由模板后,{action}变量就可以用控制器中的处理方法名来填充。这种路由模式使用属性特征来甄别不同的HTTP请求。例如,假设你的控制器类拥有如下方法:
public class ProductsController : ApiController
{
[HttpGet]
public string Details(int id);
}
那么,一个对URI为"api/products/details/1"的GET请求将会触发Details方法。
此外,可以通过添加 ActionName属性来复写处理方法名。在下面的例子中的两个方法都符合URI:"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);
}
不响应请求的处理方法
为了阻止控制器中的某个方法被触发,可以向这个方法添加 NonAction属性。这个标签向Web API框架说明此方法并不是一个处理方法,即使这个方法可能符合某个路由策略。//不是处理方法的方法
[NonAction]
public string GetPrivateData() { ... }
注:欢迎共同学习,一起交流。