D-17 路由 ? Routing

路由的介紹

在歷經昨天網頁程式的基礎知識的介紹之後,今天小光終於要開始進入網頁程式的開發了,所以今天小光會學到甚麼東西呢。

路由 Routing

「哇,昨天的基礎知識真的是讓我收穫良多阿」
小光一進公司就探頭探腦地走到大頭的座位前,然而大頭仍埋頭在需求文件中努力開發,但是他還是回應了小光的話。
「哈哈哈,我知道你昨天聽的頭昏腦脹的,不過基礎知識很重要,尤其是老K前輩跟你介紹的那些。」
聽到這裡小光忍不住吐舌頭做鬼臉來表示他的不好意思,接著突然想到甚麼似的問個問題。
「前輩,關於昨天Request Pipeline中的Routing是甚麼阿。」
這時剛好大頭開發告一段落後,他喝了杯水並抬起頭來跟小光這麼說。
「那個阿,簡單講就是怎麼樣透過URL到你程式的指引阿。」
聽到這個回答,小光表現出似懂非懂的樣子,所以看到小光的表情後大頭繼續說下去。
「怎麼,想要更進一步了解一下嗎。」
這時小光很猛烈的點頭,看到小光的樣子大頭就繼續說下去。
「好吧,那我們就來了解一下甚麼是路由以及如何設定他。」

路由是甚麼

這邊先看一下Routing是甚麼,其中MSDN中說「路由會負責比對傳入的 HTTP 要求,並將這些要求分派至應用程式的可執行端點」,所以簡單講來就是請求如何透過Url網址來到達我們寫的Code之間的對應,然而不同的網應程式類別他的對應也就不同,所以我們這邊以MVC跟WebApi為例子來說明如何設定路由,當然有興趣了解gRpc跟RazorPage的朋友們可以詳細看一下Routing這篇文章。

路由設定的地方

在Mvc與WebApi設定路由主要要設定兩個地方,StartupControllerAttribute,所以接下來分別介紹這兩個部分要設定甚麼,首先先介紹Startup的設定。

Startup的設定地方

這部分主要要設定的東西如下列所示,首先介紹Mvc的設定。

Mvc路由的設定內容

public void Configure(IApplicationBuilder app, 
    IWebHostEnvironment env)
{
    .
    .
    .
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
    .
    .
    .
}

透過上述設定,大部分的路由都會走default這個設定,例如/Products/Details/5這樣的Url就會對應到以下的程式碼的Details並且帶int參數的Action內。

public class ProductsController : Controller
{
    public IActionResult Details(int id)
    {
        ...
    }
}

不過其實上述例子中的MapControllerRoute也可以簡化為下列例子。

    app.MapDefaultControllerRoute();

然後路的設定可以設定多組,例如下列例子。

    endpoints.MapControllerRoute(name: "blog",
                pattern: "blog/{*article}",
                defaults: new { controller = "Blog", action = "Article" });
    endpoints.MapControllerRoute(name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");

在上述例子中Url為/Blog/Blog/Article/Blog/{any-string}是唯一符合 blog 路由的 URL 路徑,而且會對應到BlogController下的Article這個Action。

public class BlogController : Controller
{
    public RouteData Article ()
    {
        return ControllerContext.RouteData;
    } 

    public RouteData Index ()
    {
        return ControllerContext.RouteData;
    } 
}
所以Url跟結果會如下表所示。 Url 結果
/Blog/xxx {"dataTokens":{},"routers":[],"values":{"controller":"Blog","action":"Article","article":"xxx"}}
/Blog/Article {"dataTokens":{},"routers":[],"values":{"controller":"Blog","action":"Article","article":"Article"}}
/Blog/Index {"dataTokens":{},"routers":[],"values":{"controller":"Blog","action":"Article","article":"Index"}}
/ Home的Index的頁面
/Home Home的Index的頁面

WebApi路由的設定內容

所以介紹完了Mvc的設定方式後接下來跟大家介紹WebApi在Startup怎麼設定。

public void Configure(IApplicationBuilder app, 
    IWebHostEnvironment env)
{
    .
    .
    .
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
    .
    .
    .
}

相較於Mvc的設定來說,WebApi的設定簡單許多,因為有許多設定都是掛在Controller上的Attribute上,所以我們接下來說明一下Controller要設定的地方。

Controller設定的地方

剛剛說明完Startup要設定的部分之後,接下來我們要來看Controller設定的地方,這部分可以參考一下Mvc Routing的說明。關於Controller設定路由的部分可以分成兩種Attribute來說明,這兩種分別為RouteHTTP 動詞,因為我們在Startup使用的是MapControllers,所以如果沒特別設定的話預設會先使用預設的路由設定controller=Home}/{action=Index}/{id?,接下來先看下列Route的範例。

[Route("[controller]/[action]")]
public class HomeController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("[controller]/[action]")]
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    [Route("[controller]/[action]")]
    public IActionResult About()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}

首先在[]內的會對應到class上的controlleraction例如上面的Home這個Controller跟Index跟About這個Action,同時也可以特別指定到對應的路由例如上述的[Route("Home")],最後class上掛的attribute會繼承到方法上面所以其實方法上的[Route("[controller]/[action]")]可以省略。
再來在Restful上面會指定HttpMethod所以要搭配下列attribute使用讓Action只能接受特定HttpMethod

  • HttpGet
  • HttpPost
  • HttpPut
  • HttpDelete
  • HttpHead
  • HttpPatch
    實際設定如下。
[Route("api/[controller]")]
[ApiController]
public class Test2Controller : ControllerBase
{
    [HttpGet]   // GET /api/test2
    public IActionResult ListProducts()
    {
        ...
    }

    [HttpGet("{id}")]   // GET /api/test2/xyz
    public IActionResult GetProduct(string id)
    {
       ...
    }

    [HttpGet("int/{id:int}")] // GET /api/test2/int/3
    public IActionResult GetIntProduct(int id)
    {
        ...
    }

    [HttpGet("int2/{id}")]  // GET /api/test2/int2/3
    public IActionResult GetInt2Product(int id)
    {
        ...
    }
}

其中上述例子中可以看到[HttpGet("{id}")]這個的設定就是同時結合HttpMethod跟Route,簡單說明就是綁訂在HttpGet並且url為/api/test2/xyz的狀況下才會使用者個Action,其中url的xyz是任意字串。
所以路由就介紹到這裡告一段落了。

後記

「前輩,沒想到光一個Url的對應到程式碼就有這麼大的學問阿。」
聽完之後小光把他的感想告訴大頭,並且一邊抄寫他的筆記。
「哈哈哈,你才知道阿,不過這邊要注意的是避免寫出模凌兩可的路由喔,好一點在開發時會告訴你模凌兩可,如果寫得不好你會走到不是你想要的Action喔。」
所以今天就在大頭的叮嚀下結束了路由的課程。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *