Upgrading from v3 to v4
MvcSiteMapProvider has had some significant updates going from v3 to v4. This page outlines the upgrade path from v3 to v4.
WARNING: MvcSiteMapProvider requires NuGet 2.6 or higher to ensure your configuration is not overwritten when upgrading. Before you upgrade MvcSiteMapProvider, you should install the latest version of NuGet.
Updating the NuGet package
The first part of the upgrade from v3 to v4 will be updating the NuGet package. Before, MvcSiteMapProvider only had one NuGet package. Today, it has been split in multiple, of which the following ones are good to know at this time:
MvcSiteMapProvider.Webcontaining all views and
MvcSiteMapProvider.MVC<version>.Corecontaining the library itself
Upgrading from v3 to v4 consists of installing the correct packages for your ASP.NET MVC version:
- For MVC 2, uninstall
- For MVC 3, uninstall
- For MVC 4, uninstall
- For MVC 5, uninstall
- Note that for MVC 4 we have made it possible to upgrade
MvcSiteMapProviderinstead, which will pull in all required dependencies. Do know that this is not the recommended scenario and it is preferred to install
MvcSiteMapProvider.Web update will add views and all required runtime dependencies to your project. This package is a dependency of each of the above options and generally will not need to be installed explicitly.
Note: The MvcSiteMapProvider.Web package contains some logic to attempt to detect the type of template files to install. If you have both .aspx and .cshtml extensions in your project, it will default to .aspx templates. This may not always be the right decision. If you find that you have the wrong templates installed in your
Views/Shared/DisplayTemplatesfolder, you can safely delete them and install the razor templates from the DisplayTemplates folder in MvcSiteMapProvider.
In .NET versions prior to .NET 4.0, one line of code should be added to the
Application_Start() event of
Note that this code is automatically executed if using .NET 4.0 or higher by the use of WebActivator, so in most cases you will not need to call it manually.
MvcSiteMapProvider v3 was based on the ASP.NET provider model. In v4, we have removed that dependency. This brings some changes to configuration.
Depending on how you load the new version of MvcSiteMapProvider the configuration may be different. However since this is an upgrade the default internal DI container will be used. Refer to the configuration reference page for detailed information about configuring MvcSiteMapProvider using an external DI container.
In short, the following configuration from v3 should be removed from your
<siteMap> <providers> <add name="MvcSiteMapProvider" type="MvcSiteMapProvider.DefaultSiteMapProvider, MvcSiteMapProvider" siteMapFile="~/Mvc.Sitemap" securityTrimmingEnabled="true" cacheDuration="5" enableLocalization="true" scanAssembliesForSiteMapNodes="true" excludeAssembliesForScan="" includeAssembliesForScan="" attributesToIgnore="bling,visibility" nodeKeyGenerator="MvcSiteMapProvider.DefaultNodeKeyGenerator, MvcSiteMapProvider" controllerTypeResolver="MvcSiteMapProvider.DefaultControllerTypeResolver, MvcSiteMapProvider" actionMethodParameterResolver="MvcSiteMapProvider.DefaultActionMethodParameterResolver, MvcSiteMapProvider" aclModule="MvcSiteMapProvider.DefaultAclModule, MvcSiteMapProvider" routeMethod="" siteMapNodeUrlResolver="MvcSiteMapProvider.DefaultSiteMapNodeUrlResolver, MvcSiteMapProvider" siteMapNodeVisibilityProvider="MvcSiteMapProvider.DefaultSiteMapNodeVisibilityProvider, MvcSiteMapProvider" siteMapProviderEventHandler="MvcSiteMapProvider.DefaultSiteMapProviderEventHandler, MvcSiteMapProvider" /> </providers> </siteMap>
The above configuration will not be picked up by MvcSiteMapProvider v4. Instead, the following configuration settings can be provided in the web.config file (all settings are optional and default to what is shown here if not provided):
<appSettings> <add key="MvcSiteMapProvider_UseExternalDIContainer" value="false"/> <add key="MvcSiteMapProvider_SiteMapFileName" value="~/Mvc.sitemap"/> <add key="MvcSiteMapProvider_ScanAssembliesForSiteMapNodes" value="false"/> <add key="MvcSiteMapProvider_ExcludeAssembliesForScan" value=""/> <add key="MvcSiteMapProvider_IncludeAssembliesForScan" value=""/> <add key="MvcSiteMapProvider_AttributesToIgnore" value=""/> <add key="MvcSiteMapProvider_CacheDuration" value="5"/> <add key="MvcSiteMapProvider_ControllerTypeResolverAreaNamespacesToIgnore" value=""/> <add key="MvcSiteMapProvider_DefaultSiteMapNodeVisibiltyProvider" value=""/> <add key="MvcSiteMapProvider_VisibilityAffectsDescendants" value="true"/> <add key="MvcSiteMapProvider_SecurityTrimmingEnabled" value="false"/> <add key="MvcSiteMapProvider_EnableLocalization" value="true"/> <add key="MvcSiteMapProvider_EnableSitemapsXml" value="true"/> <add key="MvcSiteMapProvider_EnableResolvedUrlCaching" value="true"/> <add key="MvcSiteMapProvider_EnableSiteMapFile" value="true"/> <add key="MvcSiteMapProvider_IncludeRootNodeFromSiteMapFile" value="true"/> <add key="MvcSiteMapProvider_EnableSiteMapFileNestedDynamicNodeRecursion" value="false"/> <add key="MvcSiteMapProvider_UseTitleIfDescriptionNotProvided" value="true"/> </appSettings>
Many of these settings map to their v3 counterpart and their values can be copied in. All type overrides that were available, for example for specifying which
aclModule to use, have been moved towards a dependency injection strategy. If you need to override any of these types (or others, more overrides are available in v4), refer to the dependency injection documentation.
Updating sitemap XML
As with any major version upgrade we have had earlier, the XML schema for your sitemap file should updated. For this upgrade it should be changed from
You must also remove the
enableLocalization attribute from the
mvcSiteMap element (if it exists) and migrate the value to the web.config appSettings configuration value
MvcSiteMapProvider_EnableLocalization as shown above.
Updating System.Web.SiteMap Code References
If you have references in your code to Microsoft's
SiteMap static methods, you will need to update them to the MvcSiteMapProvider equivalent.
In general, any reference to
System.Web.SiteMap.Provider will need to be updated to
If you are using named providers and therefore have more than one sitemap in your project, you will need to use an external DI container and follow the directions to use more than one sitemap in a single application.
Updating Sitemaps End Point (/sitemap.xml) Code
If you have placed the line to register the /sitemap.xml endpoint in your Global.asax or other part of your initialization, you should remove it as it is now enabled by default.
// Remove this line XmlSiteMapController.RegisterRoutes(RouteTable.Routes);
Note: If you installed one of the DI packages, this line will be put into the file /App_Start/MvcSiteMapProviderConfig.cs. You should not remove the line from that file.
If you do not want the /sitemap.xml endpoint registered in your application, it can be disabled in the web.config appSettings section:
<add key="MvcSiteMapProvider_EnableSitemapsXml" value="false"/>
SiteMapPreserveRouteDataAttribute has been deprecated because it relied on a bug (that has been fixed) in order to function. It is planned for removal from the project in version 5.
The recommended migration path is to start using the PreservedRouteParameters property instead. You must specify each parameter that you want preserved on each node you want it preserved on. This is only useful in cases where you want to use the SiteMapPath HTML helper to work alongside navigation that is driven from a database and there is no value in adding them as nodes.
However, if there is value in adding the records as nodes (such as if you want them to be indexed by search engines), you should use a Dynamic Node Provider to set the value instead as shown in Routing Basics.
Updating Dynamic Node Providers, Visibility Providers, and URL Resolvers
While in v3 only the dynamic node provider had a base class, now each of these providers has a base class. Technically the interface is all that is needed, but the base classes provide a shortcut so there is less for you to implement. It is recommended to always use the base class except for advanced scenarios.
The following table shows the typical upgrade paths from v3 to v4:
|Provider||Version 3 Use||Version 4 Use|
|Dynamic Node Provider||MvcSiteMapProvider.Extensibility.DynamicNodeProviderBase||MvcSiteMapProvider.DynamicNodeProviderBase|
Dynamic Node Provider
In addition to the namespace change of the base class, the interface has also changed.
GetDynamicNodeCollection() method now has a parameter that the template node is passed through, so you can easily read and use the values from this node if needed:
// v3 IEnumerable<DynamicNode> GetDynamicNodeCollection(); // v4 IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node);
GetCacheDescription() method no longer exists because there is now a single cache that controls the timeout for the entire sitemap, so any implementation should be removed.
If you need to update the sitemap with dynamic data, it is recommended to call the
SiteMaps.ReleaseSiteMap() method immediately after the data has been updated in the database. This will force the sitemap to be rebuilt and cached with the new data on the next user request.
In addition to the new base class, the interface has also changed.
IsVisible() method no longer has a
context parameter, and the type being passed is now
MvcSiteMapProvider.ISiteMapNode rather than
// v3 bool IsVisible(SiteMapNode node, HttpContext context, IDictionary<string, object> sourceMetadata); // v4 bool IsVisible(ISiteMapNode node, IDictionary<string, object> sourceMetadata);
In addition to the new base class, the interface has also changed.
ResolveUrl() method node parameter type is now
MvcSiteMapProvider.ISiteMapNode rather than
MvcSiteMapProvider.MvcSiteMapNode and its name changed to
// v3 string ResolveUrl(MvcSiteMapNode mvcSiteMapNode, string area, string controller, string action, IDictionary<string, object> routeValues); // v4 string ResolveUrl(ISiteMapNode node, string area, string controller, string action, IDictionary<string, object> routeValues);
A Note on the AppliesTo() Method
This method exists on each of the above interfaces and each of the base classes provides a default implementation that will mimic the v3 behavior. In general, you will not need to deal with it unless you are using strongly named assemblies or implementing the interfaces directly.
v3 used .NET Reflection to load the providers into memory on demand, and in each node had a new instance created, used, and then garbage collected. In v4, we take a different approach - there is now a single instance of each provider that is kept in memory regardless of how many nodes are instantiated that services all of the nodes that call it by its name.
A string match on the name is used to determine which provider instance should be used to service a given node using the Strategy Pattern. The AppliesTo() method contains the logic to match the requested provider, and returns true if the provider is a match. To understand its usage, see this Stack Overflow question: http://stackoverflow.com/questions/1499442/best-way-to-use-structuremap-to-implement-strategy-pattern.
For backward compatibility with v3, we have provided the base classes mentioned above that default to matching the short assembly qualified name to the value in the .sitemap file, which is the same string that is used by .NET Reflection to load the type.