-
Notifications
You must be signed in to change notification settings - Fork 218
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.
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.Web
containing all views andweb.config
changes -
MvcSiteMapProvider.MVC<version>.Core
containing the library itself
Upgrading from v3 to v4 consists of installing the correct packages for your ASP.NET MVC version:
- For MVC 2, uninstall
MvcSiteMapProvider
and installMvcSiteMapProvider.MVC2
- For MVC 3, uninstall
MvcSiteMapProvider
and installMvcSiteMapProvider.MVC3
- For MVC 4, uninstall
MvcSiteMapProvider
and installMvcSiteMapProvider.MVC4
- For MVC 5, uninstall
MvcSiteMapProvider
and installMvcSiteMapProvider.MVC5
- Note that for MVC 4 we have made it possible to upgrade
MvcSiteMapProvider
instead, which will pull in all required dependencies. Do know that this is not the recommended scenario and it is preferred to installMvcSiteMapProvider.MVC4
instead.
The 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/DisplayTemplates
folder, 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 Global.asax
:
MvcSiteMapProvider.DI.Composer.Compose();
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 Web.config
file:
<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.
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 http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0
to http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0
.
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.
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 MvcSiteMapProvider.SiteMaps.Current
.
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.
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.
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 |
Visibility Provider | MvcSiteMapProvider.Extensibility.ISiteMapNodeVisibilityProvider | MvcSiteMapProvider.SiteMapNodeVisibilityProviderBase |
URL Resolver | MvcSiteMapNode.Extensibility.ISiteMapNodeUrlResolver | MvcSiteMapProvider.Web.UrlResolver.SiteMapNodeUrlResolverBase |
In addition to the namespace change of the base class, the interface has also changed.
The 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);
The 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.
The IsVisible()
method no longer has a context
parameter, and the type being passed is now MvcSiteMapProvider.ISiteMapNode
rather than System.Web.SiteMapNode
:
// 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.
The ResolveUrl()
method node parameter type is now MvcSiteMapProvider.ISiteMapNode
rather than MvcSiteMapProvider.MvcSiteMapNode
and its name changed to node
:
// 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);
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.
Want to contribute? See our Contributing to MvcSiteMapProvider guide.
- Upgrading from v3 to v4
- Routing Basics
- Configuring MvcSiteMapProvider
- Defining Sitemap Nodes in XML
- Defining Sitemap Nodes using .NET Attributes
- Defining Sitemap Nodes using IDynamicNodeProvider
- HtmlHelper Extensions
- Controlling URL Behavior
- Using Action Filter Attributes
- Sitemaps XML Protocol Endpoint for Search Engines
- Using Custom Attributes on a Node
- Specifying Node Order
- Advanced Node Visibility
- Multiple Navigation Paths to a Single Page
- Multiple Sitemaps in One Application
- Security Trimming
Other places around the web have some documentation that is helpful for getting started and finding answers that are not found here.
- MvcSiteMapProvider 4.0 - A Test Drive
- MvcSiteMapProvider 4.0 - SEO Features Tutorial
- How to Make MvcSiteMapProvider Remember a User’s Position
- MvcSiteMapProvider 4.0 - Cache Configuration
- MvcSiteMapProvider 4.0 - Extending the Cache
- MvcSiteMapProvider 4.0 - Unit Testing with the SiteMaps Static Methods
- Debugging an MvcSiteMapProvider Configuration
- Converting from C# to Vb MvcSiteMapProvider
- ASP.NET MVC Menu using Site Map Provider & Bootstrap 3 Navbar
- ASP.NET MVC SiteMapPath using Site Map Provider & Bootstrap Breadcrumbs
- NightOwl888's MvcSiteMapProvider Demos - Filter for "MvcSiteMapProvider" to see the most relevant.
- MvcSiteMapProvider Tutorial and Examples
- MvcSiteMapProvider Tutorial 2 - Breadcrumbs
- Getting Started with MvcSiteMapProvider
- Inside the MvcSiteMapProvider - Part 1
- Inside the MvcSiteMapProvider - Part 2: Dynamic node providers
- Inside the MvcSiteMapProvider - Part 3: The ISiteMapVisibilityProvider
- Inside the MvcSiteMapProvider - Part 4: The IAclModule
- Inside the MvcSiteMapProvider - Part 5: The ISiteMapNodeUrlResolver
- Styling MvcSiteMapProvider with CSS
- Using MvcSiteMapProvider with Twitter Bootstrap
- ASP.NET MVC Menu using Site Map Provider & Bootstrap Navbar