加入 MVC SiteMap provider 到專案當中

MvcSiteMapProvider
之前開發網站的時候沒有用到類似的工具,或著是用自己定義的元件來做類似的事情,後來在同事推薦下加入到開發當中。

  • 加入 MvcSiteMapProvider 到專案
  • 定義 SiteMap 階層
  • 利用 SiteMap 物件產生選單列表
  • 自行定義 Display Template
  • 搭配角色權限使用 SiteMap
  • 動態產生 SiteMapNode
  • 動態切換多個 SiteMapProvider

加入 MvcSiteMapProvider 到專案

  • 利用 Nuget >  MvcSitemapProvider
  • Nuget  的 Package Manager Console PM> Install-Package MvcSitemapProvider

一開始可以看到加入的檔案中 Mvc.sitemap 就是定義 sitemap 的檔案,檔案格式是用 XML ,預設的部分有加入 Home 跟 About 的部分。

<mvcSiteMapNode title="Home" controller="Home" action="Index">
<mvcSiteMapNode title="About" controller="Home" action="About"/>
</mvcSiteMapNode>

除了 Mvc.sitemap 也會在 Views/Shared/DisplayTemplates 加入配合產生 Ment 的 Display Templates 。

定義 SiteMap 階層

從預設的 .sitemap 檔案就可以看出基本的架構,利用 XML 階層的概念配合整個網站的架構。一開始加入 SiteMap 的另一個好處是會逼得自己了解整個網站的邏輯,遇到規劃上的問題也容易發現。在這邊我直接用 ASP.NET MVC 4 Beta 的預設專案 Template 做 SiteMap。

<mvcSiteMapNode title="首頁" controller="Home" action="Index">
<mvcSiteMapNode title="關於 MVC 4" controller="Home" action="About"/>
<mvcSiteMapNode title="會員登入" controller="Account" action="Login"/>
<mvcSiteMapNode title="註冊會員" controller="Account" action="Register"/>
<mvcSiteMapNode title="變更密碼" controller="Account" action="ChangePassword"/>
</mvcSiteMapNode>

利用 SiteMap 物件產生選單列表

定義完 SiteMap 之後,可以用來幫助我們產生一些頁面上的元件。比較常用的就是 Header 的 Menu 或是 SiteMap Path 之類的。

Html.MvcSiteMap().SiteMap()

我替換掉 Layout.cshtml 下的 menu 並且換上 MvcSiteMapProvider 的 Helper。

<nav>
@Html.MvcSiteMap().SiteMap()
</nav>

產生出來的 Html

<ul id="menu">
<li><a href="/">首頁</a> </li>
<li><a href="/Home/About">關於 MVC 4</a> </li>
<li><a href="/Account/Login">會員登入</a> </li>
<li><a href="/Account/Register">註冊會員</a> </li>
<li><a href="/Account/ChangePassword">變更密碼</a> </li>
</ul>

image
這邊預設的 menu 比較簡單,如果想要能有華麗一點的多階層 menu 就是要修改 Template 配合 javascript css。

自行定義 Display Template

在評估的時候,大家都會蠻害怕如果 Helper 的格式不能變動怎麼辦,或是說被元件綁死,但是其實完全都是可以自行定義的。之前有提到一開始加入的 Display Templates 資料夾裡面就是產出的格式,MvcSiteMapProvider 做的事只是利用 XML 裡面的定義幫忙產生物件的階層。Html 顯示的邏輯都是自訂的。我比較習慣 Razor 的寫法,所以移除掉了 ascx 的部分,但是其實做的事情都是一樣的。

  • MenuHelperModel.cshtml > @Html.MvcSiteMap().Menu()
  • SiteMapHelperModel.cshtml > @Html.MvcSiteMap().SiteMap()
  • SiteMapNodeModel.cshtml > 單一 Node 顯示方式
  • SiteMapNodeModelList.cshtml > List<Node> 顯示方式
  • SiteMapPathHelperModel.cshtml > @Html.MvcSiteMap().SiteMapPath()
  • SiteMapTitleHelperModel.cshtml > @Html.MvcSiteMap().SiteMapTitle()

這只是預設的設定,其實只要在使用方法的時候多加入參數就可以。

@Html.MvcSiteMap().Menu("想要用的template.cshtml")

搭配角色權限使用 SiteMap

在設定 SiteMapNode 的時候也有一個屬性 Roles 可以做結合

<mvcSiteMapNode title="系統管理" roles="SystemAdmin,Supervisor"
area="Admin" controller="Home" action="Index">
<mvcSiteMapNode title="會員管理" roles="SystemAdmin,Supervisor"
area="Admin" controller="Account" action="Index"/>
</mvcSiteMapNode>

