What is a sitemap?

A site map (or sitemap) is a list of pages of a web site accessible to crawlers or users. It can be either a document in any form used as a planning tool for Web design, or a Web page that lists the pages on a Web site, typically organized in hierarchical fashion.

How to create a dynamic sitemap in ASP.NET MVC?

We will walk through all the steps needed to create a dynamically updating sitemap in MVC. This is great if you have dynamic content pages for events, news, blog or other pages where urls are generated automatically using a database.


Step 1 - Create a SitemapItem Class

The SitemapItem Class will be used to store all the properties we need for each sitemap URL entry.

    public class SitemapItem
    {
        public DateTime? DateAdded { get; set; }
        public string URL { get; set; }
        public string Priority { get; set; }
    }
Step 2 - Create a SitemapActionResult

The SitemapActionResult is the result that comes back from the controller when the URL /sitemap is called. It takes a listof SitemapItem classes and generates the corresponding xml file that will be used by different search engines to index your website.

public class SitemapActionResult : ActionResult
    {
        private List _SitemapItems;
        private string _Website;
        public SitemapActionResult(List SitemapItems, string Website)
        {
            this._SitemapItems = SitemapItems;
            this._Website = Website;
        }
        public override void ExecuteResult(ControllerContext context)
        {
            context.HttpContext.Response.ContentType = "text/xml";
            using (XmlWriter writer = XmlWriter.Create(context.HttpContext.Response.Output))
            {
                writer.WriteStartElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9");
                foreach (var SiteMapItem in this._SitemapItems)
                {
                    writer.WriteStartElement("url");
                    writer.WriteElementString("loc", string.Format(this._Website + "{0}", SiteMapItem.URL));
                    if (SiteMapItem.DateAdded != null)
                    {
                        writer.WriteElementString("lastmod", string.Format("{0:yyyy-MM-dd}", SiteMapItem.DateAdded));
                    }
                    writer.WriteElementString("changefreq", "daily");
                    writer.WriteElementString("priority", SiteMapItem.Priority);
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
                writer.Flush();
                writer.Close();
            }
        }
    }

Step 3 - Create a SitemapController

The controller is where you will generate your list of SitemapItem classes that will be returned via the SitemapActionResult.

public class SitemapController : Controller
    {
        [OutputCache(Duration = 120, VaryByParam = "none")]
        public SitemapActionResult Index()
        {
            var Website = "https://www.mobilizecloud.com";
            var SitemapItems = new List();
            SitemapItems.Add(new SitemapItem
            {
                URL = "",
                Priority = "1",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/about-us",
                Priority = ".9",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-services",
                Priority = ".9",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-services/websites",
                Priority = ".8",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-services/web-applications",
                Priority = ".8",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-services/e-commerce",
                Priority = ".8",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-services/the-cloud",
                Priority = ".8",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-services/social-media",
                Priority = ".8",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-services/search-engine-optimization",
                Priority = ".8",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-services/digital-marketing",
                Priority = ".8",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-work",
                Priority = ".9",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-work/top-cme-continuing-medical-education",
                Priority = ".8",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-work/power-distributors-outdoor-power-parts-products-and-engines",
                Priority = ".8",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-work/the-ohio-state-university-wexner-medical-center-center-for-continuing-medical-education",
                Priority = ".8",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-work/nbatocolumbus-viral-campaign",
                Priority = ".8",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-work/robison-tax-law-federal-tax-law-and-section-1031-exchanges",
                Priority = ".8",
                DateAdded = new DateTime(2015, 9, 5)
            });
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-work/proserverx-complete-patient-management",
                Priority = ".8",
                DateAdded = new DateTime(2015, 9, 5)
            });   
            var db = new MobilizeCloudEntities();
            var BlogPostsMax = (from r in db.BlogPosts
                             where r.IsDeleted == false
                             select r.TimeStamp).Max();
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-water-cooler",
                Priority = ".9",
                DateAdded = BlogPostsMax > new DateTime(2015, 9, 5) ? BlogPostsMax : new DateTime(2015, 9, 5)
            });
            var BlogPostsDevelopersMax = (from r in db.BlogPosts
                                          where r.IsDeleted == false && r.Category == "developer-and-tech-things"
                                          select r.TimeStamp).Max();
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-water-cooler/developer-and-tech-things",
                Priority = ".8",
                DateAdded = BlogPostsDevelopersMax > new DateTime(2015, 9, 5) ? BlogPostsDevelopersMax : new DateTime(2015, 9, 5)
            });
            var BlogPostsSmallBusinessMax = (from r in db.BlogPosts
                                          where r.IsDeleted == false && r.Category == "small-business-thoughts"
                                          select r.TimeStamp).Max();
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-water-cooler/small-business-thoughts",
                Priority = ".8",
                DateAdded = BlogPostsSmallBusinessMax > new DateTime(2015, 9, 5) ? BlogPostsSmallBusinessMax : new DateTime(2015, 9, 5)
            });
            var BlogPostsDigitalTrendsMax = (from r in db.BlogPosts
                                          where r.IsDeleted == false && r.Category == "digital-trends"
                                          select r.TimeStamp).Max();
            SitemapItems.Add(new SitemapItem
            {
                URL = "/our-water-cooler/digital-trends",
                Priority = ".8",
                DateAdded = BlogPostsDigitalTrendsMax > new DateTime(2015, 9, 5) ? BlogPostsDigitalTrendsMax : new DateTime(2015, 9, 5)
            });
            var BlogPosts = (from r in db.BlogPosts
                             where r.IsDeleted == false
                             orderby r.TimeStamp
                             select r).ToList();
            foreach(var BlogPost in BlogPosts.AsParallel())
            {
                SitemapItems.Add(new SitemapItem
                {
                    URL = "/our-water-cooler/" + BlogPost.Category + "/" + string.Format("{0:M/d/yyyy}", BlogPost.TimeStamp) + "/" + BlogPost.URL,
                    Priority = ".7",
                    DateAdded = BlogPostsDigitalTrendsMax > new DateTime(2015, 9, 5) ? BlogPostsDigitalTrendsMax : new DateTime(2015, 9, 5)
                });
            }
            SitemapItems.Add(new SitemapItem
            {
                URL = "/contact-us",
                Priority = ".9",
                DateAdded = new DateTime(2015, 9, 5)
            });
            return new SitemapActionResult(SitemapItems, Website);
        }
    }

You will notice above there are pages that get hard coded to the sitemap such as the contact us page, about us page and home page. These page urls will not be changing and therefor can be hard coded.
But there are several loop sections where blog posts urls are generated dynamically from the database. Instead of having to recreate the sitemap or add to it every time a new blog post is published the sitemap automatically updates itself every time the url is hit.

If you have any questions or need help with a future project, please feel free to contact us.