Attribute Routing
參考文章:
介紹
Web Api與MVC一樣有Routes,結構幾乎相同,可以到App_Start資料夾查看到以下內容:
Web Api
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
MVC
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
好處
可以有更彈性的方式自訂路由
public class ReviewsController : Controller
{
// eg: /reviews
[Route(“reviews”)]
public ActionResult Index() { … }
// eg: /reviews/5
[Route(“reviews/{reviewId}”)]
public ActionResult Show(int reviewId) { … }
// eg: /reviews/5/edit
[Route(“reviews/{reviewId}/edit”)]
public ActionResult Edit(int reviewId) { … }
}
開始實作
以下將會以Web Api2做實作,基本上你至WebApiConfig
就會發現預設已透過以下的方法開啟了Attrribute Route的功能 :
- config.MapHttpAttributeRoutes();
namespace WebApi
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// 啟用Attribute Route
config.MapHttpAttributeRoutes();
..以下省略
}
}
}
修改ProductController
ProductController.cs
// 取得全部資料
// GET api/product
public HttpResponseMessage Get()
{
var products = _productServices.GetAllProducts();
if (products != null)
{
var productEntities = products as List<ProductEntity> ?? products.ToList();
if (productEntities.Any())
{
return Request.CreateResponse(HttpStatusCode.OK, productEntities);
}
}
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Products not found");
}
//取得單一資料
[Route("v2/productid/{id:int}")]
[Route("v2/particularproduct/{id:int}")]
[Route("v2/myproduct/{id:range(1, 3)}")]
// GET api/product/1
public HttpResponseMessage Get(int id)
{
var product = _productServices.GetProductById(id);
if (product != null)
{
return Request.CreateResponse(HttpStatusCode.OK, product);
}
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No product found for this id");
}
可使用以下的網址做測試:
//可使用
v2/productid/1
//可使用
v2/particularproduct/1
//可使用
v2/myproduct/1(只能輸入1到3)
//不能使用了
api/product/1
你會發現到,原本的URL格式api/product/1
變成會去取得全部資料,因為Route的優先序問題,導至他找錯Action,修正的方式如下:
- 在Controller上加入[RoutePrefix("api/product")]
- 指定URL前綴詞為api/product/xxxx/xxx
- 取得全部的資料Action上加入[Route("")]
- URL格式:api/product/
- 需透過HttpGet方法
- 取得單一的資料Action上加入[Route("{id}")]
- 告訴RouteTable此Action會使用到id這個參數
- URL格式:api/product/1 (數字可任意調換)
- 需透過HttpGet方法
# ProductController.cs
namespace WebApi.Controllers
{
[RoutePrefix("api/product")]
public class ProductController : ApiController
{
[Route("")]
// GET api/product
public HttpResponseMessage Get()
{
var products = _productServices.GetAllProducts();
if (products != null)
{
var productEntities = products as List<ProductEntity> ?? products.ToList();
if (productEntities.Any())
{
return Request.CreateResponse(HttpStatusCode.OK, productEntities);
}
}
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Products not found");
}
...省略其他RouteAttribute
[Route("{id}")]
// GET api/product/5
public HttpResponseMessage Get(int id)
{
var product = _productServices.GetProductById(id);
if (product != null)
{
return Request.CreateResponse(HttpStatusCode.OK, product);
}
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No product found for this id");
}
}