2017-01-09 53 views
1

我正在改進MVC EpiServer網站的性能,並且正在尋找關於麪包屑控制代碼優化的一些指導。我們試圖在運行時減少本站點IIS的內存佔用量。我們如何更好地優化這個EpiServer麪包屑導航代碼?

目前這段代碼是在一個視圖中,我打算通過將它放入一個輔助類來進行修改。但我的核心問題圍繞着這裏使用的實際對象。是否有這種矯枉過正或不必要?

PageData sp = DataFactory.Instance.GetPage(PageReference.StartPage); 
PageRouteHelper pageRouteHelper = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<PageRouteHelper>(); 
PageData currentPage = pageRouteHelper.Page; 
PageData pp = DataFactory.Instance.GetPage(currentPage.ParentLink); 

List<PageData> navList = new List<PageData>(); 
while (pp.ContentLink != sp.ContentLink) 
{ 
    if (pp.HasTemplate() && pp.VisibleInMenu && pp.IsVisibleOnSite()) 
    { 
     navList.Add(pp); 
    } 
    pp = DataFactory.Instance.GetPage(pp.ParentLink); 
} 
navList.Add(pp); 
navList.Reverse(); 

sp = null; 
pageRouteHelper = null; 
currentPage = null; 
pp = null; 

以上是在視圖中的代碼塊。然後通過navList一個簡單的循環週期,就像這樣:

@foreach (PageData page in navList) 
{ 
    <li>@Html.PageLink(page)</li> 
} 

我不喜歡的兩倍代碼採用DataFactory.Instance.GetPage,這3個PageData對象(加上PageData列表)實例化來執行此任務。擁有50多個屬性和大約40個方法,PageData對象看起來很重要。

這對我來說太過於矯枉過正,尤其是當我們從每個PageData對象中需要的是它的可見性,錨點URL和錨文本時。我真的很想避免代碼臃腫,特別是在這個EbcServer網站的大部分頁面上呈現的這個Breadcrumb控件上。

感謝您的幫助。

+0

此站點版本8.0.0.0。 –

回答

3

爲了您的擔憂PageData

PageData對象(你在自己的系統(「ArticlePage」,「末頁」或其他人)創建的所有衍生工具在內存中緩存相比「FooBar的風格」的教程。但是在現實生活中,您可以輕鬆地處理數百個類,以便在現代服務器上加載單個頁面,並添加一些輸出緩存或其他緩存解決方案,並且在實踐中成爲一個非問題。 Get<T>(...)GetChildren<T>(...)對於每一個請求都是非常好的。

確實,它具有負載的屬性,但對於一個給定的頁面對象,最好擁有「一個真相源」,而不是對整個站點中的每一個用法都進行自定義查詢。突然間,你會想要一些你定義的文本屬性。或訪問訪問控制列表。或者檢查它的內容類型。或編輯並保存。

例如:在一個簡單的菜單,你可能都希望它的名字,可能是某種形式的「介紹」,「節選」或「MainIntro」屬性,這是ContentLink(創建<a href=...>實際值),也,您通常會處理特定類型的項目,而不是基類,這可以打開更多由您自己定義的屬性。

所以沒有,這是沒有必要的,也沒有矯枉過正。這是常見的做法,它的工作原理。如果你不想在編輯時看到所有的屬性,你可以簡單地把它們作爲IContent。但請注意,它背後的實現仍然是PageData對象(或者是您正在檢索的實際頁面類型的運行時生成的代理類)。

除此之外:

  • 你不應該把代碼加載這樣的觀點。程序邏輯屬於控制器或其他類。這與Episerver無關,更多的是通用的最佳實踐。
  • 你應該避免訪問DataFactory,並且相當(無論是作爲一個構造函數的參數,或者通過ServiceLocator.Current.GetInstance<IContentLoader>通過依賴注入獲取IContentLoader

這裏有一個靈活且簡單的方法麪包屑:

創建一個文件像HtmlHelperExtensions.cs,其中包含:

public static IHtmlString BreadCrumbs(
    this HtmlHelper helper, 
    ContentReference currentPage, 
    Func<MenuItemViewModel, HelperResult> itemTemplate = null, 
    bool includeCurrentPage = true, 
    bool requireVisibleInMenu = true, 
    bool requirePageTemplate = true) 
{ 
    itemTemplate = itemTemplate ?? GetDefaultItemTemplate(helper); 
    Func<IEnumerable<PageData>, IEnumerable<PageData>> filter = GetFilter(requireVisibleInMenu, requirePageTemplate); 
    var menuItems = new List<MenuItemViewModel>(); 
    var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>(); 

    var currentPageData = contentLoader.Get<PageData>(currentPage); 
    ContentReference parentLink = currentPageData.ParentLink; 

    if (includeCurrentPage) 
     menuItems.Add(CreateBreadCrumb(currentPageData, currentPage, contentLoader, filter)); 

    var pages = new List<PageData>(); 

    do 
    { 
     var page = contentLoader.Get<PageData>(parentLink); 
     pages.Add(page); 
      parentLink = page.ParentLink; 
     } while (!parentLink.Equals(ContentReference.RootPage)); 

    menuItems.AddRange(
      pages.FilterForDisplay(requirePageTemplate, requireVisibleInMenu) 
       .Select(page => CreateBreadCrumb(page, currentPage, contentLoader, filter))); 

    menuItems.Reverse(); 

    return menuItems.List(itemTemplate); 
} 

private static MenuItemViewModel CreateBreadCrumb(
    PageData page, 
    ContentReference currentContentLink, 
    IContentLoader contentLoader, 
    Func<IEnumerable<PageData>, IEnumerable<PageData>> filter) 
{ 
    var menuItem = new MenuItemViewModel(page) 
    { 
     Selected = page.ContentLink.CompareToIgnoreWorkID(currentContentLink), 
     HasChildren = new Lazy<bool>(() => filter(contentLoader.GetChildren<PageData>(page.ContentLink)).Any()) 
    }; 
    return menuItem; 
} 

private static Func<IEnumerable<PageData>, IEnumerable<PageData>> GetFilter(bool requireVisibleInMenu, bool requirePageTemplate) 
{ 
    return pages => pages.FilterForDisplay(requirePageTemplate, requireVisibleInMenu); 
} 

而且,在你看來,

@helper BreadCrumb(MenuItemViewModel breadCrumbItem) 
{ 
    <li> 
     @if (breadCrumbItem.Page.HasTemplate() && !breadCrumbItem.Page.ContentLink.CompareToIgnoreWorkID(Model.CurrentPage.ContentLink)) 
     { 
      @Html.PageLink(breadCrumbItem.Page) 
     } 
     else 
     { 
      @breadCrumbItem.Page.Name 
     } 
    </li> 
} 

<nav> 
    <ul> 
     @Html.BreadCrumbs(Model.CurrentPage.ContentLink, BreadCrumb, requireVisibleInMenu: false, includeCurrentPage: false) 
    </ul> 
</nav> 
+1

謝謝!我真的很感激你的答案有多徹底。關於視圖中的大量代碼,我完全同意。這是繼承的代碼。我們的團隊也在解決網站其他領域的反模式問題。您的示例將有助於我們正在優化的其他導航控件。非常感謝。 –