我正在努力改善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>