Loading Web Navigation from XML with MVC3 Partial Views, C# .NET

modified

Introduction

The navigation menu is a common control on almost every MVC3 C# ASP .NET web site, containing sets of links for navigating to various portions of the web site. Traditionally, menu navigation links are statically embedded within an MVC3 control or directly within the HTML of a web page. Occasionally, the need may arise for navigation links to be driven from an outside data source, such as a database, XML file, or CMS (content management system). In particular, CMS content management systems often allow users to dynamically configure web site content, including navigational links. A user may choose to add or remove top-level navigation items, which in turn, instructs the CMS system to publish a differing set of navigation data. In this scenario, we would need to design our MVC3 C# ASP .NET web application to dynamically load the navigational items from a file or data-store, for display in the MVC view.

In this tutorial, we’ll walk through creating a simple top-level and secondary-level menu navigation system in MVC3. Our sub-menu navigation links will be dynamically loaded from an XML file data-source and rendered in the MVC view. We’ll create an MVC3 partial view (user control) for rendering the navigation.

Home page web navigation, loaded from XML file.

Secondary page with web navigation loaded from XML file.

A Hard-Coded Menu System

In the traditional MVC web site implementation, the menu links, top-level, and secondary navigation items would typically be hard-coded as part of the web site template (ie., MasterPage). For example, a sample templated menu navigation might appear as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ul id="top-navigation">
<li><a href="/">Home</a>
<ul>
<li><a href="/Home/Link1">Link 1</a></li>
<li><a href="/Home/Link2">Link 2</a></li>
</ul>
</li>
<li><a href="/About">About</a>
<ul>
<li><a href="/About/Link1">Link 1</a></li>
<li><a href="/About/Link2">Link 2</a></li>
<li><a href="/About/Link3">Link 3</a></li>
</ul>
</li>
<li><a href="/Help">Help</a></li>
</ul>

In the above example, we’re using a basic jQuery menu script to implement a mouse-over drop-down menu, containing a top level list of links (Home, About, and Help) and a secondary list of links under each top-level item (Link 1, Link 2, etc). Upon mousing over the top-level navigation item, a drop-down will display containing the sub-menu links.

Adding Some Dynamic Magic to Our Menu System

The above menu system is a hard-coded template implementation; meaning all navigational links are already coded within the HTML. We can actually abstract out the sub-menu navigational items to a separate MVC3 partial view user control, allowing us to then load the links from an outside datasource. We can simply replace the sub-menu link HTML with an MVC3 partial view render tag. Our partial view will then dynamically load the required sub-menu links for that menu item. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
<ul id="top-navigation">
<li><a href="/">Home</a>
<ul>
@{ Html.RenderAction("DisplaySubMenuNavigation", "Home"); }
</ul>
</li>
<li><a href="/About">About</a>
<ul>
@{ Html.RenderAction("DisplaySubMenuNavigation", "About"); }
</ul>
</li>
<li><a href="/Help">Help</a></li>
</ul>

Notice in the above code, the secondary-level menu items have been replaced by a call to Html.RenderAction. The render action will execute our DisplaySubMenuNavigation helper method and pass in the top-level navigation item to return links for. Our helper method will return the HTML from its associated partial view, which contains the sub-menu HTML format, as follows:

1
2
3
4
5
6
@model NavigationTest.Models.SubMenuNavigationModel

@foreach (var link in Model.Links)
{
<li><a href="@link.Value">@link.Key</a></li>
}

The above partial view will simply loop through all sub-menu links for the parent menu item, and insert a line of HTML for each, dynamically building up the menu. The links are populated from the model (which can originate from a text file, XML, database, or even code). In this manner, we can dynamically load navigation menu links based upon the parent item, fully supporting CMS integration in the menu.

Plugging In an XML File

We an store the contents for our web page menu links in a variety of formats. For this example, we’ll store the navigation within an XML file, as follows:

1
2
3
4
5
6
7
8
9
10
11
12
<nodes>
<node title="Home">
<link title="Link 1" href="/Home/Link1" />
<link title="Link 2" href="/Home/Link2" />
</node>
<node title="About">
<link title="Link 1" href="/About/Link1" />
<link title="Link 2" href="/About/Link2" />
<link title="Link 3" href="/About/Link3" />
</node>
<node title="Help" />
</nodes>

The Base Controller

With our HTML views laid out, we can begin our C# ASP .NET MVC3 project by creating our root MVC controllers. Our menu system will contain three main topics: Home, About, and Help. Therefore, we’ll use three controllers, one for each. Since the controllers for this project will all implement the DisplaySubMenuNavigation helper method, we can create a base MVC3 controller class for code reuse, as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
public abstract class BaseNavigationController : Controller
{
public ActionResult Index()
{
return View();
}

public ActionResult DisplaySubMenuNavigation()
{
return PartialView("~/Views/Navigation/SubMenuNavigation.cshtml",
SubMenuNavigationManager.Load(ControllerContext.RouteData.Values["controller"].ToString()));
}
}

