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");
        }

}

results matching ""

    No results matching ""