在歷經昨天網頁程式的基礎知識的介紹之後,今天小光終於要開始進入網頁程式的開發了,所以今天小光會學到甚麼東西呢。
「哇,昨天的基礎知識真的是讓我收穫良多阿」
小光一進公司就探頭探腦地走到大頭的座位前,然而大頭仍埋頭在需求文件中努力開發,但是他還是回應了小光的話。
「哈哈哈,我知道你昨天聽的頭昏腦脹的,不過基礎知識很重要,尤其是老K前輩跟你介紹的那些。」
聽到這裡小光忍不住吐舌頭做鬼臉來表示他的不好意思,接著突然想到甚麼似的問個問題。
「前輩,關於昨天Request Pipeline中的Routing是甚麼阿。」
這時剛好大頭開發告一段落後,他喝了杯水並抬起頭來跟小光這麼說。
「那個阿,簡單講就是怎麼樣透過URL到你程式的指引阿。」
聽到這個回答,小光表現出似懂非懂的樣子,所以看到小光的表情後大頭繼續說下去。
「怎麼,想要更進一步了解一下嗎。」
這時小光很猛烈的點頭,看到小光的樣子大頭就繼續說下去。
「好吧,那我們就來了解一下甚麼是路由以及如何設定他。」
這邊先看一下Routing是甚麼,其中MSDN中說「路由會負責比對傳入的 HTTP 要求,並將這些要求分派至應用程式的可執行端點」,所以簡單講來就是請求如何透過Url網址來到達我們寫的Code之間的對應,然而不同的網應程式類別他的對應也就不同,所以我們這邊以MVC跟WebApi為例子來說明如何設定路由,當然有興趣了解gRpc跟RazorPage的朋友們可以詳細看一下Routing這篇文章。
在Mvc與WebApi設定路由主要要設定兩個地方,Startup
跟Controller
的Attribute
,所以接下來分別介紹這兩個部分要設定甚麼,首先先介紹Startup
的設定。
這部分主要要設定的東西如下列所示,首先介紹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的頁面 |
所以介紹完了Mvc的設定方式後接下來跟大家介紹WebApi在Startup怎麼設定。
public void Configure(IApplicationBuilder app,
IWebHostEnvironment env)
{
.
.
.
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
.
.
.
}
相較於Mvc的設定來說,WebApi的設定簡單許多,因為有許多設定都是掛在Controller上的Attribute上,所以我們接下來說明一下Controller要設定的地方。
剛剛說明完Startup
要設定的部分之後,接下來我們要來看Controller設定的地方,這部分可以參考一下Mvc Routing的說明。關於Controller設定路由的部分可以分成兩種Attribute
來說明,這兩種分別為Route
與HTTP 動詞
,因為我們在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上的controller
跟action
例如上面的Home這個Controller跟Index跟About這個Action,同時也可以特別指定到對應的路由例如上述的[Route("Home")]
,最後class上掛的attribute會繼承到方法上面所以其實方法上的[Route("[controller]/[action]")]
可以省略。
再來在Restful上面會指定HttpMethod所以要搭配下列attribute使用讓Action只能接受特定HttpMethod
[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喔。」
所以今天就在大頭的叮嚀下結束了路由的課程。