Comment mettre en place une navigation à l'aide du SiteMap

Louis-Guillaume MORAND

- Titre : Comment mettre en place une navigation à l'aide du SiteMap

- Auteur : Louis-Guillaume MORAND

- Parution : 1 mai 2009

- Licence : Copyright ® 2009 Equipe dotnet. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- 0. Introduction

- 1. Créer un SiteMap

- 2. Understanding the SiteMap API

- 3. Creating a Menu HTML Helper

- 4. The Importance of Canonical URLs

- 5. Summary

0 - Introduction

Un SiteMap vous permet de décrire la structure de navigation d'un site Web séparément de la façon dont sont exposées les URLs à travers les contrôleurs et les contrôleurs d'action. Un SiteMap vous permet de décrire comment les pages dans une application Asp.Net MVC sont reliées entre elles, pour un objectif de navigation.
Vous pouvez utiliser un SiteMap, en combinaison avec l'API SiteMAp, pour générer les liens de navigation pour votre site Web. Par exemple, vous pouvez utiliser les SiteMaps pour générer menus, onglets, arborescences, liens précédent et suivant ou encore un fil d'Ariane. Dans ce tutoriel, je vais démontrer comment un simple HTML Helper Menu(), peut générer automatiquement les liens depuis un SiteMap.

Dans une application Asp.Net Web Forms, vous pouvez utiliser une fonctionnalité des SiteMap nommée "découpage sécurisé", pour n'afficher que les liens de navigation qu'un utilisateur est autorisé à voir. Par exemple, lorsque le découpage sécurisé est activé, vous pouvez cacher le lien Administration pour chaque utilisateur qui n'est pas autorisé à afficher la page Administration. Par défaut, le découpage sécurisé n'est pas supporté avec une application Asp.Net MVC.

1 - Créer un SiteMap

La façon la plus facile de créer un SiteMap est de créer un fichier XML qui décrit la structure de navigation de votre site Web. Vous pouvez créer un nouveau SiteMap dans Visual Studio en sélectionnant le menu Projet > Ajouter un nouvel élément et ajouter un SiteMap (voir Image 1). Pour que votre SiteMap fonctionne avec d'autres configurations, vous devez nommez votre fichier Web.SiteMap et vous devez le placer à la racine de votre application.

An XML SiteMap file contains a root <siteMap> element that contains one or more <siteMapNode> elements. You can nest one <siteMapNode> element within another <siteMapNode> element. You use these <siteMapNode> elements to describe the relationship between the pages in your ASP.NET MVC application.

Each <siteMapNode> element can have the following attributes (this is not a complete list):
- url – L'URL de la page. Utilisée pour créer l'URL d'un lien de navigation,
- title – Le titre de la page,
- description – La description de la page,
- resourceKey – A resource key that you can use to localize the siteMapNode to multiple languages
- siteMapFile – Le chemin vers un autre fichier SiteMap. Utilisé lorsqu'un SiteMap est découpé en plusieurs sous-fichiers.

XML documents are case-sensitive. So, there is a difference between <siteMapNode> and <SiteMapNode>.

The SiteMap file in Listing 1 contains four <siteMapNode> elements. It describes a website that contains a Home page and four top-level pages entitled Products, Services, and About.

Web.sitemap

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode
url="~/"
title="Home"
description="The Home Page">
<siteMapNode
url="~/Product/Index"
title="Products"
description="Our Products" />
<siteMapNode
url="~/Service/Index"
title="Services"
description="Our Services" />
<siteMapNode
url="~/Home/About"
title="About"
description="About Us" />

</siteMapNode>
</siteMap>

2 - Understanding the SiteMap API

You interact with a SiteMap through the SiteMap API. The SiteMap API is represented by the static SiteMap class. Because the SiteMap class is static, you can access the class from anywhere within an ASP.NET MVC application without doing anything special (you can access the class directly within controllers, views, helpers, model classes, and so on).

The static SiteMap class has two important properties:
- CurrentNode – Returns the SiteMapNode that corresponds to the user's current location in the website.
- RootNode – Returns the root SiteMapNode.

You use the SiteMap class to determine where you are within a SiteMap. You use the properties and methods of the SiteMapNode class to generate navigational links. Here are some of the more interesting properties of the SiteMapNode class:
- ChildNodes – Returns all of the child SiteMapNodes.
- Description – Returns the description of a SiteMapNode.
- NextSibling – Returns the next sibling SiteMapNode.
- ParentNode – Returns the parent SiteMapNode.
- PreviousSibling – Returns the previous sibling SiteMapNode.
- Title – Returns the title of a SiteMapNode.
- Url – Returns the URL of a SiteMapNode.

3 - Creating a Menu HTML Helper

You can take advantage of SiteMaps, and the SiteMap API, to create HTML Helpers that generate navigational links automatically. For example, the HTML Helper in Listing 2 generates a menu from a SiteMap.

