2014年9月22日 星期一

ASP.NET MVC - 使用 RouteJs - Part.1

我很不喜歡在 View 頁面裡直接下 Javascript 程式碼,必須要的話,我也一定會將全部的 Javascript 程式碼擺在頁面的最下面,我相當不能夠忍受 Javascript 程式碼穿插出現在 View 的任何一個地方。

View 頁面除了 Html Tag 之外還會有 Razor Syntax,我必須說在複雜的頁面顯示邏輯下,Html Tag 與 Razor Syntax 就有可能會相當混亂,此時如果再加入 Javascript 程式碼的話,這已經不是複雜或是混亂可以來形容,如果要選個適當的形容詞,那麼我會用「惡搞」,尤其是有些開發者為了要控制某些邏輯的情況下才能夠觸發哪些前端功能時,會用 Razor Syntax 來包住 Javascript 程式碼,也就是用後端程式的邏輯來控制前端程式的有無以及能否執行,這樣搞得前後端程式邏輯在頁面裡大亂鬥,這樣的做法就好像回到十多年前開發 ASP 一般。

我在專案裡對於 View 頁面所使用的做法是將 Javascript 程式碼全部抽離,然後放到一個獨立的 Javascript 檔案裡,而且一個頁面對應一個 Javascript 檔案,不會出現 A 頁面去使用到 B 頁面的前端程式,假如有出現共用的程式,則再提取出來放在更上一層的 Javascript 檔案裡,這樣的做法就如同我們在寫後端 C# 程式一樣。

但是有很多開發者對於要將 javascript 程式碼從頁面抽離都會面臨到一個問題,那就是如何取得後端方法的路徑,在 View 頁面上可以直接使用 Url.Action() 來取得路徑,但如果是在 Javascript 檔案裡就無法使用 UrlHelper 來取得路徑,而如果是直接將路徑寫死在 Javascript 程式碼裡,就會面臨到如果網站位置、路徑有改變時所帶來的影響,另外就是有時路徑並不是如我們所想的那樣,也因為無法正確取得路徑或是難以取得正確路徑的緣故,而只能讓 javascript 程式碼繼續留在 View 頁面裡。

接下來就位各位說明如何在網站裡使用 RouteJs,讓我們可以在 Javascript 程式碼裡一樣可以使用類似 Url.Action() 的方法來取得正確的路徑。

 


前面扯了一大堆,一定會有人說「你說要把 Javascript 程式碼抽離出 View 頁面,然後放到 javascript 檔案裡,但是你部落格的很多文章都是直接在頁面的下方直接寫 javascript 程式碼呀!」

部落格文章的篇幅與內容都不是很長,往往都是在說明某些情況下的一些處裡做法,所以就不會去做拆解抽離的處理,就如同坊間許多的書籍,在書本裡的範例往往都是直接在方法裡去建立資料庫連結、加入 SQL Command、執行指令、取出資料,但是現實的專案開發卻應該是資料存取給抽離出去,如果書本裡一開始就教這些的確是會造成學習的困難,所以這些書本裡的範例就不會再去說明進階的做法,因為沒有再去說明進階的做法,而使得一堆人恣意的在方法裡將整個資料存取、商業邏輯、頁面顯示邏輯的程式擺在裡面,造成日後維護的困難。

似乎離題了,不過我還是覺得有必要做說明,不然一堆人都直接在 View 頁面裡直接寫 Javascript Code,然後散在頁面的各處,我看到這樣的情況真的是很難受。

 

如果我們將 Javascript Code 寫在頁面裡,而有需要取得後端執行方法的路徑時,我們就會使用 Url.Action(),

image

但是這樣的做法只能是當 Javascript Code 在 View 頁面下的時候,如果要將頁面裡的 Javascript Code 給抽離出來放到 Javascript 檔案裡,那麼就無法使用 Url.Action() 來取得後端執行方法的路徑。

 

於是就出現了下面的做法,而這也是我之前一直所使用的方式,

image

我會先把這個頁面的 Javascript 程式會使用到的後端執行方法的路徑先產生出來,然後再給 Javascript 程式使用,如此一來,我在 Javascript 檔案裡的程式也可以拿到正確的後端執行方法的路徑,

image

 

上面的方法行得通,但是如果遇到一個頁面裡需要使用的後端執行方法有很多的時候,那麼就會如下面的情況一樣,

image

上面的還算少,曾經有個頁面所使用的 actionUrls 多達二三十個,在管理上就會很麻煩,所以我一直在找有沒有一個比較好的解決方式,讓前端程式可以不必經由 UrlHelper 就可以取得正確的後端執行方法的路徑。

 

RouteJs

image

http://dan.cx/projects/routejs

https://github.com/Daniel15/RouteJs

這個 Javascript 套件不需要依賴 jQuery 或是其他前端的 Framework,可以在 Visual Studio 裡透過 NuGet 安裝在專案裡,從 ASP.NET MVC 2 ~ 5 都有提供相對應的版本,

https://www.nuget.org/packages?q=RouteJs

image

另外專案裡一定要有 Json.NET,而使用方法可以查看 RouteJs 在 GitHub 或其官網上面的說明,接下來就從安裝到使用來做個介紹。

 

Step.1 安裝

我所使用的範例專案為 ASP.NET MVC 5,所以透過 NuGet 尋找 RouteJs 後,要選擇安裝的是 RouteJs (MVC 5),

image

安裝之後會將 readme.txt 開啟,裡面的訊息是告訴我們要在 View 頁面裡加入 RouteJs 的參考,另外 RouteJs 也可以使用在 ASP.NET WebForms 裡,不過這邊就不會討論到這一個部分,

To finish installing RouteJs, you need to reference it in your view.
 
For Razor (typically in _Layout.cshtml):
<;script src="@RouteJs.RouteJsHandler.HandlerUrl"></script>
 
For Web Forms:
<;script src="<%: RouteJs.RouteJsHandler.HandlerUrl %>"></script>
 
Please refer to the RouteJs site and GitHub project for more information, or to report bugs: http://dan.cx/projects/routejs

在 Web.Confg 裡有增加設定,一個是 section 的設定,另一個就是 RouteJs 的使用設定,

image

image

 

Step.2 單一頁面的使用

單一頁面所指的是沒有使用到 _Layout.cshtml 的 View 頁面,以下是一個登入的頁面,沒有使用 RouteJs 的內容,

image

相對應的 project.Logon.js 檔案,

image

然後現在要在這個 Logon.cshtml 裡使用 RouteJs,記得一定要加入下圖裡用紅線框起來的 reference,而原本要在 View 頁面裡事先準備的後端執行方法的路徑就可以拿掉,

image

而取得後端執行方法路徑的部分就到 project.Logon.js 裡使用 RouteJs 來處理,

image

使用的方法為「Router.action()」,與 ASP.NET MVC 的 UrlHelper 不同的是,Router.action 方法的第一個參數為 Controller 名稱,第二個參數為 Action 方法的名稱,與 UrlHelper 的 Url.Action() 是相反的。

在 project.Logon.js 裡使用剛才所設定的路徑,

image

 

Step.3 _Layout.cshtml

上面是單一頁面的使用方式,如果是許多頁面都有使用 _Layout.cshtml 的話,那就很簡單,就是將 RouteJs 的 reference 放在 _Layout.cshtml 裡就可以了,

image

以 Home/Index.cshtml 為例,原本在 View 頁面裡的 Javascript Code,

image

將 actionUrls 的部分給拿掉,然後在 project.Home.js 裡去使用 RouteJs 取得後端執行方法的路徑,

image

其中的 GetUserLogonRecord 所對應的後端執行方法是位在 Admin 的區域(Areas)裡,所以要正確取得 Areas 裡的路徑就要在 Router.action() 方法的第三個參數指定 area 的名稱,要使用小寫的「area」。

如果你的路徑會另外指定一些要傳給後端的參數與值,也是在第三個參數裡加入,使用的方式在 RouteJs 的官網或 GitHub 上面都有提到,

image

image

 

不過這邊我還是會建議各位可以詳看 RouteJs 在 GitHub 上面的單元測試內容,尤其是 Routertests.js,

https://github.com/Daniel15/RouteJs/blob/master/src/RouteJs.Tests/RouterTests.js

藉由單元測試裡的測試案例就可以知道如何使用以及產出的結果。

 

以上

4 則留言:

  1. 好方便啊,可以解決一些 js 裡面去取得 url 的問題
    感謝分享

    回覆刪除
    回覆
    1. RouteJs 的 route 設定資料來源還是依據我們後端 RouteConfig.cs 裡面的 routes 內容
      所以不用擔心需要維護兩份 route 設定資料

      刪除
  2. 但是我们的站点的静态资源全部都是放在cdn域的,项目工程下是没有Content和Scripts目录的

    回覆刪除
    回覆
    1. Hello, 你好
      如果是這樣的情境就不適合使用 RouteJS 了.

      刪除

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。

最近的留言