<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ian Mercer &#187; sitemap</title>
	<atom:link href="http://blog.abodit.com/tag/sitemap/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.abodit.com</link>
	<description>Living in the World&#039;s Smartest House</description>
	<lastBuildDate>Sat, 07 Jan 2012 19:50:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Building sitemap.xml for SEO ASP.NET MVC</title>
		<link>http://blog.abodit.com/2010/02/sitemap-xml-asp-net-aspnet-mvc/</link>
		<comments>http://blog.abodit.com/2010/02/sitemap-xml-asp-net-aspnet-mvc/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 23:30:58 +0000</pubDate>
		<dc:creator>Ian Mercer</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[SEO]]></category>
		<category><![CDATA[SEO with ASP.NET MVC]]></category>
		<category><![CDATA[sitemap]]></category>

		<guid isPermaLink="false">http://blog.abodit.com/?p=423</guid>
		<description><![CDATA[Creating a sitemap.xml file for Google and other search engines can be accomplished in MVC using a simple ActionResult that returns the appropriate XML blog. The problem however is in generating the list of URLs to go into that sitemap.xml file. In ASP.NET MVC there is no distinction between an action method that is a <a href="http://blog.abodit.com/2010/02/sitemap-xml-asp-net-aspnet-mvc/" class="more-link">More &#62;</a>]]></description>
			<content:encoded><![CDATA[<p>Creating a sitemap.xml file for Google and other search engines can be accomplished in MVC using a simple ActionResult that returns the appropriate XML blog.  The problem however is in generating the list of URLs to go into that sitemap.xml file.</p>
<p>In ASP.NET MVC there is no distinction between an action method that is a page and one that is a service call.  To remedy that let&#8217;s create an ActionFilterAttribute that can be applied to any method to mark it as a page and to record the URL that we want that page to show up as in our sitemap:</p>
<div style="font-family: Courier New; font-size: 10pt; color: black; background: white;">
<p style="margin: 0px;"><span style="color: #2b91af;"> 1</span> <span style="color: gray;">///</span><span style="color: green;"> </span><span style="color: gray;">&lt;summary&gt;</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 2</span> <span style="color: gray;">///</span><span style="color: green;"> This attribute indicates that a method is an actual page and gives the data for it</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 3</span> <span style="color: gray;">///</span><span style="color: green;"> </span><span style="color: gray;">&lt;/summary&gt;</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 4</span> [<span style="color: #2b91af;">AttributeUsage</span>(<span style="color: #2b91af;">AttributeTargets</span>.Class | <span style="color: #2b91af;">AttributeTargets</span>.Method, Inherited = <span style="color: blue;">true</span>, AllowMultiple = <span style="color: blue;">false</span>)]</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 5</span> <span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">MVCUrlAttribute</span> : <span style="color: #2b91af;">ActionFilterAttribute</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 6</span> {</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 7</span> <span style="color: blue;">public</span> <span style="color: blue;">string</span> Url { <span style="color: blue;">get</span>; <span style="color: blue;">private</span> <span style="color: blue;">set</span>; }</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 8</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 9</span> <span style="color: blue;">public</span> MVCUrlAttribute(<span style="color: blue;">string</span> url)</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 10</span> {</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 11</span> <span style="color: blue;">this</span>.Url = url;</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 12</span> }</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 13</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 14</span> <span style="color: blue;">public</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnResultExecuting(<span style="color: #2b91af;">ResultExecutingContext</span> filterContext)</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 15</span> {</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 16</span> <span style="color: blue;">string</span> fullyQualifiedUrl = filterContext.HttpContext.Request.Url.GetLeftPart(<span style="color: #2b91af;">UriPartial</span>.Authority) + <span style="color: blue;">this</span>.Url;</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 17</span> <span style="color: green;">// We build HTML here because we want the View to be easily able to include it without any conditionals</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 18</span> <span style="color: green;">// and because the ASP.NET WebForms view engine sometimes doesn&#8217;t subsitute &lt;% in certain head items</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 19</span> filterContext.Controller.ViewData[<span style="color: #a31515;">"CanonicalUrl"</span>] = <span style="color: #a31515;">@&#8221;&lt;link rel=&#8221;"canonical&#8221;" href=&#8221;"&#8221;</span> + fullyQualifiedUrl + <span style="color: #a31515;">&#8221; /&gt;&#8221;</span>;</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 20</span> <span style="color: blue;">base</span>.OnResultExecuting(filterContext);</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 21</span> }</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 22</span> }</p>
</div>
<p>You may wonder at this point why we can&#8217;t just use the Routing table to figure this out.  The issue is that multiple routes may map onto one page but we still want it to show up just once in the sitemap otherwise we will get slammed for duplicate content.  We also want to be able to mark each page with its canonical URL.</p>
<p>Now we can use reflection to find all of the &#8216;pages&#8217; in our ASP.NET MVC Application and then build a sitemap.xml file from them.</p>
<div style="font-family: Courier New; font-size: 10pt; color: black; background: white;">
<p style="margin: 0px;"><span style="color: #2b91af;"> 1</span> <span style="color: #2b91af;">List</span>&lt;<span style="color: blue;">string</span>&gt; allPageUrls = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span>&lt;<span style="color: blue;">string</span>&gt;();</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 2</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 3</span> <span style="color: green;">// Find all the MVC Routes</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 4</span> Log.Debug(<span style="color: #a31515;">&#8220;*** FINDING ALL MVC ROUTES MARKED FOR INCLUSION IN SITEMAP&#8221;</span>);</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 5</span> <span style="color: blue;">var</span> allControllers = <span style="color: #2b91af;">Assembly</span>.GetExecutingAssembly().GetTypes().Where(t =&gt; t.IsSubclassOf(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">Controller</span>)));</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 6</span> Log.DebugFormat(<span style="color: #a31515;">&#8220;Found {0} controllers&#8221;</span>, allControllers.Count());</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 7</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 8</span> <span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> controllerType <span style="color: blue;">in</span> allControllers)</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 9</span> {</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 10</span> <span style="color: blue;">var</span> allPublicMethodsOnController = controllerType.GetMethods(<span style="color: #2b91af;">BindingFlags</span>.Public | <span style="color: #2b91af;">BindingFlags</span>.Instance);</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 11</span> Log.DebugFormat(<span style="color: #a31515;">&#8220;Found {0} public methods on {1}&#8221;</span>, allPublicMethodsOnController.Count(), controllerType.Name);</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 12</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 13</span> <span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> publicMethod <span style="color: blue;">in</span> allPublicMethodsOnController)</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 14</span> {</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 15</span> <span style="color: blue;">var</span> mvcurlattr = publicMethod.GetCustomAttributes(<span style="color: blue;">true</span>).OfType&lt;<span style="color: #2b91af;">MVCUrlAttribute</span>&gt;().FirstOrDefault();</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 16</span> <span style="color: blue;">if</span> (mvcurlattr != <span style="color: blue;">null</span>)</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 17</span> {</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 18</span> <span style="color: blue;">string</span> url = mvcurlattr.Url;</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 19</span> Log.Debug(<span style="color: #a31515;">&#8220;Found &#8220;</span> + controllerType.Name + <span style="color: #a31515;">&#8220;.&#8221;</span> + publicMethod.Name + <span style="color: #a31515;">&#8221; &lt;&#8211; &#8220;</span> + url);</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 20</span> allPageUrls.Add(url);</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 21</span> }</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 22</span> }</p>
<p style="margin: 0px;"><span style="color: #2b91af;"> 23</span> }</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.abodit.com/2010/02/sitemap-xml-asp-net-aspnet-mvc/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

