Search code examples
asp.net-mvcmvcsitemapprovider

With MvcSiteMapProvider Is it possible to programmatically register lots of pages between index ranges?


I'm looking at MVCSiteMapProvider but I can't find anything in documentation that would allow me to register lots of urls by index. I have the following

http://example.com/story/1
...
...
http://example.com/story/7000000

I'd like to be able to use the library to automatically serve these in lots of different files. I've read through all the documentation but can't find anything. It seems really fully featured though so I thought I would ask before rolling my own solution.


Solution

  • You can use a dynamic node provider or implement ISiteMapNodeProvider to programatically supply your own data (including custom ids) from any source.

    Dynamic node providers can be added without using an external dependency injection container, but you need to add a "template" node either in XML or using .NET attributes to attach the provider to (see the above link).

    public class StoryDynamicNodeProvider : DynamicNodeProviderBase
    {
        public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
        {
            // Entities would be your entity framework context class
            // or repository.
            using (var entities = new Entities())
            {
                // Create a node for each blog post
                foreach (var story in entities.Stories)
                {
                    DynamicNode dynamicNode = new DynamicNode();
                    dynamicNode.Title = story.Title;
    
                    // The key of the node that this node will be the child of.
                    // This works best if you explicitly set the key property/attribute 
                    // of the parent node.
                    dynamicNode.ParentKey = "Home"; 
                    dynamicNode.Key = "Story_" + story.Id;
                    dynamicNode.Controller = "Story";
                    dynamicNode.Action = "Details";
    
                    // Add the "id" (or any other custom route values)
                    dynamicNode.RouteValues.Add("id", story.Id);
    
                    yield return dynamicNode;
                }
            }
        }
    }
    

    Using ISiteMapNodeProvider you can build the entire SiteMap structure including the root node, but currently it requires using an external DI container to inject a custom implementation.

    There is an example here of how you could implement ISiteMapNodeProvider yourself. Here is an example of injecting a custom implementation using SimpleInjector.

    Do note that there is currently a limitation in the 10s of thousands for the total number of nodes on a server because they are cached in memory, so if you have that many nodes using preservedRouteParameters is a better choice. However, it has a limitation that the individual URLs can only appear in the SiteMapPath, but not in the Menu, SiteMap, or XML Sitemap for search engines.