<?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>Alonso Robles &#187; ASP.NET</title>
	<atom:link href="http://alonsorobles.com/category/web-development/aspnet/feed/" rel="self" type="application/rss+xml" />
	<link>http://alonsorobles.com</link>
	<description>technology, academia, and other tidbits from the trenches of a boggled mind</description>
	<lastBuildDate>Wed, 18 Apr 2012 02:48:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>RavenDB Document Identifiers and MVC Routes</title>
		<link>http://alonsorobles.com/2012/03/21/ravendb-document-identifiers-and-mvc-routes/</link>
		<comments>http://alonsorobles.com/2012/03/21/ravendb-document-identifiers-and-mvc-routes/#comments</comments>
		<pubDate>Wed, 21 Mar 2012 11:38:39 +0000</pubDate>
		<dc:creator>Alonso Robles</dc:creator>
				<category><![CDATA[.NET Development]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[RavenDB]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[MVC 3]]></category>
		<category><![CDATA[ravendb]]></category>

		<guid isPermaLink="false">http://alonsorobles.com/?p=353</guid>
		<description><![CDATA[Following my recent post about getting started with RavenDB, I decided to work on a small shopping cart demo application based on the sample depot application that is written in part 2 of Agile Web Development with Rails when I &#8230; <a href="http://alonsorobles.com/2012/03/21/ravendb-document-identifiers-and-mvc-routes/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Following my recent post about <a href="http://www.headspring.com/2012/03/getting-started-with-ravendb">getting started with RavenDB</a>, I decided to work on a small shopping cart demo application based on the sample depot application that is written in part 2 of <a href="http://www.amazon.com/gp/product/1934356549/ref=as_li_ss_tl?ie=UTF8&amp;tag=importchaos-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1934356549">Agile Web Development with Rails </a><img style="margin: 0px; border-style: none !important;" src="http://www.assoc-amazon.com/e/ir?t=importchaos-20&amp;l=as2&amp;o=1&amp;a=1934356549" alt="" width="1" height="1" border="0" /> when I started running into some trouble with the RavenDB auto generated document identifiers and the MVC routes. Like any other programmer, I quickly performed a Google search to see what others had done. The search led me to a few Stack Overflow well voted answers all leading me to <a href="http://weblogs.asp.net/shijuvarghese/archive/2010/06/04/how-to-work-ravendb-id-with-asp-net-mvc-routes.aspx">a blog post on this topic</a>. Problem solved right? Not exactly. Two solutions were proposed. But before getting into those, I want to describe the problem a little more.</p>
<h3>The Problem Described</h3>
<p>Take a look at the ASP.NET MVC 3 default route found in the <em>Global.asax.cs</em> file: <div id="gist-2136967" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">RegisterRoutes</span><span class="p">(</span><span class="n">RouteCollection</span> <span class="n">routes</span><span class="p">)</span></div><div class='line' id='LC2'><span class="p">{</span></div><div class='line' id='LC3'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">routes</span><span class="p">.</span><span class="n">IgnoreRoute</span><span class="p">(</span><span class="s">&quot;{resource}.axd/{*pathInfo}&quot;</span><span class="p">);</span></div><div class='line' id='LC4'><br/></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">routes</span><span class="p">.</span><span class="n">MapRoute</span><span class="p">(</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s">&quot;Default&quot;</span><span class="p">,</span> <span class="c1">// Route name</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s">&quot;{controller}/{action}/{id}&quot;</span><span class="p">,</span> <span class="c1">// URL with parameters</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">new</span> <span class="p">{</span> <span class="n">controller</span> <span class="p">=</span> <span class="s">&quot;Home&quot;</span><span class="p">,</span> <span class="n">action</span> <span class="p">=</span> <span class="s">&quot;Index&quot;</span><span class="p">,</span> <span class="n">id</span> <span class="p">=</span> <span class="n">UrlParameter</span><span class="p">.</span><span class="n">Optional</span> <span class="p">}</span> <span class="c1">// Parameter defaults</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">);</span></div><div class='line' id='LC10'><span class="p">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2136967/c084f7d16a710152ca01c1d4d6f643a98f703ea3/gistfile1.cs" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2136967#file_gistfile1.cs" style="float:right;margin-right:10px;color:#666">gistfile1.cs</a>
            <a href="https://gist.github.com/2136967">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>
</p>
<p>This default route will basically allow you access to a resource using the basic URL convention that may look something this: <em>http://localhost/products/edit/1</em> . However, the default RavenDB auto generated document identifier for the product document ends up looking something like this: p<em>roducts/1</em>. (More information about the RavenDB <a href="http://ravendb.net/docs/client-api/basic-operations/saving-new-document">document identifiers one of the documentation pages</a>. ) So the URL to access that product resource for editing would really have to look like this: <em>http://localhost/products/edit/products/1</em>. Well that doesn’t work for two reasons:</p>
<ol>
<li>The default route will not be matched so the URL will not be routed the correct controller action.</li>
<li>The URL is not SEO friendly.</li>
</ol>
<p>Typically, this can be solved by using a custom route that access this resource by a natural key where the URL would probably end up looking like this: <em>http://localhost/products/product-name/edit</em>. This makes the URL SEO friendly, easy to read, and easy to route. However, there are some situations where the document identifier makes sense and I will continue this post on the assumption that this is the case.</p>
<p>The blog post mentioned above presents two solutions:</p>
<ul>
<li>Solution 1 – Change the identity parts separator convention for the RavenDB document store.</li>
<li>Solution 2 – Modify the ASP.NET default route</li>
</ul>
<h3>Issues with Solution 1</h3>
<p>Let’s look at the first solution. The suggestion is to change the identity separator convention from a slash (/) to a dash (-). The convention is really easy to change during the initialization of the document store object.</p>
<div id="gist-2137105" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="n">documentStore</span> <span class="p">=</span> <span class="k">new</span> <span class="n">DocumentStore</span> <span class="p">{</span> <span class="n">Url</span> <span class="p">=</span> <span class="s">&quot;http://localhost:8080/&quot;</span> <span class="p">};</span></div><div class='line' id='LC2'><span class="n">documentStore</span><span class="p">.</span><span class="n">Initialize</span><span class="p">();</span></div><div class='line' id='LC3'><span class="n">documentStore</span><span class="p">.</span><span class="n">Conventions</span><span class="p">.</span><span class="n">IdentityPartsSeparator</span> <span class="p">=</span> <span class="s">&quot;-&quot;</span><span class="p">;</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2137105/c7f32ad41de8d44b30c10c8138edcb12215b3ad9/gistfile1.cs" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2137105#file_gistfile1.cs" style="float:right;margin-right:10px;color:#666">gistfile1.cs</a>
            <a href="https://gist.github.com/2137105">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>This makes RavenDB generate document identifiers that now look like: <em>products-1</em>. Now we can generate a URL that will match the default route and may look like: <em>http://localhost/products/edit/products-1</em>. I still find some issues this this. Namely, the URL is still not really SEO friendly and not really human readable. I don’t like the idea of exposing an identifier that was forced on me by RavenDB since it essentially has coupled my URL to the RavenDB identifier convention. It just doesn’t feel right.</p>
<h3>Issues with Solution 2</h3>
<p>This solution suggests the change of the default route to something like:</p>
<div id="gist-2137442" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">RegisterRoutes</span><span class="p">(</span><span class="n">RouteCollection</span> <span class="n">routes</span><span class="p">)</span></div><div class='line' id='LC2'><span class="p">{</span></div><div class='line' id='LC3'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">routes</span><span class="p">.</span><span class="n">IgnoreRoute</span><span class="p">(</span><span class="s">&quot;{resource}.axd/{*pathInfo}&quot;</span><span class="p">);</span></div><div class='line' id='LC4'><br/></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">routes</span><span class="p">.</span><span class="n">MapRoute</span><span class="p">(</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s">&quot;Default&quot;</span><span class="p">,</span> <span class="c1">// Route name</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s">&quot;{controller}/{action}/{*id}&quot;</span><span class="p">,</span> <span class="c1">// URL with parameters</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">new</span> <span class="p">{</span> <span class="n">controller</span> <span class="p">=</span> <span class="s">&quot;Home&quot;</span><span class="p">,</span> <span class="n">action</span> <span class="p">=</span> <span class="s">&quot;Index&quot;</span><span class="p">,</span> <span class="n">id</span> <span class="p">=</span> <span class="n">UrlParameter</span><span class="p">.</span><span class="n">Optional</span> <span class="p">}</span> <span class="c1">// Parameter defaults</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">);</span></div><div class='line' id='LC10'><span class="p">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2137442/d2469600b573423dec4dbb7fd4e1153ac431fd34/gistfile1.cs" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2137442#file_gistfile1.cs" style="float:right;margin-right:10px;color:#666">gistfile1.cs</a>
            <a href="https://gist.github.com/2137442">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>This will allow route to match a URL that looked like the first one: <em>http://localhost/products/edit/products/1</em>. I don’t like this either. While it does allow the default route to match and do its job. The URL is just ugly. It also clobbers the id making the route also match something like this: <em>http://localhost/products/edit/products/more-junk/1</em>. Obviously this is not SEO friendly or human readable. Again, it just doesn’t feel right.</p>
<h3>Another Option</h3>
<p>After some digging and learning about more about the document identity field, identity type converters, custom identifiers with the document key generator convention, I realized there was a pretty simple alternative to the two options above. But to see it and to understand the simplicity, you have to look at the source of the problem.</p>
<p>The reason that MVC routes are choking on the preconfigured RavenDB document identity convention is because our models included a string based identity property. I realized I had done this on purpose to ease the mapping of the RavenDB document identifier and my object identifier. Take a look at my product object definition:</p>
<div id="gist-2205818" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="k">public</span> <span class="k">class</span> <span class="nc">Product</span></div><div class='line' id='LC2'><span class="p">{</span></div><div class='line' id='LC3'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">public</span> <span class="kt">string</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span></div><div class='line' id='LC4'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">public</span> <span class="kt">string</span> <span class="n">Title</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">public</span> <span class="kt">string</span> <span class="n">Description</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">public</span> <span class="kt">string</span> <span class="n">ImageUrl</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">public</span> <span class="kt">decimal</span> <span class="n">Price</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span></div><div class='line' id='LC8'><span class="p">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2205818/f76935b0b33b0148ca2a67b57078be7a859b3c4f/Product.cs" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2205818#file_product.cs" style="float:right;margin-right:10px;color:#666">Product.cs</a>
            <a href="https://gist.github.com/2205818">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>The shopping cart identifier is a string. Why would it be a string? It could have been an integer or a Guid or something else. It could have even been a natural key of some sort. Or even a compound key. It doesn’t have to be a string. Taking another look at the  IDocumentSession interface we can see we have four load methods available.</p>
<div id="gist-2153059" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="k">namespace</span> <span class="nn">Raven.Client</span></div><div class='line' id='LC2'><span class="p">{</span></div><div class='line' id='LC3'>&nbsp;&nbsp;<span class="k">public</span> <span class="k">interface</span> <span class="n">IDocumentSession</span> <span class="p">:</span> <span class="n">IDisposable</span></div><div class='line' id='LC4'>&nbsp;&nbsp;<span class="p">{</span></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">ISyncAdvancedSessionOperation</span> <span class="n">Advanced</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">void</span> <span class="n">Delete</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">entity</span><span class="p">);</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">T</span> <span class="n">Load</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="kt">string</span> <span class="n">id</span><span class="p">);</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">T</span><span class="p">[]</span> <span class="n">Load</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="k">params</span> <span class="kt">string</span><span class="p">[]</span> <span class="n">ids</span><span class="p">);</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">T</span><span class="p">[]</span> <span class="n">Load</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">IEnumerable</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span> <span class="n">ids</span><span class="p">);</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">T</span> <span class="n">Load</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">ValueType</span> <span class="n">id</span><span class="p">);</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">IRavenQueryable</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="n">Query</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="kt">string</span> <span class="n">indexName</span><span class="p">);</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">IRavenQueryable</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="n">Query</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;();</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">IRavenQueryable</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="n">Query</span><span class="p">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">TIndexCreator</span><span class="p">&gt;()</span> <span class="k">where</span> <span class="n">TIndexCreator</span> <span class="p">:</span> <span class="n">AbstractIndexCreationTask</span><span class="p">,</span> <span class="k">new</span><span class="p">();</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">ILoaderWithInclude</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;</span> <span class="n">Include</span><span class="p">(</span><span class="kt">string</span> <span class="n">path</span><span class="p">);</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">ILoaderWithInclude</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="n">Include</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">Expression</span><span class="p">&lt;</span><span class="n">Func</span><span class="p">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;&gt;</span> <span class="n">path</span><span class="p">);</span></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">void</span> <span class="nf">SaveChanges</span><span class="p">();</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">void</span> <span class="nf">Store</span><span class="p">(</span><span class="kt">object</span> <span class="n">entity</span><span class="p">,</span> <span class="n">Guid</span> <span class="n">etag</span><span class="p">);</span></div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">void</span> <span class="nf">Store</span><span class="p">(</span><span class="kt">object</span> <span class="n">entity</span><span class="p">,</span> <span class="n">Guid</span> <span class="n">etag</span><span class="p">,</span> <span class="kt">string</span> <span class="n">id</span><span class="p">);</span></div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">void</span> <span class="nf">Store</span><span class="p">(</span><span class="kt">object</span> <span class="n">entity</span><span class="p">);</span></div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">void</span> <span class="nf">Store</span><span class="p">(</span><span class="kt">object</span> <span class="n">entity</span><span class="p">,</span> <span class="kt">string</span> <span class="n">id</span><span class="p">);</span></div><div class='line' id='LC21'>&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC22'><span class="p">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2153059/64fbb98ab03ac0e3fc1f07fb5f07d4851a1c7e5c/gistfile1.cs" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2153059#file_gistfile1.cs" style="float:right;margin-right:10px;color:#666">gistfile1.cs</a>
            <a href="https://gist.github.com/2153059">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>After thinking about the difference between the method that accepts a string identifier and the one that accepts a value type identifier, I realized that all I had to do was change my identifier type from a string to a value type and I’m done. No fancy mapping or parsing the document identifier from RavenDB to the web browser and back. No changes to the default MVC route. No changes to the default identity separator convention. It just worked. My URLs are SEO friendly and more readable.</p>
<p>All I had to do was change the object identifier type.</p>
<div id="gist-2205829" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="k">public</span> <span class="k">class</span> <span class="nc">Product</span></div><div class='line' id='LC2'><span class="p">{</span></div><div class='line' id='LC3'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">public</span> <span class="kt">int</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span></div><div class='line' id='LC4'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">public</span> <span class="kt">string</span> <span class="n">Title</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">public</span> <span class="kt">string</span> <span class="n">Description</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">public</span> <span class="kt">string</span> <span class="n">ImageUrl</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">public</span> <span class="kt">decimal</span> <span class="n">Price</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span></div><div class='line' id='LC8'><span class="p">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2205829/dec0f6ca4b6fc6c058955333b789496725191f02/Product.cs" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2205829#file_product.cs" style="float:right;margin-right:10px;color:#666">Product.cs</a>
            <a href="https://gist.github.com/2205829">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>That was easy.</p>
<p>Of course this doesn’t solve everything. What if I really do need a string based identifier? This will probably require tweaking the behavior of the RavenDB client. I also don’t have an answer for compound keys and other natural keys which may not be a value type. Some of these may require more thought from both the RavenDB side and the MVC side of my project. But that is another problem to think about some other time.</p>
]]></content:encoded>
			<wfw:commentRss>http://alonsorobles.com/2012/03/21/ravendb-document-identifiers-and-mvc-routes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>TODO: When Creating a New ASP.NET MVC Project</title>
		<link>http://alonsorobles.com/2012/03/20/todo-when-creating-a-new-asp-net-mvc-project/</link>
		<comments>http://alonsorobles.com/2012/03/20/todo-when-creating-a-new-asp-net-mvc-project/#comments</comments>
		<pubDate>Tue, 20 Mar 2012 14:30:00 +0000</pubDate>
		<dc:creator>Alonso Robles</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[MVC 3]]></category>
		<category><![CDATA[TODO]]></category>

		<guid isPermaLink="false">http://alonsorobles.com/?p=346</guid>
		<description><![CDATA[Michael Kennedy put this great little blog post together outlining 9 things we can do when starting a new ASP.NET MVC 3 project. It’s a good starting point since the MVC 3 web application template is already out of date &#8230; <a href="http://alonsorobles.com/2012/03/20/todo-when-creating-a-new-asp-net-mvc-project/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Michael Kennedy put this great little blog post together outlining <a href="http://blog.michaelckennedy.net/2012/03/07/9-ways-your-brand-new-mvc-project-can-be-better/">9 things we can do when starting a new ASP.NET MVC 3 project</a>. It’s a good starting point since the MVC 3 web application template is already out of date with many things. Here is a quick run down of the things I do and don’t in comparison to his list:</p>
<ol>
<li>Remove the <em>MicrosoftMvc*.js</em> AJAX and validation scripts.</li>
<li>Update NuGet packages… I do things a little differently here. I completely remove the <em>EntityFramework</em> package (I may add it or another ORM back in later, but that ends up usually in a persistence specific project and it is usually a micro ORM). I also remove <em>jQuery Visual Studio 2010 Intellisense</em> package since the contents are bundled with the updated the other jQuery packages anyway. I remove the <em>jQuery UI</em> package (and add it back when I need it). Update the remaining jQuery and Modernizr packages.</li>
<li>Create my own <em>JavaScripts</em> directory to avoid overwrites when updating or installing other JavaScript based packages.</li>
<li>Love this tip! Who doesn’t like intellisense?</li>
<li>Already did this in step 2.</li>
<li>I’m not the sharpest tool in the shed when it comes to CSS. But this tip sounds like a good idea. Wonder if there is a NuGet package for Eric Meyer’s <em>reset.css</em> file?</li>
<li>I skip this step. In my opinion, the only models in my MVC project are view models anyway. So I leave the <em>Models</em> folder in my MVC project alone. If my project requires business models, they get placed in a business logic project. If I have persistence models, they get placed in my persistence project.</li>
<li>Another area where I am not the sharpest tool in the shed. But I do like fast loading pages, so I am going to try this tip out and put all the JavaScript files that I can at the bottom. Just remember that some do need to go at the top.</li>
<li>And yet another tip that I haven’t tried, but plan.</li>
</ol>
<p>As a recap, tips 1, 3, and 4 make perfect sense. Tip 2 also makes sense, but I tweak it to fit my needs and I suggest you do to. I glaze over tip 5 and skip tip 7 because it was either previously addressed or doesn’t fit my needs. Tips 6, 8, and 9 sound like good ideas and I need to try them out.</p>
]]></content:encoded>
			<wfw:commentRss>http://alonsorobles.com/2012/03/20/todo-when-creating-a-new-asp-net-mvc-project/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Enabling the SharePoint Safe Mode Call Stack, Disabling Custom Errors and Enabiling Compilation Debugging</title>
		<link>http://alonsorobles.com/2008/06/09/enabling-the-sharepoint-safe-mode-call-stack-disabling-custom-errors-and-enabling-compilation-debugging/</link>
		<comments>http://alonsorobles.com/2008/06/09/enabling-the-sharepoint-safe-mode-call-stack-disabling-custom-errors-and-enabling-compilation-debugging/#comments</comments>
		<pubDate>Tue, 10 Jun 2008 02:21:43 +0000</pubDate>
		<dc:creator>Alonso Robles</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Internet Information Services]]></category>
		<category><![CDATA[Sharepoint Server]]></category>
		<category><![CDATA[Windows Sharepoint Services]]></category>
		<category><![CDATA[.NET Development]]></category>
		<category><![CDATA[asp.net 2.0]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[iis 7.0]]></category>
		<category><![CDATA[moss 2007]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[wss 3.0]]></category>

		<guid isPermaLink="false">http://blogs.importchaos.com/alonsorobles/?p=58</guid>
		<description><![CDATA[When developling for SharePoint, I find myself always turning on the call stack and disabiling the custom errors in my development environment. It really does help when trying to debug run-time problems. I know there a few posts out there &#8230; <a href="http://alonsorobles.com/2008/06/09/enabling-the-sharepoint-safe-mode-call-stack-disabling-custom-errors-and-enabling-compilation-debugging/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>When developling for SharePoint, I find myself always turning on the call stack and disabiling the custom errors in my development environment. It really does help when trying to debug run-time problems. I know there a few posts out there that describe how to do this, but I figured I would repost it as a reference for myself (which you are welcome to use).</p>
<p>Just remember that I do this in my development environment only. I don&#8217;t recommend changing the <em>web.config</em> files in any other environment.</p>
<p><strong>Enabling the Call Stack</strong></p>
<p>Set the value <em>CallStack<strong> </strong></em>attribute in the <em>SafeMode </em>element in the <em>web.config</em> file to <em>true</em>.</p>
<pre>&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
 &lt;configuration&gt;
  ...
  &lt;SharePoint&gt;
   &lt;SafeMode MaxControls="200"
             CallStack="true"
             DirectFileDependencies="10"
             TotalFileDependencies="50"
             AllowPageLevelTrace="false"&gt;
    ...
   &lt;/SafeMode&gt;
   ...
 &lt;/SharePoint&gt;
 ...
&lt;/configuration&gt;</pre>
<p><strong>Disabling Custom Errors</strong></p>
<p>Set the value of the <em>mode</em> attribute in the <em>customErrors</em> element to <em>Off</em>.</p>
<pre>&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
 &lt;configuration&gt;
  ...
  &lt;system.web&gt;
   ...
   &lt;customErrors mode="Off" /&gt;
   ...
  &lt;/system.web&gt;
 ...
&lt;/configuration&gt;</pre>
<p><strong>Enabiling Compilation Debugging</strong></p>
<p>Set the value of the <em>debug </em>attriute in the <em>compilation</em> element to <em>true</em>.</p>
<pre>&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
 &lt;configuration&gt;
  ...
  &lt;system.web&gt;
   ...
   &lt;compilation debug="true"&gt;
    ...
   &lt;/compilation&gt;
   ...
  &lt;/system.web&gt;
 ...
&lt;/configuration&gt;</pre>
<p> <strong>Putting it all together</strong></p>
<pre>&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
 &lt;configuration&gt;
  ...
  &lt;SharePoint&gt;
   &lt;SafeMode MaxControls="200"
             CallStack="true"
             DirectFileDependencies="10"
             TotalFileDependencies="50"
             AllowPageLevelTrace="false"&gt;
    ...
   &lt;/SafeMode&gt;
   ...
 &lt;/SharePoint&gt;
 &lt;system.web&gt;
   ...
   &lt;customErrors mode="Off" /&gt;
   ...
   &lt;compilation debug="true"&gt;
    ...
   &lt;/compilation&gt;
   ...
  &lt;/system.web&gt;
 ...
&lt;/configuration&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://alonsorobles.com/2008/06/09/enabling-the-sharepoint-safe-mode-call-stack-disabling-custom-errors-and-enabling-compilation-debugging/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>SharePoint Ramp Up Webcasts for ASP.NET Developers</title>
		<link>http://alonsorobles.com/2008/05/20/sharepoint-ramp-up-webcasts-for-aspnet-developers/</link>
		<comments>http://alonsorobles.com/2008/05/20/sharepoint-ramp-up-webcasts-for-aspnet-developers/#comments</comments>
		<pubDate>Tue, 20 May 2008 17:53:05 +0000</pubDate>
		<dc:creator>Alonso Robles</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Windows Sharepoint Services]]></category>
		<category><![CDATA[asp.net 2.0]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[webcast]]></category>
		<category><![CDATA[wss 3.0]]></category>

		<guid isPermaLink="false">http://blogs.importchaos.com/alonsorobles/?p=39</guid>
		<description><![CDATA[I wish I would have seen this schedule earlier since the first webcast was today. Nevertheless, I will be trying to catch the others live (or on demand if I miss them). Even as an experienced WSS3/MOSS2007 developer, getting the chance &#8230; <a href="http://alonsorobles.com/2008/05/20/sharepoint-ramp-up-webcasts-for-aspnet-developers/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I wish I would have <a title="ASP.NET Developer Looking for a SharePoint Ramp-Up?" href="http://www.andrewconnell.com/blog/archive/2008/05/13/ASP.NET-Developer-Looking-for-a-SharePoint-RampUp.aspx">seen this schedule</a> earlier since the first webcast was today. Nevertheless, I will be trying to catch the others live (or on demand if I miss them). Even as an experienced WSS3/MOSS2007 developer, getting the chance to see a couple of MVPs (<a href="http://www.andrewconnell.com/blog">Andrew Connell</a> and <a href="http://www.thorprojects.com/">Rob Bogue</a>) introduce the basics is great review and a chance to check your skills.</p>
<table border="1" cellspacing="2" cellpadding="2">
<tbody>
<tr>
<td width="0" valign="top"><strong>Date (all times EDT)</strong></td>
<td width="0" valign="top"><strong>Topic &amp; Registration URL</strong></td>
<td width="0" valign="top"><strong>Presenter</strong></td>
</tr>
<tr>
<td width="0" valign="top">Tues, May 20 : 12-1p</td>
<td width="0" valign="top"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032378826&amp;Culture=en-US">Web Parts</a></td>
<td width="0" valign="top"><a href="http://www.thorprojects.com/">Rob Bogue</a></td>
</tr>
<tr>
<td width="0" valign="top">Wed, May 21 : 12-1p</td>
<td width="0" valign="top"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032378828&amp;Culture=en-US">Data Lists</a></td>
<td width="0" valign="top"><a href="http://www.thorprojects.com/">Rob Bogue</a></td>
</tr>
<tr>
<td width="0" valign="top">Tues, May 27 : 12-1p</td>
<td width="0" valign="top"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032378831&amp;Culture=en-US">Silverlight</a></td>
<td width="0" valign="top"><a href="http://www.andrewconnell.com/blog">Andrew Connell</a></td>
</tr>
<tr>
<td width="0" valign="top">Wed, May 28 : 12-1p</td>
<td width="0" valign="top"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032378833&amp;Culture=en-US">Event Handlers</a></td>
<td width="0" valign="top"><a href="http://www.andrewconnell.com/blog">Andrew Connell</a></td>
</tr>
<tr>
<td width="0" valign="top">Tues, June 3 : 12-1p</td>
<td width="0" valign="top"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032378835&amp;Culture=en-US">Site Branding</a></td>
<td width="0" valign="top"><a href="http://www.andrewconnell.com/blog">Andrew Connell</a></td>
</tr>
<tr>
<td width="0" valign="top">Wed, June 4 : 12-1p</td>
<td width="0" valign="top"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032378839&amp;Culture=en-US">Workflow</a></td>
<td width="0" valign="top"><a href="http://www.thorprojects.com/">Rob Bogue</a></td>
</tr>
<tr>
<td width="0" valign="top">Tues, June 10 : 12-1p</td>
<td width="0" valign="top"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032378841&amp;Culture=en-US">Web Services</a></td>
<td width="0" valign="top"><a href="http://www.andrewconnell.com/blog">Andrew Connell</a></td>
</tr>
<tr>
<td width="0" valign="top">Wed, June 11 : 12-1p</td>
<td width="0" valign="top"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032378843&amp;Culture=en-US">Page Navigation</a></td>
<td width="0" valign="top"><a href="http://www.andrewconnell.com/blog">Andrew Connell</a></td>
</tr>
<tr>
<td width="0" valign="top">Tues, June 17 : 12-1p</td>
<td width="0" valign="top"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032378845&amp;Culture=en-US">User Management</a></td>
<td width="0" valign="top"><a href="http://www.thorprojects.com/">Rob Bogue</a></td>
</tr>
<tr>
<td width="0" valign="top">Wed, June 18 : 12-1p</td>
<td width="0" valign="top"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032378824&amp;Culture=en-US">Content Types</a></td>
<td width="0" valign="top"><a href="http://www.thorprojects.com/">Rob Bogue</a></td>
</tr>
</tbody>
</table>
<p>If you have any interest in SharePoint development, then you don&#8217;t want to miss these webcasts.</p>
]]></content:encoded>
			<wfw:commentRss>http://alonsorobles.com/2008/05/20/sharepoint-ramp-up-webcasts-for-aspnet-developers/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

