Domanda

I use MvcSiteMapProvider in order to implement a dynamic Sitemap for our site. The site has a constantly updated collection of articles, and each one is represented as a different page. Thus we use MvcSiteMapProvider in order to have a dynamically generated sitemap.xml. The problem, however, is that we have added images to the articles, that we want to add to the sitemap.xml so that they can be indexed as well.

What I need to achieve is generate a structure like the one described for adding image urls to sitemaps, i.e:

<?xml version="1.0" encoding="UTF-8"?>
 <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
  xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
 <url>
   <loc>http://example.com/sample.html</loc>
   <image:image>
     <image:loc>http://example.com/image.jpg</image:loc>
   </image:image>
   <image:image>
     <image:loc>http://example.com/photo.jpg</image:loc>
   </image:image>
 </url> 
</urlset> 

Currently my DynamicNode generation code is like this

public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
{
    List<Article> articles = new List<Article>();
    using(siteMapHelperDB db = new siteMapHelperDB())
    {
        articles = db.GetArticleSiteMapNodes();
    }
    foreach(Article item in articles)
    {
        var dynamicNode = new DynamicNode();
        dynamicNode.Title = item.urlName; // URL Friendly title
        dynamicNode.RouteValues.Add("id", string.Format("{0}/{1}", item.ID, item.urlName));

        yield return dynamicNode;
    }
}

My Mvc.Sitemap description is this:

<mvcSiteMapNode title="Articles" controller="Articles" action="Show"
                dynamicNodeProvider="ArticlesKB.ArticlesNodeProvider, ArticlesKB"/>

All this works great so far. What I need now is to find out, how do I actually add the <image:image> nodes per each article.

Is this currently supported in MvcSiteMapProvider 4? If it is, what do I need to do to implement it?

Thanks!

È stato utile?

Soluzione

This is not currently supported out of the box. 1 other person has requested it and even made a first draft but it was never completed, and it is on the to-do list to add as a new feature. But, being that this is open source it will get done when someone gets around to it :).

So, you have 2 options:

  1. Build this into MvcSiteMapProvider as a first-class feature and submit it as a contribution via pull request.
  2. Extend MvcSiteMapProvider using the Attributes dictionary to store the child image collections for each node as a second-class feature that is just for your application.

For the first option, we would like to have support for all of the various types of sitemaps that Google has invented. So the design should take into account extensibility even if you only decide to implement the image sitemap for now.

The steps involved are:

  1. Read the contribution guide.
  2. Create a interfaces with all of the properties required for each of the child objects (if just doing images, you just need a single property, but we should have an interface rather than a string in case Google extends it). We are using DI, so it is important that the interface is what is passed around, not the concrete type.
  3. Create corresponding objects for each interface. They must use the same name exactly excluding the "I" so they are wired up automatically in the external DI configurations.
  4. Create dictionaries and/or collections that accept the interface(s) you created in step 2. Use the ones in the MvcSiteMapProvider.Collections.Specialized namespace as a guide.
  5. Keep in mind that the SiteMap is shared between all users, so the objects must be made read-only when the SiteMap.IsReadOnly property is true (see the collections and LockableSiteMapNode for examples).
  6. Update the XmlSiteMapResult class to read from the new collections and produce the appropriate XML. Since this is a standardized format that is unlikely to change, hard coding the XML declaration is fine.
  7. Decide on which method you are going to use to populate your nodes (ISiteMapNodeProvider, IDynamicNodeProvider, XML, or .NET Attributes) and update the corresponding ISiteMapNodeProvider implementation so it populates the new child collections/dictionaries. ISiteMapNodeProvider is your easiest option - in that case you can just build your implementation within your app and you are done. If you decide to go with XML, I think it would be best to use the exact same format that Google uses as child nodes of <mvcSiteMapNode/> so it could potentially be copied and pasted from another XML document. You would need to update the XSD file so it can validate the XML appropriately.
  8. Implement your source of the image URLs. Ideally, we would like all sources to support this, but will accept with one or two sources. ISiteMapNodeProvider needs to support it in every case. Each child collection/dictionary should be instantiated the same way as the current child collections/dictionaries by using an abstract factory to create it when the SiteMapNode is created.

For any additional questions/feedback please use the open issue @ GitHub. This will likely take a bit of back and fourth communication to achieve, which is best done there.

For the second option:

  1. Use one of the node sources to provide a child dictionary of custom Attributes (note that .NET attributes are currently broken for this - the patch will be in v4.5). Add them to the Attributes dictionary node.Attributes.Add("sitemaps-images", imageCollection).
  2. Copy the XmlSiteMapResult to your project and update it so it writes the appropriate XML if the "sitemaps-images" dictionary has entries. Currently there is no way to inject an alternate implementation.
  3. Build a custom controller to serve the /sitemaps.xml endpoint and use the XmlSiteMapResult the same way the built-in XmlSiteMapController does.
  4. Disable the built-in controller: for internal DI, set the appSettings "MvcSiteMapProvider_EnableSitemapsXml" value to "false" in web.config. For external DI, remove the XmlSiteMapController.RegisterRoutes(RouteTable.Routes); line from the App_Start\MvcSiteMapProviderConfig.cs file.
  5. Register your routes in a similar fashion to the way it is done in XmlSiteMapController.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top