這邊的 roles 就是整合的 .net 的 Forms Authentication 的 Roles 屬性,當沒有權限頁面就不會出現在 SiteMap 裡面。這邊只是針對 SiteMap 部份顯示與否,如果直接存取 action 還是可以進入。不過我們可以配合這個邏輯來自訂 ActionFilter。

public class RolesAuthenticationAttribute : ActionFilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (SiteMap.CurrentNode == null)
{
throw new UnauthorizedAccessException();
}
}
}

只要將 ActionFilterAttribute 套用到 BaseController 或是只想針對個別套用也可以,這樣在權限控管上就可以由 sitemap 來做統一的設定。

自訂角色可以參考 ASP.NET 自訂角色的方式(不用實做 Role Provider)

動態產生 SiteMapNode

如果說需要動態產生 SiteMap 節點,像是 Blogger 這樣,Menu 是根據資料庫或其他來源來產生,那就需要動態來產生。

<mvcSiteMapNode title="" controller="Page" action="Index"
dynamicNodeProvider="MasonPrint.MVC4.Beta.Utilities.DynamicNodeProviders.PageDynamicNodeProvider
, MasonPrint.MVC4.Beta"/>

利用設定 DynamicNodeProvider 來做到動態節點。

public class PageDynamicNodeProvider : DynamicNodeProviderBase
{
public override IEnumerable<DynamicNode> GetDynamicNodeCollection()
{
DatabaseEntities1 db = new DatabaseEntities1();
var returnValue = new List<DynamicNode>();
//根據資料來源建立節點
foreach (var item in db.Pages.ToList())
{
DynamicNode node = new DynamicNode();
node.Title = item.Title;
node.ParentKey = "Page";
node.Key = "Page_" + item.Id;
node.RouteValues.Add("id", item.Id);

returnValue.Add(node);
}

// Return
return returnValue;
}
}

動態切換多個 SiteMapProvider

如果需要動態切換不同的 SiteMapProvider

SiteMap.Provider.ParentProvider = SiteMap.Providers["MvcSiteMapProvider1"];

需要注意事項

  1. .Sitemap 設定中 Key 必須是唯一值
  2. 如果 Action 不存在則 SiteMap 物件中節點不會產生
  3. SiteMap 物件建立之後會暫存在 Server 端

本篇專案下載


ASP.NET MVC SiteMap provider

Documenting [Authorize] attribute usage, producing a report

NuGet Package Manager ★★★★★ – The AppStore in Visual Studio

概略解釋 Forms Authentication 的運作

ASP.NET 自訂角色的方式(不用實做 Role Provider)

NuGet Package Manager ★★★★★ – The AppStore in Visual Studio

這個工具真的是非常的推薦,是現在用 Visual Studio 2010 開發以來,個人認為幫助最大的工具了。每次找到了什麼好用的 library 總是要找尋一些相關的文章,怎麼設定需要那些參考。現在有了 NuGet ,專案裡面好幾個 Library 我都還不知道他組件的名稱,就已經拿來用了。(看來太方便也是一個缺點)

NuGet 的力量主要還是建立在社群上面,他除了最基本的工具之外,平台才是真正的重點。很多人都會開發一些好用的小工具,或著是眾人合作的 open source 專案,原本的模式可能是透過社群去發布推薦,但是使用者在使用上也必須先了解相關設定,再手動把參考 reference 進來。而且如果一般工程師使用者沒有 follow 到這個訊息,也可能一直也不知道原來有這麼多資源可以幫助解決他手上的問題。

所以這個工具一次整合了兩個部分,就是社群以及降低使用門檻,讓開發者來幫你設定,而且使用者也可以看到下載數的排名。而開發者當然是希望自己做的東西愈多人用愈好,所以也會希望大家可以更方便的來用,造就了一個良性循環的結果。

image

▲首先在擴充管理員搜尋找到這個外掛功能安裝

image

▲接著在專案的功能列表之中我們就可以發現 NuGet 這個管理工具

image

▲包括 Library 的排名,介紹,安裝,使用者投票

image

▲安裝中

安裝結束之後就可以看到參考已經被加入了,如果 config 需要有額外的設定,一般來說也都會幫你預設完成。

image

▲在 NuGet 設定中,還可以設定私人伺服器

Reference

NuGet

http://nuget.codeplex.com/

架設私房NuGet Server

http://blog.darkthread.net/post-2011-05-27-nuget-server.aspx

還在揮汗徒手安裝程式庫? 試試NuGet吧

http://blog.darkthread.net/post-2011-03-12-nuget.aspx

介紹好用 Visual Studio 2010 擴充套件:NuGet 套件管理員

http://blog.miniasp.com/post/2011/05/17/Useful-Visual-Studio-2010-tool-NuGet-Package-Manager.aspx