我正在努力改善MVC EpiServer网站的性能,并且正在寻找有关面包屑控件代码优化的一些指导。我们正在尝试减少该站点运行时在IIS中的内存占用。

当前,此代码处于视图中,我打算通过将其放入帮助器类中进行修改。但是我的核心问题是围绕这里使用的实际对象。有这种过度杀伤力还是不必要的?

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和锚文本时。我真的很想避免代码肿,尤其是在此EpiServer网站大部分页面上呈现的Breadcrumb控件上。

谢谢你的帮助。

最佳答案

对于您对PageData的关注:

PageData对象(以及您在自己的系统(“ ArticlePage”,“ ListPage”或其他系统中创建的所有派生对象))被缓存在内存中。与“ FooBar风格”的教程示例类相比,它很有趣,但是在现实生活中,您可以可以轻松地在现代服务器上的单个页面加载中处理数百个;添加一些输出缓存或其他缓存解决方案,在实践中就变成了非问题。针对每个请求执行一堆Get<T>(...)GetChildren<T>(...)很好。

它确实具有大量的属性,但是对于给定的页面对象来说,拥有“一个真实的来源”可能要比对整个站点中的每种用法进行自定义查询更好。突然,您将需要一些已定义的文本属性。或访问访问控制列表。或检查它的内容类型。或编辑并保存。

例如:在一个简单的菜单中,您可能都想要它的名称,可能是某种形式的“ Intro”,“ Excerpt”或“ MainIntro”属性,它是ContentLink(为<a href=...>创建实际值) ,您通常会处理特定类型的项目,而不是PageData基类,这会打开您自己定义的更多属性。

所以不,这不是不必要的,也不是矫over过正。这是常见的做法,并且有效。如果您只是不想在编辑时看到所有属性,则可以将它们作为IContent处理。但是请注意,其背后的实现仍将是PageData对象(或者是您正在检索的实际页面类型的运行时生成的代理类)。

除此之外:


您不应在视图中放入类似的代码。程序逻辑属于控制器或其他类。这与Episerver无关,更多与常规最佳做法无关。
您应该避免访问DataFactory,而是通过依赖项注入(作为构造函数参数或通过IContentLoader)检索ServiceLocator.Current.GetInstance<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>

09-06 01:43