2018年3月17日 星期六

【MVC教學】3. Route(一)


什麼是Route 在現實生活中比較接近於郵差與地圖的關係,你將想要送的東西交給郵差,郵差依據包裹上的地址,透過地圖找到目的地然後投遞。

而對應到程式中[網址]就是你包裹要送達的目的地址,Route就是[地圖],而網址的[參數]就是你要投遞的包裹



接著我們來看看專案內的Route在哪邊設定,又它是如何透過網址知道該把[包裹]送去哪支程式的,這邊先把我們之前的專案執行起來,並且點擊[關於]


可以看到關於頁的網址為 /Home/About


接著我們在HomeControllerAbout下中斷點後再點擊一次網頁的[關於]按鈕,會發現程式停在我們下中斷點的地方了? 為什麼知道程式會跑到這邊呢 ? 這一切都是因為有Route指路的關係



RouteConfig

Route的規則是可以自己制訂的,而制定的地方就在App_Start資料夾底下的RouteConfig裡面




讓我們來解讀這段程式碼,首先routes.MapRoute就是註冊地址的方法,裡面有幾個參數分別為

Name : 你對於這個Route的命名

Url : 網址條件,當網址符合這個條件特徵時,就會依據這個Route的指示去找對應執行的程式碼

defaults : 參數的預設值


相信光是講解參數的意義對於要理解Route還有相當的距離,讓我們直接來實戰理解 /Home/About這串網址如何對應到Route的吧,剛剛有說,routes.MapRouteUrl參數是用來判斷網址特徵是否相符,如果相符就會被這串Route捕捉到,但是這兩個怎麼看都不像啊

真實網址 /Home/About
Route Url :  {controller}/{action}/{id}


首先必須先知道一件事情,當Route Url的網址用{ }包起來的時候,代表他是個變數,什麼是變數?變數是一個表示值,它可以是任意的值,而{}裡面的字就是變數的名稱,以上述例子為例

我們有一個變數叫做controller,它可以是任意的值
我們有一個變數叫做action,它可以是任意得值
我們有一個變數叫做id,它也可以是任意的值

那套入/Home/About會變成什麼結果?

我們有一個變數叫做controller,它現在的值是Home
我們有一個變數叫做action,它現在的值是About
我們有一個變數叫做id,它現在沒有值

Route的制定中,controlleraction為保留字,意思是告訴他要執行哪個controllerAction,依據這邊的規定,所以它知道要去執行Home這個Controller,裡面一個叫做AboutAction



在Controller裡面寫的方法我們稱之為Action,而他通常都會回傳ActionResult

再讓我們看一個例子 [首頁]

首頁的網址為 : http://localhost:54004/



網址最前面這段寫著 Localhost :54004 ,Localhost為網址的Domain,54004為Port,Domain是網站的位置,例如我們在google搜尋Facebook時,會看到網址變成https://www.google.com.tw/search?q=facebook,而www.google.com.tw就是Domain,當讀到這串Domain時,就會透DNS找到Google的伺服器,然後呼叫它,並且請求他執行/search?q=facebook,這也是為什麼我們討論Route時沒有把Domain納進來,Domain只是讓網路能找到你服務的伺服器位置,後面才是你撰寫程式要處理的Route網址

所以首頁網址等於  

首頁網址 /
Route Url :  {controller}/{action}/{id}

我們有一個變數叫做controller,它現在沒有值
我們有一個變數叫做action,它現在沒有值
我們有一個變數叫做id,它現在沒有值


什麼都沒有,那程式到底要執行哪邊? 這時候Default終於派上用場了,Default的意思就是,當沒有值時,請用我設定的值代替吧



所以

controller為空值,所以用Default的值代替,所以它的值為Home
action為空值,所以用Default的值代替,所以它的值為Index
id為空直,但Default設定它為UrlParameter.Optional,意思是它是選擇性的,如果沒有沒關係

所以這個Route設定又完美符合了,所以依據條件,我們去HomeControllerIndex下中斷點,試試看進入首頁時是不是會停在這邊





的確,他依據規則跑到了HomeControllerIndex Action了。


那舉一反三一下,換句話說首頁網址也可以是 /Home/Index 摟,試試看,你會發現它的確走到一樣的中斷點




你可能會說,那這樣Route還有什麼好學的,這個寫法幾乎萬用了啊? 的確在MVC預設專案中的這個Route設定我們通常稱它為萬用Route,但也因為它幾乎萬用,所以不好管理,所以正常來說都還是會制定自己的Route規則,好方便管理,這個之後慢慢寫專案碰到多了會更有感觸。


接著我們來試著修改一下程式,讓我們的{id}能派上用場吧!!
在剛剛的案例中,因為id設定是Optional所以都沒派上用場,來試試看他怎麼用吧,首先我們先在HomeControllerAbout Action中加入參數id,並且把回傳的訊息改成Your id is (你帶進來的值)




接著我們重新執行一次程式,並且把網址改成/Home/About/Steven



再練習一次Route比對

我們有一個變數叫做controller,它現在的值是Home
我們有一個變數叫做action,它現在的值是About
我們有一個變數叫做id,它現在的值是Steven


讓接著看中斷點,把滑鼠移到id那的參數會看到,Id依據我們下的網址,以Steven帶進來了



接著看網頁呈現的成果


練習制定一個屬於我們的Route


看了兩個範例,我們也來制定一個Route規則給自己用吧,而且我們不要用變數的方式。



我們希望有個網址為/tellMe/whoAreYou/{name},且name跟之前的id一樣是個變數,可以由你自己打喜歡的文字來決定,寫完後來試試看這個route可不可行



結果竟然錯了,來看看少了什麼

網址 /tellMe/whoAreYou/steven
Route Url :  /tellMe/whoAreYou/{name}

比對tellMe,符合
比對whoAreYou,符合
比對Name這個變數,現在的值為Steven

然後呢? 有沒有發現即便這邊都比對正確,符合route規則,但我們沒告訴他Controller是誰,Action是誰,程式當然不知道該去執行誰,所以再來改一下,因為我們還沒學到如何建立ControllerAction,所以先用現成的, 導到homeControllerContact





讓我們再試試看剛剛的網址



這次不會壞掉了,且正確的導到HomeControllerContact Action去,接著試試不帶{Name}會怎麼樣



變成找不到資源,為什麼?因為我們的Name沒有設定為UrlParameter.Optional,所以是必帶的參數,這邊要特別注意!!! 之前教很多新人Route時很多人都卡在這邊

Route比對時必須完全符合才會被捕捉到

所以回頭審視我們的Route註冊目前有兩個規則

1. tellMe/whoAreYou/{name}
2. {controller}/{action}/{id}

而我們帶的網址為 /tellMe/whoAreYou ,比對的規則將會是


由上到下,所以先比對了 1. tellMe/whoAreYou/{name} 的規則 
tellMe,符合
whoAreYou,符合
Route要求要有Name,且不是Optional,所以必帶,”不符合”


這段Route會被跳過,執行比對2. {controller}/{action}/{id} 的規則
ControllertellMe,符合
ActionWhoAreYou,符合
Id為空值,因為為Optional,符合


所以實際程式去找的是TellMeController裡面的WhoAreYou這個Action,因為找不到這支程式所以顯示錯誤,而不是去執行規則1. HomeControllerContact這個Action


這是新手常常會犯的觀念錯誤,所以特別舉這個例子希望能夠較清楚的比較跟釐清,而Route因為還有很多種設定,避免一次太多造成混亂,所以先到這邊。試著將上述的觀念釐清,對於之後撰寫MVC Route時會很有幫助