views:

235

answers:

1

I am using the ASP.NET MVC SiteMap provider to create dynamic sitemap nodes. It works when the application is first loaded, but I wish to add/remove nodes when an ActionResult executes (to add/remove a record from the database). My web.sitemap is as follows (taken out the parent node and other siblings)

<mvcSiteMapNode dynamicNodeProvider="MyWebSite.DynamicNodeProvider.DatesDynamicNodeProvider, MyWebSite">
    <mvcSiteMapNode action="Details" dynamicNodeProvider="MyWebSite.DynamicNodeProvider.DetailsDynamicNodeProvider, MyWebSite" />
    <mvcSiteMapNode action="Edit" dynamicNodeProvider="MyWebSite.DynamicNodeProvider.EditDynamicNodeProvider, MyWebSite" />
    <mvcSiteMapNode action="Delete" dynamicNodeProvider="MyWebSite.DynamicNodeProvider.DeleteDynamicNodeProvider, MyWebSite" />
</mvcSiteMapNode>

The dates are generated dynamically:

    public override IEnumerable<DynamicNode> GetDynamicNodeCollection()
    {
        DBDataContext db = new DBDataContext();

        var records = db.records.ToList();
        if (records != null)
        {
            DateTime created;
            foreach (var record in records)
            {
                if (record.DateCreated.HasValue)
                {
                    created = record.DateCreated.Value;
                    DynamicNode node = CreateNode(created);
                    yield return node;
                }

            }
        }
    }

    public static DynamicNode CreateNode(DateTime date)
    {
        DynamicNode node = new DynamicNode("record_" + date.ToString("yyyy-M"), date.ToString("MMMM yyyy"));
        node.Action = date.ToString("yyyy-M");
        node.ParentKey = "records";
        return node;
    }

And then add nodes under these generated nodes:

    public override IEnumerable<DynamicNode> GetDynamicNodeCollection()
    {
        DBDataContext db = new DBDataContext();

        var records = db.records.ToList();
        if (records != null)
        {
            // Create a node for each record
            foreach (var record in records)
            {
                if (record.DateCreated.HasValue)
                {
                    DynamicNode node = CreateNode(record);

                    yield return node;
                }
            }
        }
    }

    public static DynamicNode CreateNode(Record record)
    {
        DateTime created = record.DateCreated.Value;
        DynamicNode node = new DynamicNode("record_edit_" + record.ID, string.Format("{0:dd MMM yyyy}: {1} (Edit)", created, record.Title));
        node.RouteValues["id"] = record.ID;
        node.ParentKey = "record_" + created.ToString("yyyy-M");

        return node;
    }

However, I then get to the point of creating these nodes within an ActionResult, but get stuck at this point. I can grab the node:

var node = ((MvcSiteMapProvider.DefaultSiteMapProvider)SiteMap.Provider).FindSiteMapNodeFromKey("record_edit_" + record.ID);

But then I want to check if the node is null, and if not create a new one (and the parent node if it does not exist). First thing I tried doesn't work, as not sure if you can add a DynamicNode to the site map (as I can't cast DynamicNode to SiteMapNode)

    if (node == null)
    {
        node = DynamicNodeProvider.EditDynamicNodeProvider.CreateNode(record) as SiteMapNode;
        var parent = ((MvcSiteMapProvider.DefaultSiteMapProvider)SiteMap.Provider).FindSiteMapNodeFromKey("record_" + record.DateCreated.Value.ToString("yyyy-M"));
        if (parent == null)
        {
            parent = DynamicNodeProvider.DatesDynamicNodeProvider.CreateNode(record.DateCreated.Value) as SiteMapNode;
            parent.Action = record.DateCreated.Value.ToString("yyyy-M");
            parent.ParentKey = "records";
        }
        node.ParentKey = parent.ParentKey;
    }

Of course, this doesn't work because of the aforementioned problem.

This is just for the edit page for each record, I also want change the title (if the title is changed) or delete from the sitemap if necessary.

Any ideas?

A: 

Try setting the cache dependency on your dynamic node providers and have them trigger a sitemap update when needed (for example when a record is added).

maartenba
How do you setup the dependencies with CacheDescription? I do not want to rebuild all the nodes set by the dynamic node provider (since it would be doing it regularly), just the record that has changed and the parent (if it does not exist). None of the dynamic node provider examples (in MvcMusicStore) show how you would use the other CacheDescription options
Sam
Unfortunately this will trigger a complete rebuild. CacheDescription can be a timespan, explicit expiry date, or a CacheDependency. I use the last one in some projects. (http://msdn.microsoft.com/en-us/library/system.web.caching.cachedependency.aspx)
maartenba