2017-01-09 2 views
1

Ich arbeite daran, die Leistung einer MVC EpiServer-Website zu verbessern und war auf der Suche nach Anleitungen zur Codeoptimierung für eine Breadcrumb-Steuerung. Wir versuchen, den Speicherbedarf in IIS dieser Site bei der Ausführung zu reduzieren.Wie können wir diesen Breadcrumb-Navigationscode von EpiServer besser optimieren?

Derzeit ist dieser Code in einer Ansicht, die ich ändern möchte, indem es in eine Hilfsklasse platziert. Aber meine Kernfrage dreht sich um die tatsächlichen Objekte, die hier verwendet werden. Ist das alles übertrieben oder unnötig?

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; 

Das obige ist in einem Codeblock in der Ansicht. Dann eineine einfachen Schleifendurchläufe durch den navlist, etwa so:

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

Ich mag nicht, dass der zweimal Code beschäftigt DataFactory.Instance.GetPage, und die 3 Pagedata-Objekte (plus eine Pagedata Liste) instanziiert erhalten diese Aufgabe auszuführen. Mit 50+ Eigenschaften und ungefähr 40 Methoden sieht das PageData-Objekt gewichtig aus.

Das fühlt sich für mich wie Overkill an, besonders wenn wir von jedem PageData-Objekt die Sichtbarkeit, die Anker-URL und den Ankertext erwarten. Ich würde wirklich Code Bloat vermeiden wollen, besonders bei diesem Breadcrumb-Steuerelement, das auf den meisten Seiten dieser EpiServer-Site gerendert wird.

Danke für Ihre Hilfe.

+0

Diese Website hat die Version 8.0.0.0. –

Antwort

3

Für Ihre Bedenken über PageData:

PageData Objekte (und alle Derivate Sie in Ihrem eigenen System ("ArticlePage", "ListPage" oder andere) erstellen, werden im Arbeitsspeicher zwischengespeichert Im Vergleich zu "FooBar-style" Tutorial. Beispiel Klassen, es ist enorm, aber im wirklichen Leben, können Sie leicht Hunderte von ihnen für eine einzelne Seite laden auf einem modernen Server. Fügen Sie einige Ausgabe-Caching oder andere Caching-Lösungen, und es wird ein Nicht-Problem in der Praxis Bündel von Get<T>(...) und GetChildren<T>(...) für jede Anfrage ist völlig in Ordnung.

Es ist wahr, dass es viele Eigenschaften hat , aber es ist wahrscheinlich besser, eine "Quelle der Wahrheit" für ein bestimmtes Seitenobjekt zu haben, als benutzerdefinierte Abfragen für jede einzelne Verwendung in Ihrer gesamten Site zu haben. Plötzlich wirst du eine Texteigenschaft haben wollen, die du definiert hast. Oder greifen Sie auf die Zugriffskontrollliste zu. Oder überprüfen Sie den Inhaltstyp. Oder editiere es und speichere es.

Zum Beispiel: In einem einfachen Menü, werden Sie beide wahrscheinlich seinen Namen wollen, möglicherweise eine Form von „Intro“, „Auszug“ oder „MainIntro“ Eigenschaft ist es ContentLink (der Istwert für <a href=...> erstellen) Auch , behandeln Sie oft Elemente eines bestimmten Typs und nicht die Basisklasse PageData, die zu noch mehr Eigenschaften führt, die Sie selbst definieren.

So keine, ist es nicht unnötig noch zu viel Aufwand. Es ist üblich, und es funktioniert. Wenn Sie während der Bearbeitung nicht alle Eigenschaften anzeigen möchten, können Sie sie einfach als IContent behandeln. Beachten Sie jedoch, dass die dahinterstehende Implementierung immer noch PageData Objekte (oder vielmehr Laufzeit-generierte Proxy-Klassen für den tatsächlichen Seitentyp, den Sie abrufen) ist.

Abgesehen davon:

  • Sie sollten nicht in einer Ansicht wie viel Code setzen. Programmlogik gehört zu Controllern oder anderen Klassen. Dies hat nichts mit Episerver zu tun, sondern eher mit allgemeinen Best Practices.
  • sollten Sie vermeiden DataFactory Zugriff und eher IContentLoader über Dependency Injection (entweder als Konstruktorparameter abrufen oder über ServiceLocator.Current.GetInstance<IContentLoader>

Hier ist eine flexible und einfache Möglichkeit, Paniermehl zu tun.

Erstellen Sie eine Datei wie HtmlHelperExtensions.cs, welche enthält:

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); 
} 

Und aus Ihrer Sicht;

@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

Vielen Dank! Ich weiß es wirklich zu schätzen, wie gründlich deine Antwort ist. Hinsichtlich der Menge an Code in der Ansicht stimme ich völlig zu. Dies ist ein vererbter Code. Unser Team befasst sich auch mit Anti-Patterns in anderen Bereichen der Site. Ihr Beispiel wird uns bei anderen Navigationssteuerelementen helfen, die wir ebenfalls optimieren. Vielen Dank. –

Verwandte Themen