Dynamic sitemaps

In many web applications, sitemap nodes are directly related to content in a persistent store like a database.For example, in an e-commerce application, a list of product details pages in the sitemap maps directly to the list of products in the database. Using dynamic sitemaps, a small class can be provided to the MvcSiteMapProvider offering a list of dynamic nodes that should be incldued in the sitemap. This ensures the product pages do not have to be specified by hand in the sitemap XML.

First of all, a sitemap node should be defined in XML. This node will serve as a template and tell the MvcSiteMapProvider infrastructure to use a custom dynamic node procider:

<mvcSiteMapNode title="Details" action="Details" dynamicNodeProvider="MvcMusicStore.Code.StoreDetailsDynamicNodeProvider, MvcMusicStore" />

Next, a class implementing MvcSiteMapProvider.Extensibility.IDynamicNodeProvider or extending MvcSiteMapProvider.Extensibility.DynamicNodeProviderBase should be created in your application code. Here’s an example:

public class StoreDetailsDynamicNodeProvider 
    : DynamicNodeProviderBase 
{ 
    MusicStoreEntities storeDB = new MusicStoreEntities();

    public override IEnumerable<DynamicNode> GetDynamicNodeCollection() 
    { 
        // Build value 
        var returnValue = new List<DynamicNode>();

        // Create a node for each album 
        foreach (var album in storeDB.Albums.Include("Genre")) 
        { 
            DynamicNode node = new DynamicNode(); 
            node.Title = album.Title; 
            node.ParentKey = "Genre_" + album.Genre.Name; 
            node.RouteValues.Add("id", album.AlbumId);

            returnValue.Add(node); 
        }

        // Return 
        return returnValue; 
    } 
}

Cache dependency

When providing dynamic sitemap nodes to the MvcSiteMapProvider, chances are that the hierarchy of nodes will become stale, for example when adding products in an e-commerce website. This can be solved by specifying a CacheDescriptor on your MvcSiteMapProvider.Extensibility.IDynamicNodeProvider implementation:

public class StoreDetailsDynamicNodeProvider 
    : DynamicNodeProviderBase 
{ 
    MusicStoreEntities storeDB = new MusicStoreEntities();

    public override IEnumerable<DynamicNode> GetDynamicNodeCollection() 
    { 
        // ... 
    } 

    public override CacheDescription GetCacheDescription() 
    { 
        return new CacheDescription("StoreDetailsDynamicNodeProvider") 
        { 
            SlidingExpiration = TimeSpan.FromMinutes(1) 
        }; 
    } 
}

Last edited Jul 23, 2010 at 10:09 AM by maartenba, version 2

Comments

justrhysism Jul 27, 2012 at 3:32 AM 
Ie Ming - Did you find a solution? I could really use it!

Ridermansb Dec 26, 2011 at 5:14 PM 
I'm not able to work with this feature.
I need a node inside another .. see the complete question on stackoverflow:
http://stackoverflow.com/questions/8624932/working-with-child-nodes-of-dynamicnodeprovider

ronnieoverby Oct 8, 2011 at 11:46 PM 
Make sure to return nodes in order from top level to bottom level. Otherwise nodes won't correctly have children.

daveb84 Sep 16, 2011 at 12:59 PM 
I've just reached the end of a world of pain with this provider.

I was experiencing the "No parameterless constructor defined for this object." error. This was because I had my own custom AuthorizeAttribute that did not have a default constructor. Looking through the code in reflector it seems that AuthorizeAttributes are read and created using reflection, but ignore the constructor parameters. The result was this exception, and the menu item did not appear. I solved the problem by adding a parameterless constructor to be AuthorizeAttribute.

rfogh Apr 12, 2011 at 10:45 AM 
If you use dynamic sitemaps and experience problems with child nodes, check out this page: http://stackoverflow.com/questions/4137855/creating-child-nodes-for-a-dynamicnode-in-mvcsitemapprovider-that-have-dynamic-pa
/Rune

ieming Feb 24, 2011 at 8:40 AM 
When I tried to call sitemap.xml, I am getting the error, "No parameterless constructor defined for this object.". This is because I am using Ninject for Dependency Injection. It works perfectly when the service class is being called within the controller class through DI. It seems that DI fails when trying to call it within this dynamic class.

And when I tried to put a breakpoint in this dynamic provider class, but it seems that this class was never hit. Does anybody experience such a problem before?

Thanks,
Ie Ming