MVC 3 XML Sitemap

Ok, so you’ve got your shiny new mvc3 app up and running. Now, it’s time to bake in some of that SEO goodness. Here’s how you can easily add a sitemap.xml to your new mvc application. The solution specified below not only pumps out the xml file to submit to the search engines, but it is also a System.Web.SiteMapProvider, so you can use it for menus and wherever else you want to use your sitemap.

I’m a big fan of NuGet, so bring up the Package Manager Console and grab MvcSiteMapProvider (or download it from github).

Install-Package MvcSiteMapProvider

Once it is installed there will be a new Mvc.sitemap file added with the following to your solution:

<mvcSiteMapNode title="Home" controller="Home" action="Index">
    <mvcSiteMapNode title="About" controller="Home" action="About"/>
</mvcSiteMapNode>

Now for the easy bit: to get a ~/sitemap.xml to auto-generate for us based on our controller actions we specified in the sitemap file above. All you need to do is simply add the following to your route registration (generally Global.Application_Start()):

XmlSiteMapController.RegisterRoutes(RouteTable.Routes);

Now, like a lot of other people out there my next question was, what about my dynamically generated content from the database (such as Product/Details/1)?  Easy – MvcSiteMapProvider comes with dynamic node support. Just create a class like the following:


public class ProductDetailsDynamicNodeProvider : DynamicNodeProviderBase
 {
     public override IEnumerable<DynamicNode> GetDynamicNodeCollection()
     {
         // Create a node for each product
         foreach (Product product in productService.GetAllProducts())
         {
             var node = new DynamicNode();
             node.Title = product.Name;
             node.RouteValues.Add("id", product.Id);

             yield return node;
         }
     }
     public override CacheDescription GetCacheDescription()
     {
        return new CacheDescription("ProductDetailsDynamicNodeProvider")
        {
            SlidingExpiration = TimeSpan.FromMinutes(60);
        };
    }
 }

Things to note with the above code: you don’t have to override the cachedescription method, but this does allow us to specify how long all our products will be cached for in the sitemap. Then, you can add your dynamic node to the mvc.sitemap files as follows:

<mvcSiteMapNode title="Details" action="Details"
dynamicNodeProvider="Website.ProductDetailsDynamicNodeProvider, Website"/>

Now you are done and have a working auto-generated mvc sitemap. For those of us who are using it to generate breadcrumbs, check out the awesome example of html helpers in the documentation.

Next time, I’ll be looking at creating SEO friendly URLs in MVC.

Posted in .Net, Asp.Net, Xml at January 8th, 2012. No Comments.

FirstObject XML Editor

I was looking for a fast, free XML editor today, which could handle fairly large (~100MB) XML files without too much hassle. Previously I’ve used XML Marker for this; it’s fantastic, however it has a fairly clunky interface. I wish SymbolClick would release a more modern version!

Anyway, today I found FirstObject XML Editor and gave it a try; so far it seems great! It’s lightweight (only a single EXE file), and it’s fast. Best of all, it has a very, very simple way to format (i.e. pretty print) XML files – just press F8!

Highly recommended.

Posted in Applications, Xml at August 1st, 2009. 1 Comment.

Persisting objects into database using xml serialization

Recently I showed you how to pull sql query result sets into object instances using the XmlReader and deserialization. This article aims to show you the opposite process – persisting an object instance into a database table using serialization and Sql Server xml parsing.

The same Channel database table and entity class will be used for all examples.

Channel Table Schema

/// Represents a media channel (e.g. web, mobile, iphone, etc.)
public class Channel
{
   public Channel()
   {
   }

   public Channel(string type, string description)
   {
       Type = type;
       Description = description;
   }

    /// Get/Set the channel identifier
    public int Id { get; set; }

    /// Get/Set the channel type (e.g. web, mobile, iphone, etc.)
    public string Type { get; set; }

    /// Get/Set the description of the channel.
    public string Description { get; set; }
 }

The Stored Procedure

The sproc takes in an sql server xml datatype parameter. This is provided via a normal string representation of the xml. Within the SPROC you prepare the document for querying, pull out the values you require and perform the insert.

To understand the following SPROC, you need to have have a basic understanding of:

a) how your object instance xml serialization format looks


<?xml version="1.0" encoding="utf-16"?>
<Channel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Id>0</Id>
  <Type>web</Type>
  <Description>800x600 or larger browsers</Description>
</Channel>'

and

b) an understanding of xpath and xquery for pulling the values out from the xml.

Check out the – Resources – Sql Xml - for some links that might help you out.


CREATE PROCEDURE [usp_PersistChannel]
	@xmldoc XML
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE
            @iDoc int,
            @type varchar(50),
            @description varchar(255)

    EXEC sp_xml_preparedocument
           @iDoc OUTPUT,
           @xmldoc,
            ''

    SELECT
            @Type = [Type],
            @Description = [Description]
    FROM
            OPENXML (@iDoc, '/Channel',3)
	WITH (  [Type] varchar(50) './Type',
	Description] varchar(255) './Description' )

    EXEC sp_xml_removedocument @idoc

    INSERT INTO Channel VALUES (@Type, @Description)                

    SELECT @@IDENTITY
END

Data Access Code

The following is a convenience method to help aid the serialization process of an object instance.


        /// Serialize an instance of an object to a string.
        public string Serialize(object instance)
        {
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);
            XmlSerializer serializer = new XmlSerializer(instance.GetType(), null, new Type[0], null, null);
            serializer.Serialize(sw, instance);
            return sb.ToString();
        }

Usage Examples:



        /// Persist a Channel.
        public void Persist(Channel channel)
        {
            channel.Id = Int32.Parse(
                                Database.ExecuteScalar(
                                   Database.GetStoredProcCommand("usp_PersistChannel", Serialize(channel))
                                ).ToString()
                             );
        }
Posted in .Net, Development, Sql Server, Xml at February 18th, 2008. 3 Comments.

Quickduck logo