For the MvcSiteMapProvider v4, I've written a custom sitemap url resolver by overriding SiteMapNodeUrlResolverBase.
But I don't know how to register it in the MvcSiteMapProviderRegistry to make sure that a node's Url is always resolved using my own SiteMapNodeUrlResolver.
I expected something like:
this.For<ISiteMapNodeUrlResolver>().Use<MyUrlResolver>();
But this doesn't work, how should I do this?
The SiteMapNodeUrlResolvers (along with visibility providers and dynamic node providers) use a strategy pattern so you can wire up multiple instances and then refer to each instance by name. That name is then used by the AppliesTo()
method to determine which URL resolver to use for each node.
If you inherit from SiteMapNodeUrlResolverBase rather than implement ISiteMapNodeUrlResolver, the default implementation of AppliesTo()
will work in most cases. Then, this line (which is already included in the module by default) will automatically wire up all SiteMapNodeUrlResolvers:
// Multiple implementations of strategy based extension points
CommonConventions.RegisterAllImplementationsOfInterface(
(interfaceType, implementationType) => this.For(interfaceType).Singleton().Use(implementationType),
multipleImplementationTypes,
allAssemblies,
excludeTypes,
"^Composite");
By default, it only scans MvcSiteMapProvider.dll and your MVC project. If you have your URL resolver defined in a separate assembly, you will need to modify the allAssemblies variable to ensure that it includes your custom assembly.
Once it is loaded, then you need to call it by name. The default implementation uses the "ShortAssemblyQualifiedName", which is the same string that you would normally use to refer to a type in a configuration file (as long as your assembly is not strong named).
<mvcSiteMapNode title="Home" action="Index" controller="Home" urlResolver="MyNamespace.MySiteMapNodeUrlResolver, MyAssembly" />
The urlResolver property/attribute must be set on every node you wish to override the default implementation on.
If you prefer, you can implement the AppliesTo() method yourself so you can shorten the amount of configuration that is required. Note this will only work when using an external DI container because the internal DI container uses the type names from the configuration to instantiate the objects.
public override bool AppliesTo(string providerName)
{
return "myUrlResolver".Equals(providerName, StringComparison.InvariantCulture);
}
<mvcSiteMapNode title="Home" action="Index" controller="Home" urlResolver="myUrlResolver" />