Dynamically Create Google Sitemap with ASP.NET

This article will cover dynamically generating your sitemap to submit to Google Sitemaps using ASP.NET and as usual the code will be available in C# and VB.NET. Whenever you develop a site with the intention of putting it on the internet, it’s necessary to do everything you can to index your site with the various search engines using all the tools at your disposal. Google allows you to submit a sitemap of your site to their search engine to help optimize your searching. You can see more details here

Google Sitemaps

We’re going to use HTTP handlers which are files that work similar to ISAPI modules but with no need to install on the server, ASP.NET handles everything for you.

First step is to create a .sitemap file and populate it.







Now that we have the sitemap file, we can use a handler to process the request. The handler will do the following

  1. Prepare all the XML header information for the file
  2. Read in the sitemap file
  3. Create root node, then nodes for each page in the sitemap file

Pretty straight forward really. Now to the code!

C#
<%@ WebHandler Language="C#" Class="OurSiteMap" %>
using System;
using System.Web;
using System.Xml;
using System.Text;
using System.IO;

public class OurSiteMap : IHttpHandler
{
private XmlWriter xmlWriter;

public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/xml";

XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
settings.Indent = true;
xmlWriter = XmlWriter.Create(context.Response.OutputStream, settings);
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9");

// Add root node
AddUrl(SiteMap.RootNode);

// Add all other nodes
SiteMapNodeCollection nodes = SiteMap.RootNode.GetAllNodes();
foreach (SiteMapNode node in nodes) {
AddUrl(node);
}

xmlWriter.WriteEndElement();
xmlWriter.WriteEndDocument();
xmlWriter.Flush();
}

private void AddUrl(SiteMapNode node)
{
// ignore any nodes that are empty
if (string.IsNullOrEmpty(node.Url))
{
return;
}

// ignore any nodes that are not part of the site
if (node.Url.StartsWith("http", true, null)) {
return;
}

// Open url tag
xmlWriter.WriteStartElement("url");

// Write location
xmlWriter.WriteStartElement("loc");
xmlWriter.WriteString(GetFullUrl(node.Url));
xmlWriter.WriteEndElement();

// Write last modified
xmlWriter.WriteStartElement("lastmod");
xmlWriter.WriteString(GetLastModifiedDate(node.Url));
xmlWriter.WriteEndElement();

// Close url tag
xmlWriter.WriteEndElement();
}

private string GetFullUrl(string url)
{
HttpContext currentContext = HttpContext.Current;
string server = currentContext.Request.Url.GetComponents(UriComponents.SchemeAndServer, UriFormat.UriEscaped);
return CombineURL(server, url);
}

private string CombineURL(string urlBase, string url)
{
urlBase = urlBase.TrimEnd(new char[] { '/' });
url = url.TrimStart(new char[] { '/' });
return urlBase + "/" + url;
}

private string GetLastModifiedDate(string url)
{
HttpContext currentContext = HttpContext.Current;
string path = currentContext.Server.MapPath(url);
return File.GetLastWriteTimeUtc(path).ToString("s");
}

public bool IsReusable
{
get { return true; }
}
}

VB.NET
<%@ WebHandler Language="VB" Class="OurSiteMap" %>
Imports System
Imports System.Web
Imports System.Xml
Imports System.Text
Imports System.IO

Public Class OurSiteMap
Implements IHttpHandler

Private xmlWriter As XmlWriter

Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/xml"

Dim settings As New XmlWriterSettings()
settings.Encoding = Encoding.UTF8
settings.Indent = True
xmlWriter = XmlWriter.Create(context.Response.OutputStream, settings)
xmlWriter.WriteStartDocument()
xmlWriter.WriteStartElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9")

' Add root node
AddUrl(SiteMap.RootNode)

' Add all other nodes
Dim nodes As SiteMapNodeCollection = SiteMap.RootNode.GetAllNodes()
For Each node As SiteMapNode In nodes
AddUrl(node)
Next

xmlWriter.WriteEndElement()
xmlWriter.WriteEndDocument()
xmlWriter.Flush()
End Sub

Private Sub AddUrl(ByVal node As SiteMapNode)
' ignore any nodes that are empty
If String.IsNullOrEmpty(node.Url) Then
Return
End If

' ignore any nodes that are not part of the site
If node.Url.StartsWith("http",True,Nothing) Then
Return
End If

' Open url tag
xmlWriter.WriteStartElement("url")

' Write location
xmlWriter.WriteStartElement("loc")
xmlWriter.WriteString(GetFullUrl(node.Url))
xmlWriter.WriteEndElement()

' Write last modified
xmlWriter.WriteStartElement("lastmod")
xmlWriter.WriteString(GetLastModifiedDate(node.Url))
xmlWriter.WriteEndElement()

' Close url tag
xmlWriter.WriteEndElement()
End Sub

Private Function GetFullUrl(ByVal url As String) As String
Dim currentContext As HttpContext = HttpContext.Current
Dim server As String = currentContext.Request.Url.GetComponents(UriComponents.SchemeAndServer, UriFormat.UriEscaped)
Return CombineURL(server,url)
End Function

Private Function CombineURL(ByVal urlBase As String, ByVal url As String) As String
urlBase = urlBase.TrimEnd(New Char() {"/"c})
url = url.TrimStart(New Char() {"/"c})
Return urlBase + "/" + url
End Function

Private Function GetLastModifiedDate(ByVal url As String) As String
Dim currentContext As HttpContext = HttpContext.Current
Dim path As String = currentContext.Server.MapPath(url)
Return File.GetLastWriteTimeUtc(path).ToString("s")
End Function

Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class

That’s it! Now you can submit your .ashx file as the XML to Google Sitemaps and you are done!

One Response to "Dynamically Create Google Sitemap with ASP.NET"

  1. Exactly what I was looking for. I’ve searched so many articles and couldn’t found the right recipe.

    Thanks alot :)

Leave a Reply