Once you’ve got your sitemap
correctly configured and setup,
you will be looking to use some of the features of a Sitemap – for
example, breadcrumbs. In this post we will start with an empty MVC3
project, and add the asp.net sitemap provider, a few controller actions
and corresponding views, and we will have the provider produce some
breadcrumbs for us.
Setup
Lets start from an
Empty MVC3 project. Fire up Visual Studio. Create a new Asp.Net MVC3 Web application. I’m going to call mine SitemapDemo:
For the sake of this demonstration, I have selected an empty template and have chosen Razor as my view engine.
Now before we go any further, lets go ahead and install the
NuGet package. Select View > Other Windows and then select “Package Manager Console”:
This will then dock the Package Manager Console somewhere into your
view. In order to add the Asp.net MVC sitemap provider to the current
project, we need to enter the following command into the Package Manager
Console, and hit enter:
PM> Install-Package MvcSiteMapProvider
This command will then download the necessary files (dlls, cshtml
files) and add them into your MVC project. This could take a few minutes
depending on your connection. If this has been successful, your Package
Manager Console should give you an output similar to the following:
PM> Install-Package MvcSiteMapProvider
Successfully installed 'MvcSiteMapProvider 3.1.0.0'.
Successfully added 'MvcSiteMapProvider 3.1.0.0' to SitemapDemo.
PM>
Now lets take a look at what exactly the NuGet package manager has added to our project:
- SitemapDemo > References > MvcSiteMapProvider – This is the reference to the MvcSiteMapProvider dll
- SitemapDemo > Mvc.sitemap – This file will be used to describe our MVC3 website in XML nodes
- SitemapDemo > Views > Shared > DisplayTemplates > MenuHelperModel.cshtml
- SitemapDemo > Views > Shared > DisplayTemplates > SiteMapHelperModel.cshtml
- SitemapDemo > Views > Shared > DisplayTemplates > SiteMapNodeModel.cshtml
- SitemapDemo > Views > Shared > DisplayTemplates > SiteMapNodeModelList.cshtml
- SitemapDemo > Views > Shared > DisplayTemplates > SiteMapPathHelperModel.cshtml
- SitemapDemo > Views > Shared > DisplayTemplates > SiteMapTitleHelperModel.cshtml
As we’re using Razor as our view engine, we can go ahead and delete
the asax files that have been added to the SitemapDemo > Views >
Shared > DisplayTemplates folder. Here’s how your solution should now
look:
Now that’s the install over. Let’s add a half decent set of
controller actions and views to the site before we go on to playing with
the SiteMapProvider. The point of this is to capture the kind of
structure that you would find in a typical website.
Important
The MVC Sitemap provider will fail silently in some fashion if we try
to force it to work with controller actions that either don’t exist or
that point to non existent views. This is why we are doing this stage
first.
All sites have a homepage, so lets add this first. Right click on
your Controllers folder, and add a controller called “HomeController”.
Lets leave the scaffolding options blank:
Once your controller is created and open, right click inside the Index action and select “Add View…”
In the Add View dialogue that pops up, just go a head hit add.
Nothing will need changing. Now lets change the text inside the created
page’s h2 tag on the page – something like “Index – this is the home
page” will do.
And now lets add another controller in the same way that we added the
HomeController. Let’s call it NewsController. Update the newly created
news controller to contain an additional action result called “Sports”:
02 | using System.Collections.Generic; |
07 | namespace SitemapDemo.Controllers |
09 | public class NewsController : Controller |
14 | public ActionResult Index() |
21 | public ActionResult Sports() |
Now, lets add a view for each of our newly created NewsController
actions. Lets do this in the same way that we added the view for the
home page – by right clicking within the body of each controller action.
Again, we can simply leave all of the defaults in the “Add View”
dialogue and just hit “Add” for both views.
Now edit the h2 tag on the News Index cshtml file to read “News
Index”. Lets also edit the h2 tag on the News Sports cshtml file to read
“Sports News”.
Let’s now add one more Controller for illustration – AboutController.
Once created, you can leave the controller unchanged, and can add a
view for the Index controller action. This time, lets change the h2 to
tags to read “About Page”.
As we have now added 4 pages to our website, it’s now worth just
testing them out before we start integrating the Site Map Provider. Hit
the debug button – below are screen shots and their corresponding URLs:
localhost:xxxx
localhost:xxxx/News
localhost:xxxx/News/Sports
localhost:xxxx/About
Ok, so we’ve now got a small site with a little bit of a structure. Lets represent that structure in an easy diagram:
Visualising our layout like this will really help us describe our
site’s structure in our Mvc.sitemap file correctly. Our Index page is
our wrapper for the entire site as it is the page that sits in the root,
and is the first port of call into the site.
Now lets get into configuring our Sitemap. Lets start by editing our
Mvc.sitemap file, which is in the root of our project. This file
contains all of the xml nodes needed to represent your controller and
action combinations.
Edit your Mvc.Sitemap file so that it is the same as the listing below:
1 | xml version = "1.0" encoding = "utf-8" ?>
|
3 | < mvcSiteMapNode title = "Home" controller = "Home" action = "Index" > |
4 | < mvcSiteMapNode title = "News" controller = "News" action = "Index" > |
5 | < mvcSiteMapNode title = "Sports News" controller = "News" action = "Sports" /> |
7 | < mvcSiteMapNode title = "About" controller = "About" action = "Index" /> |
We have now represented our website structure / workflow in the
MVC.Sitemap file. A classic “gotcha” here is forgetting that your entire
site is wrapped in a node that represents your homepage. Your sitemap
file must contain this node – after all, your website’s homepage is the
page that the client sees as the root of everything. So even though the
Index action is actually at
yourwebsite/Index, the client will typically see it just as
yourwebsite/. The rest of the structure should make sense when compared to the website navigation diagram, earlier in this post.
Adding Navigation
Now that we’ve got some controllers and actions setup, and our site
structure described properly in our Mvc.Sitemap file, lets add some
navigation to all pages.
Open up your _Layout.cshtml partial, located in the Views/Shared
folder. Update the listing so that the code between the body tags looks
like this:
2 | @Html.MvcSiteMap().Menu(false, true, true) |
We are now calling the MvcSiteMap library and telling it to output
the website’s navigation on every page. The parameters specified mean
that:
- We don’t want it to start from the current node (changing this to true will break it!)
- We want the starting node to appear in child level
- We want to show the starting node. Setting this to false will hide the parental “Home” node
And now if we run our application, we should see the navigation laid out on every page, complete with links:
Editing the navigation appearance
So now we’ve managed to output a simple navigation onto all pages of
our website. If you want to change any styling, or how the navigation is
displayed, simply alter the code in
Views/Shared/DisplayTemplates/MenuHelperModel.cshtml. Lets make a simple
change and add an inline style to change our bullet points from circles
to squares:
2 | @foreach (var node in Model.Nodes) { |
3 | < li style = "list-style-type:square;" >@Html.DisplayFor(m => node) |
4 | @if (node.Children.Any()) { |
5 | @Html.DisplayFor(m => node.Children) |
You can now hit refresh in your browser without needing to re-compile. Your News index page should now look like this:
Breadcrumbs
We can add breadcrumbs in a similarly easy fashion. Let’s open up our _Layout.cshtml partial and edit the listing:
2 | @Html.MvcSiteMap().Menu(false, true, true) |
3 | < p >Start of Breadcrumbs:p > |
4 | @Html.MvcSiteMap().SiteMapPath() |
Now all pages on our site will have a handy set of breadcrumb links:
Similarly, if we want to customise the presentation of our
breadcrumbs, we need to change the
Views/Shared/DisplayTemplates/SiteMapPathHelperModel.cshtml file.
Dynamic URLs / Parametered URLs
Every real site will need to employ a dynamic / Parametered URL at
some point. Incorporating a dynamic URL into the MVC Sitemap is
straightforward when you know how. Lets start by adding a new action to
the NewsController:
3 | public ActionResult Article( int id) |
Now lets add a view – right click anywhere within the new action and
select “Add View…”. Again, just hit Add – we don’t need to change any of
the options. Now update the newly created Article.cshtml file with the
following:
2 | ViewBag.Title = "Article"; |
5 | < h2 >Viewing Article @ViewBag.idh2 > |
Now lets browse to localhost:xxxx/News/Article/1234:
Note that this new page does not appear anywhere in our sitemap, and that the breadcrumbs are totally empty.
In order to add the page into our navigation, we must first decide
where it needs to go. I’d like this page to sit underneath the News
section. So lets edit our Mvc.Sitemap file and add a Key attribute to
the “News” node. This is simply to give it a unique identifier:
1 | < mvcSiteMapNode title = "News" controller = "News" action = "Index" key = "News" > |
Now we need to decorate our controller action with some attributes
that tell it where to insert the action in the site’s structure. Update
your Article action in your News controller:
3 | [MvcSiteMapNode(Title = "Article" , ParentKey = "News" )] |
4 | public ActionResult Article( int id) |
Now lets compile and browse to localhost:xxxx/News/Article/1234: