2010-10-15 133 views
4

我對ASP.Net和MVC都很陌生。ASP.Net MVC幫助重構

我在我的母版頁下面的代碼:

<div id="main-menu" class="menu"> 
    <% 
    var items = (IList<CompanyName.Framework.Web.MenuItem>)ViewData["MainMenu"]; 
    if (items.Count > 0) 
    { 
    %><ul><% 
    foreach (var item in items) 
    { 
    if (!string.IsNullOrEmpty(item.RequiredRole) && !System.Threading.Thread.CurrentPrincipal.IsInRole(item.RequiredRole)) 
     continue; 

    %><li><a href="<%= item.Uri %>"><%= item.Title %></a></li><% 
    } 
    %></ul><% 
    } 
    %> 
</div> 

我可以將代碼移動到另一個文件或以任何方式重構代碼?

編輯:

我ApplicationController的所有控制器導出:

public class ApplicationController : Controller 
{ 
    List<MenuItem> _mainMenu = new List<MenuItem>(); 
    List<MenuItem> _contextMenu = new List<MenuItem>(); 

    protected IList<MenuItem> MainMenu 
    { 
     get { return _mainMenu; } 
    } 

    protected IList<MenuItem> ContextMenu 
    { 
     get { return _contextMenu; } 
    } 

    protected string PageTitle { get; set; } 

    protected override void OnResultExecuting(ResultExecutingContext filterContext) 
    { 
     ViewData["PageTitle"] = PageTitle; 
     ViewData["MainMenu"] = MainMenu; 
     ViewData["ContextMenu"] = ContextMenu; 
     base.OnResultExecuting(filterContext); 
    } 
} 

回答

9

這裏有一些建議:

改善1號:使用視圖模型和強類型的意見,而不是ViewData的

public ActionResult Index() 
{ 
    // TODO: Fetch this data from a repository 
    var menus = new[] { 
     new MenuItem(), new MenuItem() 
    }.ToList(); 

    return View(menus); 
} 

,然後在您的視圖:

<div id="main-menu" class="menu"> 
    <% 
     if (Model.Count > 0) 
     { 
      %><ul><% 
      foreach (var item in Model) 
      { 
       if (!string.IsNullOrEmpty(item.RequiredRole) && !System.Threading.Thread.CurrentPrincipal.IsInRole(item.RequiredRole)) 
        continue; 

       %><li><a href="<%= item.Uri %>"><%= item.Title %></a></li><% 
      } 
      %></ul><% 
     } 
    %> 
</div> 

仍然可怕,完全不可讀的標籤湯。


改進2號:使用編輯/顯示模板:

~/Views/Home/DisplayTemplates/MenuItem.ascx

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CompanyName.Framework.Web.MenuItem>" %> 

<% if (!string.IsNullOrEmpty(Model.RequiredRole) && 
     System.Threading.Thread.CurrentPrincipal.IsInRole(Model.RequiredRole)) { %> 
    <li> 
     <a href="<%= Model.Uri %>"><%= Model.Title %></a> 
    </li> 
<% } %> 

,然後在主視圖:

<div id="main-menu" class="menu"> 
    <ul> 
     <%= Html.DisplayForModel() %> 
    </ul> 
</div> 

改進編號3:避免在視圖中編寫業務規則。因此,在您的視圖模型添加屬性:

public bool IsLinkVisible 
{ 
    get 
    { 
     return !string.IsNullOrEmpty(RequiredRole) && 
       Thread.CurrentPrincipal.IsInRole(RequiredRole); 
    } 
} 

,使顯示的模板現在看起來是這樣的:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CompanyName.Framework.Web.MenuItem>" %> 
<% if (Model.IsLinkVisible) { %> 
    <li> 
     <a href="<%= Model.Uri %>"><%= Model.Title %></a> 
    </li> 
<% } %> 

改進號4:編寫自定義HTML助手來解析這個錨因爲在視圖中編寫C#仍然是醜陋和不可測:

public static class HtmlExtensions 
{ 
    public static MvcHtmlString MenuItem(this HtmlHelper<MenuItem> htmlHelper) 
    { 
     var menuItem = htmlHelper.ViewData.Model; 
     if (!menuItem.IsLinkVisible) 
     { 
      return MvcHtmlString.Empty; 
     } 
     var li = new TagBuilder("li"); 
     var a = new TagBuilder("a"); 
     a.MergeAttribute("href", menuItem.Uri); 
     a.SetInnerText(menuItem.Title); 
     li.InnerHtml = a.ToString(); 
     return MvcHtmlString.Create(li.ToString()); 
    } 
} 

最後是你的顯示模板:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CompanyName.Framework.Web.MenuItem>" %> 
<%= Html.MenuItem() %> 
+2

+1不錯的改進流程! – 2010-10-15 09:04:07

+0

問題是我將BusinessObjects用作大多數視圖的模型。 MainMenu(和一個ContextMenu)是ApplicationControlLer上的屬性,並在執行ActionResult之前分配給ViewData。當然,我可以做一個ApplicationViewData ,它將業務對象作爲類型參數。但是,這並不是一個乾淨的解決方案,因爲控制器中的屬性和母版頁中使用ViewData [「MainMenu」],因爲只有母版頁受到後者的影響。我喜歡你的解決方案,但是我怎樣才能使用它,而不必使用輸入視圖? – jgauffin 2010-10-15 09:28:19

+0

如果它在主頁面中,則表示所有視圖都需要此屬性。因此,您可以使所有視圖模型都從包含菜單屬性的基本視圖模型派生。然後可以將此屬性填充到操作篩選器中,以避免在所有操作中執行此操作,然後可以強制將此母版頁鍵入到此基本視圖模型中。 – 2010-10-15 09:30:35

3

是的,你可以把該塊到.ascx文件和使用:

<% html.RenderPartial("myPartialFile.asx"); %> 

的上面假定myPartialFile.ascx位於與母版頁相同的文件夾中,通常是Views/Shared文件夾。

+0

事實上部分必須是在同一個文件夾或瀏覽/共享文件夾。沒有必要在那裏移動。即使你對通常分享的母版頁當然是對的。 – 2010-10-15 08:54:47

+0

+1 - 正是我想要建議L :) – 2010-10-15 08:55:12