Our concrete C# MVC3 .NET controllers can inherit from the base controller and define their specific content, as follows:

1
2
3
4
5
6
7
8
9
10
11
12
public class HomeController : BaseNavigationController
{
public ActionResult Link1()
{
return View();
}

public ActionResult Link2()
{
return View();
}
}

The other controllers will follow the same pattern. They’ll simply return empty views in this example, but inheriting the same sub-menu navigation loading helper method.

Creating the Views

The associated view for each controller will use the main Layout.cshtml template for its layout, as defined as the default master template in the ViewStart.cshtml. In this example, we’ll also be displaying the sub-menu navigation items along the left-side of the web page when a sub-menu page is selected. Therefore, our sub-menu view pages will use a different template than the default one. We can define this by including a tag in the sub-menu views as follows:

Link1.cshtml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@{
ViewBag.Title = "About Link1";
Layout = "~/Views/Shared/_SubMenu.cshtml";
}

@section Title
{
About Link1
}

@section Content
{
About Link 1 Content
}

Creating our Sub-Menu View Layout

In the above sub-menu view, we’re using a new layout, which includes the sub-menu navigation links along the left-side of the web page. We can define this new layout as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}

<div style="float: left; padding: 0 30px 0 0;">
<ul id="left-navigation">
@{ Html.RenderAction("DisplaySubMenuNavigation",
@HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString()); }
</ul>
</div>

<h2>@RenderSection("Title", false)</h2>

@RenderSection("Content", false)

Note in the above code, our new layout also inherits from the default Layout.cshtml. It just defines additional view HTML to include in addition to the default layout. This layout’s HTML code includes a server-side call to DisplaySubMenuNavigation and passes in the current controller’s name. This allows the layout view to display the current secondary-menu links, for the selected parent menu item, within the page. For example, when the user navigates to a link under the “About” menu item, the links included in the drop-down will be displayed along the left-side of the page (since the controller name “About” will be passed to the DisplaySubMenuNavigation method).

The Sub-Menu Navigation Model

Since our sub-menu view will be rendering data from a model, we can define the sub-menu navigation model class as follows:

1
2
3
4
5
6
7
8
9
public class SubMenuNavigationModel
{
public Dictionary<string, string> Links { get; set; }

public SubMenuNavigationModel()
{
Links = new Dictionary<string, string>();
}
}

The above model is fairly simple. It contains a list of links to be included under the parent menu item. The links can be populated from any data-source, and then rendered in the partial view for our C# .NET MVC3 secondary-level menu navigation.

In our base controller class, our helper method DisplaySubMenuNavigation calls a manager class method to load the sub-menu links for the supplied parent menu item (specified by controller name). We can define our manager class, which loads the secondary-level links from an XML file, as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static SubMenuNavigationModel Load(string controllerName)
{
SubMenuNavigationModel leftNavigation = new SubMenuNavigationModel();

// Load the navigation XML document.
XDocument xDoc = XDocument.Load(HttpContext.Current.Server.MapPath(@"~/Content/navigation.xml"));

// Select all links for our navigation node (top-level menu item).
var links = from node in xDoc.Descendants("node")
where (string)node.Attribute("title") == controllerName
select node.Elements("link");

if (links.Count() > 0)
{
// Create a link for each item.
foreach (var link in links.First())
{
leftNavigation.Links.Add((string)link.Attribute("title"), (string)link.Attribute("href"));
}
}

return leftNavigation;
}

In the above code, we’re using LINQ to XML to load the list of web site navigation links from an XML file. We could easily modify our code to load the links from an outside data source, such as a database, CMS content management system, or even a web service. Third-party tools, such as a CMS content management system, could easily modify the backing data-source, to dynamically change the C# ASP .NET MVC3 menu navigation links on the web site. Since the HTML formatting of the links is included within the partial view, changing the style of the links themselves can be maintained outside of the code.

Bringing it All Together

The final result is a C# ASP .NET MVC3 web site that loads its secondary menu navigation links from an outside data source. If a new sub-menu item is required, we can modify the backing datasource to automatically include the new link in both the drop-down menu and the left-side navigation.

We’ve facilitated the ability for third-party tools, services, and CMS content management system to maintain and modify our web site’s navigational structure. By implementing a flexible framework, C# ASP .NET MVC3 web applications can be customized and more easily maintained by business users and system support.

See It In Action

Download @ GitHub

You can download the project source code on GitHub by visiting the project home page.

About the Author

This article was written by Kory Becker, software developer and architect, skilled in a range of technologies, including web application development, machine learning, artificial intelligence, and data science.

Share