Helpers\MenuHelper.cs

using System.Text;
using System.Web;
using System.Web.Mvc;

namespace MvcApplication1.Helpers
{
public static class MenuHelper
{
public static string Menu(this HtmlHelper helper)
{
var sb = new StringBuilder();

// Create opening unordered list tag
sb.Append("<ul class='menu'>");

// Render each top level node
var topLevelNodes = SiteMap.RootNode.ChildNodes;
foreach (SiteMapNode node in topLevelNodes)
{
if (SiteMap.CurrentNode == node)
sb.AppendLine("<li class='selectedMenuItem'>");
else
sb.AppendLine("<li>");

sb.AppendFormat("<a href='{0}'>{1}</a>", node.Url, helper.Encode(node.Title));
sb.AppendLine("</li>");
}

// Close unordered list tag
sb.Append("</ul>");

return sb.ToString();
}

}
}

Listing 2 contains an extension method named Menu() that extends the HtmlHelper class. This method grabs all of the child nodes of the root node in the SiteMap and renders a list of links. The links are rendered in an HTML unordered list <ul> tag.
The SiteMap.CurrentNode property is used to determine whether a link being rendered corresponds to the current location of the user. The current node is marked with the Cascading Style Sheet selectedMenuItem class.
You can use the Menu() HTML helper in a particular view. However, it makes more sense to call the Menu() helper method within a View Master Page. That way, the menu will appear in all of the views in your application.

The View Master Page in Listing 3 illustrates how you can use the Menu() helper method.

Site.master

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.Master.cs" Inherits="MvcApplication1.Views.Shared.Site" %>
<%@ Import Namespace="MvcApplication1.Helpers" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
<style type="text/css">

.menu
{
list-style:none;
padding:0px;
margin:0px;
}

.menu li
{
float:left;
}

.menu a
{
display:block;
background-color:#eeeeee;
color:Black;
font-weight:bold;
padding:4px;
border:solid 1px black;
text-decoration:none;
margin:2px;
}

.selectedMenuItem a
{
background-color: White;
}

</style>

</head>
<body>
<div>

<%= Html.Menu() %>

<br style="clear:both" />

<asp:ContentPlaceHolder
ID="ContentPlaceHolder1"
runat="server" />

</div>
</body>
</html>

Notice that the namespace MvcApplication1.Helpers is imported at the top of the View Master Page. You must import the namespace of the extension method in order for the extension method to appear as a method of the Html property.

Notice that the View Master Page contains a Cascading Style Sheet that is used to style the menu links rendered by the Menu() helper. This style sheet is used to format the unordered list and links to look like a tab strip (see Figure 2).
When you click a menu link, the selected menu link is highlighted with the style defined by the selectedMenuItem CSS class. In the case of Listing 3, the selected menu item is displayed with a white background color and unselected menu items are displayed with a gray background color.

4 - The Importance of Canonical URLs

In an ASP.NET MVC application, multiple URLs can be mapped to the same controller action. For example, by default, you can invoke the Index() action on the Home controller by requesting any of the following URLs:
http://www.MySite.com/
http://www.MySite.com /Home
http://www.MySite.com /Home/Index

The default routes set up in the Global.asax file map all three of these URLs to the same controller action. Furthermore, you can invoke the Index action exposed by the Product controller by requesting either of the following URLs:
http://www.MySite.com/Product/
http://www.MySite.com/Product/Index

This feature of the ASP.NET MVC framework causes problems when you use SiteMaps. When you create a standard XML SiteMap file, you can associate each SiteMapNode with only one URL. For example, you can associate only one URL with the Index action of the Home controller. Alternative URLs for the same action won't match the correct SiteMapNode. So what do you do?

One option is to modify the routes defined in the Global.asax file so that multiple URLs cannot be mapped to the same controller action. For example, instead of defining the Default route like this:

routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);

You can replace the Default route definition with the following two route definitions like this:

routes.MapRoute(
"Home",
"",
new { controller = "Home", action = "Index", id = "" }
);

routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { id = "" }
);

The first route definition maps the URL http://www.MySite.com/ to the Index action of the Home controller. The second route definition maps a URL such as http://www.MySite.com/Product/Index to the Index action of the Product controller.
These modified routes won't match a URL like http://www.MySite.com/Home/Index or http://www.MySite.com/Product. The modified routes map one and only one URL to a controller action. In other words, you are forced to use canonical URLs for all of your controller actions.

Another solution to the problem of canonical URLs is to take advantage of the Internet Information Services 7.0 URL Rewrite Module. Learn more at http://learn.iis.net/page.aspx/460/using-url-rewrite-module/

5 - Summary

In this tutorial, you learned how to use SiteMaps to describe the navigational structure of your ASP.NET MVC websites. You learned how to create new XML SiteMap files and interact with the SiteMap API. Finally, you learned how to create a custom Menu() HTML helper that generates website menu links from a SiteMap automatically.