Recently we built a new navigation macro using razor and the embeded content picker. The user assosiates the categories they want to appear in the main navigation using the embeded content picker, the razor script then goes and pulls the nodes and node children to build the navigation with dropdowns.
The problem that we have run into is that it takes up to 10 seconds to load. We can cache the macro which helps, but we really want to know if there is a better way to increase the performance of this razor script.
@{ @*get the Home Node parameter; this is the ID of the node that contains the navigations*@ var homeNode = String.IsNullOrEmpty(Parameter.homeNode) ? @Model.NodeById(1053) : @Model.NodeById(Parameter.homeNode); <ul class="main_nav clearfix"> @foreach(dynamic navLink in homeNode.mainNavigation) { var link = string.IsNullOrEmpty(@navLink.contentPickerLink.InnerText) ? "#" : @Model.NodeById(navLink.contentPickerLink.InnerText).Url; var linkNodeID = string.IsNullOrEmpty(@navLink.contentPickerLink.InnerText) ? "" : @Model.NodeById(navLink.contentPickerLink.InnerText); var maxSubNavLevel = string.IsNullOrEmpty(@navLink.maxSubNavLevel.InnerText) ? 1 : int.Parse(@navLink.maxSubNavLevel.InnerText); <li> <a href="@link">@navLink.linkText.InnerText</a> @*if this node has children then run this function again to create a sub menu*@ @if (link != "#"){ if (@linkNodeID.Children.Count() > 0 && ! @linkNodeID.umbracoHideChildren) { @traverse(@linkNodeID , 1, @maxSubNavLevel) } } </li> } </ul> } @helper traverse(dynamic parent, int subNavCount, int maxSubNavLevel ) { <ul class="clearfix"> @*loop through all nodes where umbracoNaviHide is not true*@ @foreach (var node in parent.Children.Where("Visible")) { @*create a class of "current" if this is the node you are on*@ var selected = Array.IndexOf(Model.Path.Split(','), node.Id.ToString()) >= 0 ? " class=\"current\"" : ""; @*if there is no umbracoRedirect, then use the Url of the node*@ var navigationURL = String.IsNullOrEmpty(@node.umbracoRedirect) ? @node.Url : @node.umbracoRedirect; @*if there is no specified navTitle, then use the Name of the node*@ var navigationTitle = String.IsNullOrEmpty(@node.navigationTitle) ? @node.Name : @node.navigationTitle; @*create a class of "arrow" for items with a sub menu*@ var subMenuArrow = @node.Children.Count() > 0 && subNavCount < maxSubNavLevel && !@node.umbracoHideChildren ? " class=\"arrow\"" : ""; var newSubNavCount = subNavCount + 1; <li@Html.Raw(selected)> <a href="@navigationURL"@Html.Raw(subMenuArrow)>@navigationTitle</a> @*if this node has children, we have not reached maxLevels, and umbracoHideChildren is not true, then run this function again to create a sub menu*@ @if (@node.Children.Count() > 0 && subNavCount < maxSubNavLevel && !@node.umbracoHideChildren) { @traverse(node,newSubNavCount,maxSubNavLevel ); } </li> } </ul> }
Navigation Performance
Recently we built a new navigation macro using razor and the embeded content picker. The user assosiates the categories they want to appear in the main navigation using the embeded content picker, the razor script then goes and pulls the nodes and node children to build the navigation with dropdowns.
The problem that we have run into is that it takes up to 10 seconds to load. We can cache the macro which helps, but we really want to know if there is a better way to increase the performance of this razor script.
Hi Chuck,
One thing that I've found (and seen across forums), not just from Umbraco but Razor/LINQ in general if you change:
to:
@node.Children.Any()
This is quicker as my understanding is the .Count() has to iterate through all the items.
Probably wont solve the whole speed issues, also i recommend installing the mini profiler project http://our.umbraco.org/projects/developer-tools/miniprofiler-for-umbraco will help you narrow the issue more.
Tom
Hey Tom,
I can't seem to get .Any() to work. Is this available in 4.8?
With this code I get the error: Error loading MacroEngine script (file: MainNavigation.cshtml)
is working on a reply...