1

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?

djot
  • 2,952
  • 4
  • 19
  • 28
Jurjen Ladenius
  • 1,945
  • 1
  • 12
  • 9

1 Answers1

0

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" />
Community
  • 1
  • 1
NightOwl888
  • 55,572
  • 24
  • 139
  • 212
  • Any way to implement interface ISiteMapNodeUrlResolver, which would be much easier (single line) than decorate every node with the name of the resolver. – Joao Leme Jan 27 '17 at 21:13
  • No, there isn't. It is not recommended to use a `UrlResolver` except for extreme edge cases, since that would effectively make your outgoing generated URL different from both incoming and outgoing URLs generated using .NET Routing. If you need to customize the URL, you should instead use .NET Routing which gives you control over both MVC and `MvcSiteMapProvider` to ensure they are consistent. – NightOwl888 Jan 28 '17 at 00:29
  • I have an edge case and I think there should be an easier way. Everything was working just fine on v3 BUT v4 completely broke the code and its not compatible...if only v3 was available on .net4.5. – Joao Leme Jan 28 '17 at 00:54
  • 1
    I suggest you ask a new question with exactly what you had in mind. v4 is much more configurable than v3, but it uses a different approach and your special case can probably be implemented another way. – NightOwl888 Jan 28 '17 at 01:59