Auto-generating a sitemap conforming to Sitemap Protocol 0.9

Having recently installed BlogEngine.NET, I was interested to see the auto-generated sitemap that Mads had created. Basically, he implemented a custom HttpHandler that when requested would respone with XML that conformed to the Sitemap Protocol 0.9 which is dictated by sitemaps.org. This is an XML schema that all of the major search engines have signed up to which include Google, Yahoo! and Microsoft.

What I wanted to do is to implement this for my own site, but the custom handlers of Mads was tailored to BlogEngine.NET, so it required a bit of tweaking. Now, I have a Web.sitemap for my website, so in the scheme of wanting to do things from a generic point of view, I decided to implement the HttpHandler to utilise the Web.sitemap file to generate the sitemap response. To do this, first we have to load up the sitemap file…

XmlSiteMapProvider xmlSiteMap = new XmlSiteMapProvider();
NameValueCollection myCollection = new NameValueCollection(1);
myCollection.Add(“siteMapFile”, “Web.sitemap”);
xmlSiteMap.Initialize(“provider”, myCollection);
xmlSiteMap.BuildSiteMap();

Then we have to navigate through the tree structure identifying the nodes that we are interested in…

private static void ProcessNode(XmlWriter writer, SiteMapNode node, string attribute)
{
foreach (SiteMapNode siteMapNode in node.ChildNodes)
{
string actualUrl;
if (siteMapNode.HasChildNodes)
{
ProcessNode(writer, siteMapNode, attribute);
}
actualUrl = siteMapNode[attribute];
if (string.IsNullOrEmpty(actualUrl))
{
actualUrl = siteMapNode.Url;
if (string.IsNullOrEmpty(actualUrl))
{
continue;
}
}
WriteUrl(actualUrl, writer);
}
}

And lastly building up the XML response…

if(Uri.IsWellFormedUriString(actualUrl, UriKind.Relative))
{
FileInfo fileInfo = new FileInfo(HostingEnvironment.MapPath(actualUrl));
writer.WriteStartElement(“url”);
writer.WriteElementString(“loc”, HttpContext.Current.Request.Url.AbsoluteUri.Replace(HttpContext.Current.Request.Url.AbsolutePath, “”) + actualUrl);
writer.WriteElementString(“lastmod”, fileInfo.LastWriteTime.ToString(“yyyy-MM-dd”));
writer.WriteElementString(“changefreq”, “monthly”);
writer.WriteEndElement();
}

I have implemented this HttpHandler in a seperate component, simply to allow me to reference this utility from other websites that I have written, but you may decide to simply plug in the HttpHandler to your main project….the decision is yours.

Now, hopefully you’ve also realised that you’ll need to reference the HttpHandler in the website’s web.config……like so…

<httpHandlers>
<add verb=”*” path=”sitemap.axd” type=”CodeConsults.HttpHandlers.Generic.Sitemap” validate=”false”/>
</httpHandlers>

Now you can run your website, point your favoured browser to http://website/sitemap.axd and voila, your sitemap is available for all to see. But the last stage should be to update your robots.txt file to tell the search engines that you have a nice sitemap for them to use. To do this simply open your robots.txt file and enter the following…

sitemap: http://www.codeconsults.com/sitemap.axd

Alternative to Server.MapPath…use HostingEnvironment.MapPath

A call to the following context sensitive MapPath function does exactly what the documentation says it does.

System.Web.HttpContext.Current.Server.MapPath(“\filename.txt”);

It returns the physical file path that corresponds to the specified virtual path on the Web server. But this isn’t always what you want as it works on the current context which may be a web form running in a sub-directory of the main website.

In this case the solution is simple. Use the following code to map the path to a physical path on the server

System.Web.Hosting.HostingEnvironment.MapPath(“\filename.txt”);

How to get the size of blob data

I currently get blob data from a SQL database but a collegue pointed out that I wasn’t making it easy for him to see how much data is returned from the query. After a bit of head-scratching he found the solution which as usual is not in the MSDN documentation.

Here’s an example of how to do it…
using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
reader.Read(); // Get length of data by pass null as the byte array parameter
long dataLength = reader.GetBytes(0, 0, null, 0, 0);
Simple really….if only Microsoft would tell us this in the first place…!

Shrinking a SQL Server log file (.ldf)

I’ve been working quite a bit recently with a database that I have been constantly deleting from and re-adding data for testing an uploader. The uploader carries out hundreds of SQL statements and as such it has resulted in a rather large log file, which over time would get to the unmanageable size.

So I had a quick look for ways to reduce the log file size when I want to… In the end it’s simple Smile

DBCC SHRINKDATABASE(<database name>)

Simply put in the name of the database and execute it.

Re-seeding an identity column in SQL using DBCC CHECKIDENT

Here’s a handy bit of SQL that i’ve been using to reset the seed of an identity column for a table. I have often needed to do this when i’ve cleaned out a table, but have needed to start the identity entry back at 0 rather than it’s current seed value

DBCC CHECKIDENT (<table name>, RESEED, -1)
GO

Simply fill in the name of the table and execute it. This will reseed the identity to -1 meaning that when you next enter a new row it will start at 0.

Lastly, make sure you have the GO command between calls to DBCC or it won’t work 🙁

Getting the Calling method through Reflection

Having recently created a simple framework for other developers to use, I needed to create a custom Exception class to use when throwing exceptions.

When throwing an exception in a WinForms application I always generate my own Exception class, which adds some other useful information that I can package along with the actual exception that was originally thrown. Although the Call Stack is included in the actual exception, one thing that I like to do is tell the developer the method in which the exception was originally thrown. This removes the need for the developer to navigate through the exception as all they are initially after is where the Exception occured.

In the past I would have normally simply passed in the method name like so:

throw new Exception(connSettings, MethodBase.GetCurrentMethod().Name, “Argument is Null”, ex);

But I decided to spend some time making this transparent. In the end I was able to put this in the actual Exception class using the following method which is called as a part of the constructor of the Exception class:

private void SetCallingMethod()

{
method = new StackFrame(2, false).GetMethod().Name;
}

In this we open up a new stack trace and navigate to the second frame in the trace (remembering that frame 1 of the stack will result in the constructor method). Now the code to create the new exception is simpler:

throw new Exception(connSettings, “Argument is Null”, ex);

Tagged