<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://weblogs.asp.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Eilon Lipton's Blog</title><link>http://weblogs.asp.net/leftslipper/default.aspx</link><description>Technical blog on Microsoft ASP.NET (and AJAX and MVC).</description><dc:language>en</dc:language><generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator><item><title>Migrating ASP.NET MVC 2 applications to ASP.NET MVC 3 Preview 1</title><link>http://weblogs.asp.net/leftslipper/archive/2010/07/28/migrating-asp-net-mvc-2-applications-to-asp-net-mvc-3-preview-1.aspx</link><pubDate>Wed, 28 Jul 2010 17:34:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7574844</guid><dc:creator>Eilon</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=7574844</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2010/07/28/migrating-asp-net-mvc-2-applications-to-asp-net-mvc-3-preview-1.aspx#comments</comments><description>&lt;p&gt;&lt;strong&gt;&lt;font size="5"&gt;ASP.NET MVC 3 Preview 1 has just been released! More info on &lt;/font&gt;&lt;/strong&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx"&gt;&lt;strong&gt;&lt;font size="5"&gt;ScottGu's blog&lt;/font&gt;&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;&lt;font size="5"&gt;.&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://go.microsoft.com/fwlink/?LinkID=157073"&gt;Download ASP.NET MVC 3 Preview 1!&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;I just finished up a preview of my ASP.NET MVC application conversion tool to support conversions from ASP.NET MVC 2 to ASP.NET MVC 3.&lt;/p&gt;  &lt;p&gt;The previous version of the app that converted from ASP.NET MVC 1.0 to ASP.NET MVC 2 is available &lt;a href="http://weblogs.asp.net/leftslipper/archive/2010/03/10/migrating-asp-net-mvc-1-0-applications-to-asp-net-mvc-2-rtm.aspx"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/image_588A1258.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://weblogs.asp.net/blogs/leftslipper/image_thumb_6FDA382B.png" width="584" height="504" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;h4&gt;&lt;b&gt;Download&lt;/b&gt;&lt;/h4&gt;  &lt;p&gt;The app is a single executable: &lt;a href="http://weblogs.asp.net/blogs/leftslipper/MvcAppConverter-MVC3Preview1.zip"&gt;Download MvcAppConverter-MVC3Preview1.zip (256 KB)&lt;/a&gt;.&lt;/p&gt;  &lt;h4&gt;&lt;b&gt;Usage&lt;/b&gt;&lt;/h4&gt;  &lt;p&gt;The only requirement for this tool is that you have .NET Framework 4 on the machine. You do not need to have Visual Studio or ASP.NET MVC installed (unless you want to open your project!). Even though the tool performs an automatic backup of your solution it is recommended that you perform a manual backup of your solution as well.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;To convert an ASP.NET MVC 2 project built with Visual Studio 2010 to an ASP.NET MVC 3 project in Visual Studio 2010 perform these steps:      &lt;ul&gt;       &lt;li&gt;Launch the converter&lt;/li&gt;        &lt;li&gt;Select the solution&lt;/li&gt;        &lt;li&gt;Click the “Convert” button&lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;To convert an ASP.NET MVC 2 project built with Visual Studio 2008 to an ASP.NET MVC 2 project in Visual Studio 2010:     &lt;ul&gt;       &lt;li&gt;Open the project in Visual Studio 2010 to convert the solution and project file formats from VS2008 to VS2010&lt;/li&gt;        &lt;li&gt;Upgrade the .NET Framework target version of each project to .NET Framework 4 because ASP.NET MVC 3 is compatible with only .NET Framework 4&lt;/li&gt;        &lt;li&gt;Launch the converter &lt;/li&gt;        &lt;li&gt;Select the solution &lt;/li&gt;        &lt;li&gt;Click the “Convert” button&lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;&lt;b&gt;What it can do&lt;/b&gt;&lt;/h4&gt;  &lt;ul&gt;   &lt;li&gt;Open up ASP.NET MVC 2 projects from Visual Studio 2010 (no other versions of ASP.NET MVC or Visual Studio are supported) &lt;/li&gt;    &lt;li&gt;Create a full backup of your solution’s folder &lt;/li&gt;    &lt;li&gt;For every VB or C# project that has a reference to System.Web.Mvc.dll it will (this includes ASP.NET MVC web application projects as well as ASP.NET MVC test projects): &lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;Update references to ASP.NET MVC 2&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;For every VB or C# ASP.NET MVC Web Application it will:&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;Change the project type to an ASP.NET MVC 3 project&lt;/li&gt;      &lt;li&gt;Update the root ~/web.config references to ASP.NET MVC 3&lt;/li&gt;      &lt;li&gt;Update the root ~/web.config to have a binding redirect from ASP.NET MVC 2 to ASP.NET MVC 3&lt;/li&gt;      &lt;li&gt;Update the ~/Views/web.config references to ASP.NET MVC 3&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;Add or update the JavaScript files (add jQuery, add jQuery.Validate, add Microsoft AJAX, add/update Microsoft MVC AJAX, add Microsoft MVC Validation adapter)&lt;/li&gt;    &lt;li&gt;Unknown project types or project types that have nothing to do with ASP.NET MVC will not be updated&lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;&lt;b&gt;What it can’t do&lt;/b&gt;&lt;/h4&gt;  &lt;ul&gt;   &lt;li&gt;It cannot convert projects build with Visual Studio 2008 or with .NET Framework 3.5.&lt;/li&gt;    &lt;li&gt;It can have issues if your solution contains projects that are not located under the solution directory.&lt;/li&gt;    &lt;li&gt;If you are using a source control system it might have problems overwriting files. It is recommended that before converting you check out all files from the source control system.&lt;/li&gt;    &lt;li&gt;It cannot change code in the application that might need to be changed due to breaking changes between ASP.NET MVC 2 and ASP.NET MVC 3.&lt;/li&gt;    &lt;li&gt;The &lt;a href="http://go.microsoft.com/fwlink/?LinkID=191783"&gt;release notes&lt;/a&gt; include manual steps to upgrade your application.&lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;Feedback, Please!&lt;/h4&gt;  &lt;p&gt;If you need to convert a project to ASP.NET MVC 3 please try out this application and hopefully you’re good to go. If you spot any bugs or features that don’t work leave a comment here and I will try to address these issues in an updated release.&lt;/p&gt;  &lt;h4&gt;Other Resources&lt;/h4&gt;  &lt;p&gt;There are already a bunch of blog posts, walkthroughs, and even videos on the new preview, so check them out:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;ScottGu’s introduction blog post: &lt;a href="http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx"&gt;Introducing ASP.NET MVC 3 (Preview 1)&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Phil Haack’s announcement: &lt;a href="http://haacked.com/archive/2010/07/27/aspnetmvc3-preview1-released.aspx"&gt;ASP.NET MVC 3 Preview 1 Released&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Scott Hanselman’s Hanselminutes with Phil: &lt;a href="http://www.hanselminutes.com/default.aspx?showID=242"&gt;&amp;lt;ASP.NET MVC 3 Preview 1 with Phil Haack/&amp;gt;&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;More Hanselminutes: &lt;a href="http://channel9.msdn.com/posts/Glucose/Hanselminutes-on-9-ASPNET-MVC-3-and-NEW-ASPNET-Futures-with-Phil-Haack-and-Morgan-the-Intern/"&gt;Hanselminutes on 9 - ASP.NET MVC 3 and NEW ASP.NET Futures with Phil Haack and Morgan the Intern&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://go.microsoft.com/fwlink/?LinkID=157073"&gt;Download ASP.NET MVC 3 Preview 1&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://go.microsoft.com/fwlink/?LinkID=191783"&gt;Release notes&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Brad Wilson has a four-part post on ASP.NET MVC 3’s new dependency injection support:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://bradwilson.typepad.com/blog/2010/07/service-location-pt1-introduction.html"&gt;ASP.NET MVC 3 Service Location: Introduction (Part 1)&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://bradwilson.typepad.com/blog/2010/07/service-location-pt2-controllers.html"&gt;ASP.NET MVC 3 Service Location: Controllers (Part 2)&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://bradwilson.typepad.com/blog/2010/07/service-location-pt3-views.html"&gt;ASP.NET MVC 3 Service Location: Views (Part 3)&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://bradwilson.typepad.com/blog/2010/07/service-location-pt4-filters.html"&gt;ASP.NET MVC 3 Service Location: Filters (Part 4)&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7574844" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/aspnetmvc/default.aspx">aspnetmvc</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/visualstudio/default.aspx">visualstudio</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/Visual+Studio/default.aspx">Visual Studio</category></item><item><title>Creating Visual Studio projects that only contain static files</title><link>http://weblogs.asp.net/leftslipper/archive/2010/05/27/creating-visual-studio-projects-that-only-contain-static-files.aspx</link><pubDate>Thu, 27 May 2010 20:00:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7508321</guid><dc:creator>Eilon</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=7508321</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2010/05/27/creating-visual-studio-projects-that-only-contain-static-files.aspx#comments</comments><description>&lt;p&gt;Have you ever wanted to create a Visual Studio project that only contained static files and didn’t contain any code?&lt;/p&gt;  &lt;p&gt;While working on &lt;a href="http://www.asp.net/mvc"&gt;ASP.NET MVC&lt;/a&gt; we had a need for exactly this type of project. Most of the projects in the ASP.NET MVC solution contain code, such as managed code (C#), unit test libraries (C#), and &lt;a href="http://projects.nikhilk.net/ScriptSharp"&gt;Script#&lt;/a&gt; code for generating our JavaScript code.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/image_41F59B27.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; margin-left: 0px; border-top: 0px; margin-right: 0px; border-right: 0px" title="MVC 2 Solution" border="0" alt="MVC 2 Solution" src="http://weblogs.asp.net/blogs/leftslipper/image_thumb_5CC1C133.png" width="269" height="293" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;However, one of the projects, &lt;strong&gt;MvcFuturesFiles&lt;/strong&gt;, contains no code at all. It only contains static files that get copied to the build output folder:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/image_5A87C928.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="MVC Futures Files project contents" border="0" alt="MVC Futures Files project contents" src="http://weblogs.asp.net/blogs/leftslipper/image_thumb_5C581EEF.png" width="269" height="403" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;As you may well know, adding static files to an existing Visual Studio project is easy. Just add the file to the project and in the property grid set its Build Action to “Content” and the Copy to Output Directory to “Copy if newer.” This works great if you have just a few static files that go along with other code that gets compiled into an executable (EXE, DLL, etc.).&lt;/p&gt;  &lt;p&gt;But this solution does not work well if the projects only contains static files and has no compiled code. If you create a new project in Visual Studio and add static files to it you’ll still get an EXE or DLL copied to the output folder, despite not having any actual code. We wanted to avoid having a teeny little DLL generated in the output folder.&lt;/p&gt;  &lt;p&gt;In ASP.NET MVC 2 we came up with a simple solution to this problem. We started out with a regular C# Class Library project but then edited the project file to alter how it gets built. The critical part to get this to work is to define the MSBuild targets for &lt;strong&gt;Build&lt;/strong&gt;, &lt;strong&gt;Clean&lt;/strong&gt;, and &lt;strong&gt;Rebuild&lt;/strong&gt; to perform custom tasks instead of running the compiler. The Build, Clean, and Rebuild targets are the three main targets that Visual Studio requires in every project so that the normal UI functions properly. If they are not defined then running certain commands in Visual Studio’s Build menu will cause errors.&lt;/p&gt;  &lt;p&gt;Once you create the class library projects there are a few easy steps to change it into a static file project:&lt;/p&gt;  &lt;p&gt;The first step in editing the csproj file is to remove the reference to the &lt;strong&gt;Microsoft.CSharp.targets&lt;/strong&gt; file because the project doesn’t contain any C# code:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(MSBuildToolsPath)\Microsoft.CSharp.targets&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;
.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; }&lt;/style&gt;

&lt;p&gt;The second step is to define the new Build, Clean, and Rebuild targets to delete and then copy the content files:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Build&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Copy&lt;/span&gt;
            &lt;span class="attr"&gt;SourceFiles&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;@(Content)&amp;quot;&lt;/span&gt;
            &lt;span class="attr"&gt;DestinationFiles&lt;/span&gt;=&amp;quot;@(&lt;span class="attr"&gt;Content-&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;'$(OutputPath)%(RelativeDir)%(Filename)%(Extension)')&amp;quot; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Clean&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Exec&lt;/span&gt; &lt;span class="attr"&gt;Command&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;rd /s /q $(OutputPath)&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Exists($(OutputPath))&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Rebuild&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Clean;Build&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;
.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; }&lt;/style&gt;

&lt;p&gt;The third and last step is to add all the files to the project as normal Content files (as you would do in any project type).&lt;/p&gt;

&lt;p&gt;To see how we did this in the ASP.NET MVC 2 project you can &lt;a href="http://aspnet.codeplex.com/releases/view/41742"&gt;download the source code&lt;/a&gt; and inspect the MvcFutureFules.csproj project file.&lt;/p&gt;

&lt;p&gt;If you’re working on a project that contains many static files I hope this solution helps you out!&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7508321" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/aspnetmvc/default.aspx">aspnetmvc</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/visualstudio/default.aspx">visualstudio</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/Visual+Studio/default.aspx">Visual Studio</category></item><item><title>Last GUID used up - new ScottGuID unique ID to replace it</title><link>http://weblogs.asp.net/leftslipper/archive/2010/04/01/last-guid-used-up-new-scottguid-unique-id-to-replace-it.aspx</link><pubDate>Thu, 01 Apr 2010 12:00:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7424363</guid><dc:creator>Eilon</dc:creator><slash:comments>38</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=7424363</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2010/04/01/last-guid-used-up-new-scottguid-unique-id-to-replace-it.aspx#comments</comments><description>&lt;p&gt;You might have heard in recent news that the last ever &lt;a href="http://en.wikipedia.org/wiki/Globally_Unique_Identifier"&gt;GUID&lt;/a&gt; was used up. The GUID {FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF} was just consumed by a soon to be released project at Microsoft. Immediately after the GUID's creation the word spread around the Microsoft campuses around the globe. Microsoft's approximately 100,000 worldwide employees then started blogging, tweeting, and facebooking about the dubious &amp;quot;achievement.&amp;quot; The following screenshot shows &lt;a href="http://msdn.microsoft.com/en-us/library/ms241442(VS.80).aspx"&gt;GUIDGEN&lt;/a&gt; (the Windows tool for creating GUIDs) with the last ever GUID.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/clip_image002_745C1309.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image002" border="0" alt="clip_image002" src="http://weblogs.asp.net/blogs/leftslipper/clip_image002_thumb_41FAD03B.jpg" width="389" height="401" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;All GUIDs created by projects at Microsoft must be registered in a central repository for record keeping. This allows quick-fix engineers, security engineers, anti-malware developers, and testers to do a quick look up of an unknown GUID and find out if it belongs to Microsoft. The following screenshot shows the Microsoft GUID Tracker internal application and the last few GUIDs being used up by various Microsoft projects.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/clip_image004_25ECA201.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="clip_image004" border="0" alt="clip_image004" src="http://weblogs.asp.net/blogs/leftslipper/clip_image004_thumb_1507FE11.jpg" width="627" height="356" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;What is perhaps more interesting than the news about the GUID is the project that used that last GUID. The recent announcements regarding the development experience for the &lt;a href="http://www.windowsphone7series.com/"&gt;Windows Phone 7 Series&lt;/a&gt; (WP7S) all involve &lt;a href="http://weblogs.asp.net/scottgu/archive/2010/03/18/building-a-windows-phone-7-twitter-application-using-silverlight.aspx"&gt;free editions of Visual Studio 2010&lt;/a&gt;. One of the lesser known developer tools is based on a resurrected project that many of you are probably familiar with, but have never used. The tool is in fact Microsoft Bob 7 Series (MB7S). MB7S is an agent-based approach for mobile phone app development. The UI incorporates both natural language interfaces and motion gesture behaviors, similar to the Windows Phone 7 Series “Metro” interface. If it works, it will help to expand the breadth of mobile app developers.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/msbob_2D9A2C12.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="msbob" border="0" alt="msbob" src="http://weblogs.asp.net/blogs/leftslipper/msbob_thumb_2BEE81A0.png" width="644" height="484" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;h3&gt;After the GUID: The ScottGuID&lt;/h3&gt;  &lt;p&gt;It came as no big surprise that eventually the last GUID would be used up. Knowing this, a group of engineers at Microsoft has designed, implemented, and tested a replacement to the GUID: The &lt;i&gt;ScottGuID&lt;/i&gt;. There are several core principles of the ScottGuID:&lt;/p&gt;  &lt;p&gt;1. The concepts used in ScottGuIDs must be easily understood by a developer who is already familiar with GUIDs&lt;/p&gt;  &lt;p&gt;2. There must exist a compatibility layer between ScottGuIDs and GUIDs&lt;/p&gt;  &lt;p&gt;3. A ScottGuID must be usable in a practical manner in non-computing environments&lt;/p&gt;  &lt;p&gt;4. There must exist ScottGuID APIs for all common platforms: Win32/Win64/WinCE, .NET (incl. Silverlight), Linux, FreeBSD, MacOS (incl. iPhone OS), Symbian, RIM BlackBerry, Google Android, etc.&lt;/p&gt;  &lt;p&gt;5. ScottGuIDs must never run out&lt;/p&gt;  &lt;h3&gt;ScottGuID use cases&lt;/h3&gt;  &lt;p&gt;One of the more subtle principles of the ScottGuID is principle #3. While technically a GUID could be used in any environment, it was not practical to do so in terms of data entry and error detection. In order to have the ScottGuID be a true universal ID it must be usable in &lt;i&gt;non-computing environments&lt;/i&gt;.&lt;/p&gt;  &lt;p&gt;Prior to the announcement of the ScottGuID there have been a number of until-now confidential projects. One of the tools that will soon become public is ScottGuIDGen, which is in essence an updated version of GUIDGEN that can create ScottGuIDs. The following screenshot shows a sample ScottGuID.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/clip_image007_114706E9.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image007" border="0" alt="clip_image007" src="http://weblogs.asp.net/blogs/leftslipper/clip_image007_thumb_23925E5C.jpg" width="444" height="300" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;To demonstrate the various applications of the ScottGuID there were test deployments around the globe. The following examples are a small showcase of the applications that have already been prototyped.&lt;/p&gt;  &lt;h4&gt;Log in to Hotmail:&lt;/h4&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/hotmail_00D1269F.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="hotmail" border="0" alt="hotmail" src="http://weblogs.asp.net/blogs/leftslipper/hotmail_thumb_443BB8B2.png" width="644" height="441" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;Pay for gas:&lt;/h4&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/gasstation_17B7AA2E.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="gas-station" border="0" alt="gas-station" src="http://weblogs.asp.net/blogs/leftslipper/gasstation_thumb_539BEE36.png" width="644" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;Sign in to Twitter:&lt;/h4&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/twitter_419F0ECF.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="twitter" border="0" alt="twitter" src="http://weblogs.asp.net/blogs/leftslipper/twitter_thumb_72C0DA20.png" width="644" height="463" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;Dispense cat food:&lt;/h4&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/icanhaz_14429A61.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="icanhaz" border="0" alt="icanhaz" src="http://weblogs.asp.net/blogs/leftslipper/icanhaz_thumb_7A07529E.png" width="642" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h3&gt;Conclusion&lt;/h3&gt;  &lt;p&gt;I hope that this brief introduction to the ScottGuID shows how technology can continue to move forward, even when it appears there is a point that cannot be passed. With a small number of principles, a team of smart engineers, and a passion for &amp;quot;getting it right&amp;quot; the ScottGuID should last well past our lifetimes. In the coming months expect further announcements regarding additional developer tools, samples, whitepapers, podcasts, and videos.&lt;/p&gt;  &lt;p&gt;Please leave a comment on this post if you have any questions about the ScottGuID or what you would like to see us do with it. With ScottGuID, the possibilities are nearly endless and we want to stretch their reach as far as possible.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7424363" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/c_2300_/default.aspx">c#</category></item><item><title>Migrating ASP.NET MVC 1.0 applications to ASP.NET MVC 2 RTM</title><link>http://weblogs.asp.net/leftslipper/archive/2010/03/10/migrating-asp-net-mvc-1-0-applications-to-asp-net-mvc-2-rtm.aspx</link><pubDate>Thu, 11 Mar 2010 06:00:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7378074</guid><dc:creator>Eilon</dc:creator><slash:comments>32</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=7378074</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2010/03/10/migrating-asp-net-mvc-1-0-applications-to-asp-net-mvc-2-rtm.aspx#comments</comments><description>&lt;P&gt;&lt;STRONG&gt;&lt;EM&gt;&lt;FONT size=4&gt;ASP.NET MVC 2 RTM has just been released! More info on &lt;A href="http://weblogs.asp.net/scottgu/archive/2010/03/11/asp-net-mvc-2-released.aspx" mce_href="http://weblogs.asp.net/scottgu/archive/2010/03/11/asp-net-mvc-2-released.aspx"&gt;ScottGu's blog&lt;/A&gt;.&lt;/FONT&gt;&lt;/EM&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;I have updated the MVC App Converter to convert projects from ASP.NET MVC 1.0 to ASP.NET MVC 2 RTM.&lt;/P&gt;
&lt;P&gt;This should be last the last major change to the MVC App Converter that I released previews of in the past several months.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/image_214BB2B3.png" mce_href="http://weblogs.asp.net/blogs/leftslipper/image_214BB2B3.png"&gt;&lt;IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: inline; BORDER-TOP: 0px; BORDER-RIGHT: 0px" title="MVC App Converter screen shot" border=0 alt="MVC App Converter screen shot" src="http://weblogs.asp.net/blogs/leftslipper/image_thumb_00C703B2.png" width=694 height=544 mce_src="http://weblogs.asp.net/blogs/leftslipper/image_thumb_00C703B2.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;H2&gt;&lt;B&gt;Download&lt;/B&gt;&lt;/H2&gt;
&lt;P&gt;The app is a single executable: &lt;A href="http://weblogs.asp.net/blogs/leftslipper/MvcAppConverter-MVC2RTM.zip" mce_href="http://weblogs.asp.net/blogs/leftslipper/MvcAppConverter-MVC2RTM.zip"&gt;Download MvcAppConverter-MVC2RTM.zip (255 KB)&lt;/A&gt;.&lt;/P&gt;
&lt;H2&gt;&lt;B&gt;Usage&lt;/B&gt;&lt;/H2&gt;
&lt;P&gt;The only requirement for this tool is that you have .NET Framework 3.5 SP1 on the machine. You do not need to have Visual Studio or ASP.NET MVC installed (unless you want to open your project!). Even though the tool performs an automatic backup of your solution it is recommended that you perform a manual backup of your solution as well.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;To convert an ASP.NET MVC 1.0 project built with Visual Studio 2008 to an ASP.NET MVC 2 project in Visual Studio 2008 perform these steps: 
&lt;UL&gt;
&lt;LI&gt;Launch the converter &lt;/LI&gt;
&lt;LI&gt;Select the solution &lt;/LI&gt;
&lt;LI&gt;Click the “Convert” button &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;To convert an ASP.NET MVC 1.0 project built with Visual Studio 2008 to an ASP.NET MVC 2 project in Visual Studio 2010: 
&lt;UL&gt;
&lt;LI&gt;Wait until Visual Studio 2010 is released (next month!) and it will have a built-in version of this tool that will run automatically when you open an ASP.NET MVC 1.0 project&lt;/LI&gt;
&lt;LI&gt;Perform the above steps, then open the project in Visual Studio 2010 and it will perform the remaining conversion steps &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;H2&gt;&lt;B&gt;What it can do&lt;/B&gt;&lt;/H2&gt;
&lt;UL&gt;
&lt;LI&gt;Open up ASP.NET MVC 1.0 projects from Visual Studio 2008 (no other versions of ASP.NET MVC or Visual Studio are supported) &lt;/LI&gt;
&lt;LI&gt;Create a full backup of your solution’s folder &lt;/LI&gt;
&lt;LI&gt;For every VB or C# project that has a reference to System.Web.Mvc.dll it will (this includes ASP.NET MVC web application projects as well as ASP.NET MVC test projects): 
&lt;UL&gt;
&lt;LI&gt;Update references to ASP.NET MVC 2 &lt;/LI&gt;
&lt;LI&gt;Add a reference to System.ComponentModel.DataAnnotations 3.5 (if not already present) &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;For every VB or C# ASP.NET MVC Web Application it will: 
&lt;UL&gt;
&lt;LI&gt;Change the project type to an ASP.NET MVC 2 project &lt;/LI&gt;
&lt;LI&gt;Update the root ~/web.config references to ASP.NET MVC 2 &lt;/LI&gt;
&lt;LI&gt;Update the root ~/web.config to have a binding redirect from ASP.NET MVC 1.0 to ASP.NET MVC 2 &lt;/LI&gt;
&lt;LI&gt;Update the ~/Views/web.config references to ASP.NET MVC 2 &lt;/LI&gt;
&lt;LI&gt;Add or update the JavaScript files (add jQuery, add jQuery.Validate, add Microsoft AJAX, add/update Microsoft MVC AJAX, add Microsoft MVC Validation adapter) &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;Unknown project types or project types that have nothing to do with ASP.NET MVC will not be updated &lt;/LI&gt;&lt;/UL&gt;
&lt;H2&gt;&lt;B&gt;What it can’t do&lt;/B&gt;&lt;/H2&gt;
&lt;UL&gt;
&lt;LI&gt;It cannot convert projects directly to Visual Studio 2010 or to .NET Framework 4. &lt;/LI&gt;
&lt;LI&gt;It can have issues if your solution contains projects that are not located under the solution directory. &lt;/LI&gt;
&lt;LI&gt;If you are using a source control system it might have problems overwriting files. It is recommended that before converting you check out all files from the source control system. &lt;/LI&gt;
&lt;LI&gt;It cannot change code in the application that might need to be changed due to breaking changes between ASP.NET MVC 1.0 and ASP.NET MVC 2.&lt;/LI&gt;&lt;/UL&gt;
&lt;H2&gt;Feedback, Please!&lt;/H2&gt;
&lt;P&gt;If you need to convert a project to ASP.NET MVC 2 please try out this application and hopefully you’re good to go. If you spot any bugs or features that don’t work leave a comment here and I will try to address these issues in an updated release.&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7378074" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/aspnetmvc/default.aspx">aspnetmvc</category></item><item><title>Migrating ASP.NET MVC 1.0 applications to ASP.NET MVC 2 Beta (updated!)</title><link>http://weblogs.asp.net/leftslipper/archive/2009/11/23/migrating-asp-net-mvc-1-0-applications-to-asp-net-mvc-2-beta-updated.aspx</link><pubDate>Mon, 23 Nov 2009 19:55:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7263695</guid><dc:creator>Eilon</dc:creator><slash:comments>13</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=7263695</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2009/11/23/migrating-asp-net-mvc-1-0-applications-to-asp-net-mvc-2-beta-updated.aspx#comments</comments><description>&lt;P&gt;&lt;STRONG&gt;NOTE: There is an &lt;/STRONG&gt;&lt;A href="about:/leftslipper/archive/2010/03/10/migrating-asp-net-mvc-1-0-applications-to-asp-net-mvc-2-rtm.aspx" mce_href="http://weblogs.asp.net/leftslipper/archive/2010/03/10/migrating-asp-net-mvc-1-0-applications-to-asp-net-mvc-2-rtm.aspx"&gt;&lt;STRONG&gt;updated version of this tool&lt;/STRONG&gt;&lt;/A&gt;&lt;STRONG&gt; that is compatible with ASP.NET MVC 2 RTM.&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Thanks to the great feedback I’ve received on my &lt;A href="http://weblogs.asp.net/leftslipper/archive/2009/10/19/migrating-asp-net-mvc-1-0-applications-to-asp-net-mvc-2.aspx" mce_href="http://weblogs.asp.net/leftslipper/archive/2009/10/19/migrating-asp-net-mvc-1-0-applications-to-asp-net-mvc-2.aspx"&gt;ASP.NET MVC conversion tool for ASP.NET MVC 2 Preview 2&lt;/A&gt; I’ve updated it to support conversions to &lt;A href="http://go.microsoft.com/fwlink/?LinkID=157068" mce_href="http://go.microsoft.com/fwlink/?LinkID=157068"&gt;ASP.NET MVC 2 Beta&lt;/A&gt;. I’ve included a number of bugs fixes and improvements based on the feedback:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;The JavaScript files have been updated to be compatible with ASP.NET MVC 2 Beta&lt;/LI&gt;
&lt;LI&gt;A “Scripts” folder will be automatically created if one does not already exist&lt;/LI&gt;
&lt;LI&gt;References to the System.Web.Mvc.dll assembly will be updated to use the fully-qualified name (public key token, etc.)&lt;/LI&gt;
&lt;LI&gt;UI improvements&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/image_4B614125.png" mce_href="http://weblogs.asp.net/blogs/leftslipper/image_4B614125.png"&gt;&lt;IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: inline; BORDER-TOP: 0px; BORDER-RIGHT: 0px" title="ASP.NET MVC Solution Converter" border=0 alt="ASP.NET MVC Solution Converter" src="http://weblogs.asp.net/blogs/leftslipper/image_thumb_37032DAD.png" width=584 height=538 mce_src="http://weblogs.asp.net/blogs/leftslipper/image_thumb_37032DAD.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;H2&gt;Download&lt;/H2&gt;
&lt;P&gt;The app is a single executable: &lt;A href="http://weblogs.asp.net/blogs/leftslipper/MvcAppConverter-MVC2Beta.zip" mce_href="http://weblogs.asp.net/blogs/leftslipper/MvcAppConverter-MVC2Beta.zip"&gt;Download MvcAppConverter.zip (226 KB)&lt;/A&gt;.&lt;/P&gt;
&lt;H2&gt;Usage&lt;/H2&gt;
&lt;P&gt;The only requirement for this tool is that you have .NET Framework 3.5 SP1 on the machine. You do not need to have Visual Studio or ASP.NET MVC installed (unless you want to open your project!). Even though the tool performs an automatic backup of your solution it is recommended that you perform a manual backup of the solution as well.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;To convert an ASP.NET MVC 1.0 project built with Visual Studio 2008 to an ASP.NET MVC 2 project in Visual Studio 2008 perform these steps: 
&lt;UL&gt;
&lt;LI&gt;Launch the converter &lt;/LI&gt;
&lt;LI&gt;Select the solution &lt;/LI&gt;
&lt;LI&gt;Click the “Convert” button &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;To convert an ASP.NET MVC 1.0 project built with Visual Studio 2008 to an ASP.NET MVC 2 project in Visual Studio 2010: 
&lt;UL&gt;
&lt;LI&gt;Perform the above steps, then open the project in Visual Studio 2010 and it will perform the remaining conversion steps &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;H2&gt;What it can do&lt;/H2&gt;
&lt;UL&gt;
&lt;LI&gt;Open up ASP.NET MVC 1.0 projects from Visual Studio 2008 (no other versions of ASP.NET MVC or Visual Studio are supported) &lt;/LI&gt;
&lt;LI&gt;Create a full backup of your solution’s folder &lt;/LI&gt;
&lt;LI&gt;For every VB or C# project that has a reference to System.Web.Mvc.dll it will (this includes ASP.NET MVC web application projects as well as ASP.NET MVC test projects): 
&lt;UL&gt;
&lt;LI&gt;Update references to ASP.NET MVC 2 &lt;/LI&gt;
&lt;LI&gt;Add a reference to System.ComponentModel.DataAnnotations 3.5 (if not already present) &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;For every VB or C# ASP.NET MVC Web Application it will: 
&lt;UL&gt;
&lt;LI&gt;Change the project type to an ASP.NET MVC 2 project &lt;/LI&gt;
&lt;LI&gt;Update the root ~/web.config references to ASP.NET MVC 2 &lt;/LI&gt;
&lt;LI&gt;Update the root ~/web.config to have a binding redirect from ASP.NET MVC 1.0 to ASP.NET MVC 2 &lt;/LI&gt;
&lt;LI&gt;Update the ~/Views/web.config references to ASP.NET MVC 2 &lt;/LI&gt;
&lt;LI&gt;Add or update the JavaScript files (add jQuery, add jQuery.Validate, add Microsoft AJAX, add/update Microsoft MVC AJAX, add Microsoft MVC Validation adapter) &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;Unknown project types or project types that have nothing to do with ASP.NET MVC will not be updated &lt;/LI&gt;&lt;/UL&gt;
&lt;H2&gt;What it can’t do&lt;/H2&gt;
&lt;UL&gt;
&lt;LI&gt;It cannot convert projects directly to Visual Studio 2010 or to .NET Framework 4. &lt;/LI&gt;
&lt;LI&gt;It can have issues if your solution contains projects that are not located under the solution directory. &lt;/LI&gt;
&lt;LI&gt;If you are using a source control system it might have problems overwriting files. It is recommended that before converting you check out all files from the source control system. &lt;/LI&gt;
&lt;LI&gt;It cannot change code in the application that might need to be changed due to breaking changes between ASP.NET MVC 1.0 and ASP.NET MVC 2. Consult the &lt;A href="http://go.microsoft.com/fwlink/?LinkID=157066" mce_href="http://go.microsoft.com/fwlink/?LinkID=157066"&gt;readme&lt;/A&gt; for information on breaking changes. &lt;/LI&gt;&lt;/UL&gt;
&lt;H2&gt;Feedback, Please!&lt;/H2&gt;
&lt;P&gt;If you need to convert a project to ASP.NET MVC 2 please try out this application and hopefully you’re good to go. If you spot any bugs or features that don’t work leave a comment here and I will try to address these issues in an updated release.&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7263695" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/aspnetmvc/default.aspx">aspnetmvc</category></item><item><title>Migrating ASP.NET MVC 1.0 applications to ASP.NET MVC 2</title><link>http://weblogs.asp.net/leftslipper/archive/2009/10/19/migrating-asp-net-mvc-1-0-applications-to-asp-net-mvc-2.aspx</link><pubDate>Mon, 19 Oct 2009 19:38:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7233210</guid><dc:creator>Eilon</dc:creator><slash:comments>37</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=7233210</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2009/10/19/migrating-asp-net-mvc-1-0-applications-to-asp-net-mvc-2.aspx#comments</comments><description>&lt;P&gt;&lt;STRONG&gt;NOTE: There is an &lt;/STRONG&gt;&lt;A href="http://weblogs.asp.net/leftslipper/archive/2010/03/10/migrating-asp-net-mvc-1-0-applications-to-asp-net-mvc-2-rtm.aspx" mce_href="http://weblogs.asp.net/leftslipper/archive/2010/03/10/migrating-asp-net-mvc-1-0-applications-to-asp-net-mvc-2-rtm.aspx"&gt;&lt;STRONG&gt;updated version of this tool&lt;/STRONG&gt;&lt;/A&gt;&lt;STRONG&gt; that is compatible with ASP.NET MVC 2 RTM.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;To help our customers adopt ASP.NET MVC 2 I built an application that helps upgrade Visual Studio 2008 solutions that use &lt;A href="http://www.asp.net/mvc/download/" mce_href="http://www.asp.net/mvc/download/"&gt;ASP.NET MVC 1.0&lt;/A&gt; to use &lt;A href="http://www.microsoft.com/downloads/details.aspx?familyid=D3F06BB9-5F5F-4F46-91E9-813B3FCE2DB1&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?familyid=D3F06BB9-5F5F-4F46-91E9-813B3FCE2DB1&amp;amp;displaylang=en"&gt;ASP.NET MVC 2 Preview 2&lt;/A&gt;. This application is inspired by &lt;A href="http://www.hanselman.com/blog/CheesyASPNETMVCProjectUpgraderForVisualStudio2010Beta1.aspx" mce_href="http://www.hanselman.com/blog/CheesyASPNETMVCProjectUpgraderForVisualStudio2010Beta1.aspx"&gt;Scott Hanselman’s blog post&lt;/A&gt; on updating ASP.NET MVC projects to work in Visual Studio 2010 Beta 1.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/image_620D4FA7.png" mce_href="http://weblogs.asp.net/blogs/leftslipper/image_620D4FA7.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=image border=0 alt=image src="http://weblogs.asp.net/blogs/leftslipper/image_thumb_139B4DEE.png" width=584 height=504 mce_src="http://weblogs.asp.net/blogs/leftslipper/image_thumb_139B4DEE.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;H1&gt;&lt;B&gt;Download&lt;/B&gt;&lt;/H1&gt;
&lt;P&gt;The app is a single executable: &lt;A href="http://weblogs.asp.net/blogs/leftslipper/MvcAppConverter.zip" mce_href="http://weblogs.asp.net/blogs/leftslipper/MvcAppConverter.zip"&gt;Download MvcAppConverter.zip (220 KB)&lt;/A&gt;.&lt;/P&gt;
&lt;H1&gt;&lt;B&gt;Usage&lt;/B&gt;&lt;/H1&gt;
&lt;P&gt;The only requirement for this tool is that you have .NET Framework 3.5 SP1 on the machine. You do not need to have Visual Studio or ASP.NET MVC installed (unless you want to open your project!). Even though the tool performs an automatic backup of your solution it is recommended that you perform a manual backup of the solution as well.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;To convert an ASP.NET MVC 1.0 project built with Visual Studio 2008 to an ASP.NET MVC 2 project in Visual Studio 2008 perform these steps: 
&lt;UL&gt;
&lt;LI&gt;Launch the converter &lt;/LI&gt;
&lt;LI&gt;Select the solution &lt;/LI&gt;
&lt;LI&gt;Click the “Convert” button &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;To convert an ASP.NET MVC 1.0 project built with Visual Studio 2008 to an ASP.NET MVC 2 project in Visual Studio 2010: 
&lt;UL&gt;
&lt;LI&gt;Perform the above steps, then open the project in Visual Studio 2010 and it will perform the remaining conversion steps &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;H1&gt;&lt;B&gt;What it can do&lt;/B&gt;&lt;/H1&gt;
&lt;UL&gt;
&lt;LI&gt;Open up ASP.NET MVC 1.0 projects from Visual Studio 2008 (no other versions of ASP.NET MVC or Visual Studio are supported) &lt;/LI&gt;
&lt;LI&gt;Create a full backup of your solution’s folder &lt;/LI&gt;
&lt;LI&gt;For every VB or C# project that has a reference to System.Web.Mvc.dll it will (this includes ASP.NET MVC web application projects as well as ASP.NET MVC test projects): 
&lt;UL&gt;
&lt;LI&gt;Update references to ASP.NET MVC 2 &lt;/LI&gt;
&lt;LI&gt;Add a reference to System.ComponentModel.DataAnnotations 3.5 (if not already present) &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;For every VB or C# ASP.NET MVC Web Application it will: 
&lt;UL&gt;
&lt;LI&gt;Change the project type to an ASP.NET MVC 2 project &lt;/LI&gt;
&lt;LI&gt;Update the root ~/web.config references to ASP.NET MVC 2 &lt;/LI&gt;
&lt;LI&gt;Update the root ~/web.config to have a binding redirect from ASP.NET MVC 1.0 to ASP.NET MVC 2 &lt;/LI&gt;
&lt;LI&gt;Update the ~/Views/web.config references to ASP.NET MVC 2 &lt;/LI&gt;
&lt;LI&gt;Add or update the JavaScript files (add jQuery, add jQuery.Validate, add Microsoft AJAX, add/update Microsoft MVC AJAX, add Microsoft MVC Validation adapter) &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;Unknown project types or project types that have nothing to do with ASP.NET MVC will not be updated &lt;/LI&gt;&lt;/UL&gt;
&lt;H1&gt;&lt;B&gt;What it can’t do&lt;/B&gt;&lt;/H1&gt;
&lt;UL&gt;
&lt;LI&gt;It cannot convert projects directly to Visual Studio 2010 or to .NET Framework 4. &lt;/LI&gt;
&lt;LI&gt;It can have issues if your solution contains projects that are not located under the solution directory. &lt;/LI&gt;
&lt;LI&gt;If you are using a source control system it might have problems overwriting files. It is recommended that before converting you check out all files from the source control system. &lt;/LI&gt;
&lt;LI&gt;It cannot change code in the application that might need to be changed due to breaking changes between ASP.NET MVC 1.0 and ASP.NET MVC 2. Consult the &lt;A href="http://go.microsoft.com/fwlink/?LinkID=157066" mce_href="http://go.microsoft.com/fwlink/?LinkID=157066"&gt;readme&lt;/A&gt; for information on breaking changes. &lt;/LI&gt;&lt;/UL&gt;
&lt;H1&gt;Feedback, Please!&lt;/H1&gt;
&lt;P&gt;If you need to convert a project to ASP.NET MVC 2 please try out this application and hopefully you’re good to go. If you spot any bugs or features that don’t work leave a comment here and I will try to address these issues in an updated release.&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7233210" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/aspnetmvc/default.aspx">aspnetmvc</category></item><item><title>Introducing SmartyRoute: A smarty-ier way to do routing in ASP.NET applications</title><link>http://weblogs.asp.net/leftslipper/archive/2009/10/07/introducing-smartyroute-a-smarty-ier-way-to-do-routing-in-asp-net-applications.aspx</link><pubDate>Wed, 07 Oct 2009 17:38:19 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7224924</guid><dc:creator>Eilon</dc:creator><slash:comments>8</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=7224924</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2009/10/07/introducing-smartyroute-a-smarty-ier-way-to-do-routing-in-asp-net-applications.aspx#comments</comments><description>&lt;p&gt;Inspired by ideas I have heard from people on my team (ideas that apparently I misunderstood!), I am introducing the new SmartyRoute, which provides a smarty-ier way to do routing in ASP.NET applications.&lt;/p&gt;  &lt;p&gt;The basic idea is that you can make a request to a resource in an ASP.NET application without specifying a file extension in the URL. SmartyRoute will try to append a set of supported file extensions to find a handler to serve the request.&lt;/p&gt;  &lt;h1&gt;Basic Routing&lt;/h1&gt;  &lt;p&gt;In the simplest usage a user can make a request to &lt;strong&gt;~/helloworld&lt;/strong&gt; and SmartyRoute will find &lt;strong&gt;~/helloworld.aspx&lt;/strong&gt; on disk and use that as the handler. This is a very common scenario: Many developers don’t want to have file extensions in the URLs of their web sites. SmartyRoute enables developers to do that without making other changes to the application.&lt;/p&gt;  &lt;h1&gt;Slightly More Advanced Routing&lt;/h1&gt;  &lt;p&gt;A more advanced scenario is where a developer wants to have a URL such as ~/category/beverages. With the feature shown so far the developer has to have a &lt;strong&gt;~/category/beverages.aspx&lt;/strong&gt; on disk. There would also need to be another ASPX for every category in the application. However, SmartyRoute can walk up the path segments of the URL to locate a parent ASPX file. In this case SmartyRoute will detect that there is a file &lt;strong&gt;~/category.aspx&lt;/strong&gt; and load that instead. The rest of the data on the URL (in this case &amp;quot;beverages&amp;quot;) can get passed in as parameters to the ASPX page.&lt;/p&gt;  &lt;h1&gt;Even More Advanced Routing&lt;/h1&gt;  &lt;p&gt;To get parameter values there are a number of helper APIs that SmartyRoute offers. The simplest way is to call SmartyRoute.GetRouteMatch().PathInfo, which will return everything after the last &amp;quot;/&amp;quot; of what was handled in the request. For example, if the user requests &lt;strong&gt;~/category/beverages&lt;/strong&gt; and it gets handled by &lt;strong&gt;~/category.aspx&lt;/strong&gt; then the remaining &amp;quot;beverages&amp;quot; value in the URL will be the path info:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; category = SmartyRoute.GetRouteMatch().PathInfo; // &lt;span class="rem"&gt;category == &amp;quot;beverages&amp;quot;&lt;/span&gt; &lt;/pre&gt;
&lt;style type="text/css"&gt;

.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; }&lt;/style&gt;

&lt;p&gt;If the path info contains multiple segments there is an alternative API that will do some of the heavier lifting for the developer. For example, if the URL is ~/category/beverages/5 (where &amp;quot;5&amp;quot; is the page number) there are these helpers:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; category = SmartyRoute.GetNextRouteValue(); &lt;span class="rem"&gt;// category == &amp;quot;beverages&amp;quot;&lt;/span&gt;
    &lt;span class="kwrd"&gt;int&lt;/span&gt; page = SmartyRoute.GetNextRouteValue&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt;(); // &lt;span class="rem"&gt;page == 5&lt;/span&gt;&lt;/pre&gt;

&lt;h1&gt;Setting It Up&lt;/h1&gt;

&lt;p&gt;To use SmartyRoute in an application add a reference to the eStuff.Routing project and then go to your global.asax.cs and add this simple registration:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt;[] supportedExtensions = &lt;span class="kwrd"&gt;new&lt;/span&gt;[] { &lt;span class="str"&gt;&amp;quot;aspx&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;ashx&amp;quot;&lt;/span&gt; };
    RouteTable.Routes.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; SmartyRoute(supportedExtensions));&lt;/pre&gt;
&lt;style type="text/css"&gt;

.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; }&lt;/style&gt;

&lt;p&gt;And that’s it!&lt;/p&gt;

&lt;h1&gt;Sample Project&lt;/h1&gt;

&lt;p&gt;In the &lt;a href="http://weblogs.asp.net/blogs/leftslipper/SmartyRoute.zip"&gt;attached sample project&lt;/a&gt; (13KB) there is the eStuff.Routing project and a sample ASP.NET Web Application Project. Open the solution in Visual Studio 2008 (with SP1) and try out these URLs:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;http://localhost:59519/Default (will load ~/default.aspx) &lt;/li&gt;

  &lt;li&gt;http://localhost:59519/foo/bar (will load ~/foo/bar.aspx) &lt;/li&gt;

  &lt;li&gt;http://localhost:59519/category/beverages/5/soda (will load ~/category.aspx with parameters) &lt;/li&gt;

  &lt;li&gt;http://localhost:59519/MyHandlers/Boring (will load ~/MyHandlers/Boring.ashx handler) &lt;/li&gt;

  &lt;li&gt;http://localhost:59519/MyHandlers/CoolStuff/Quote (will try to load ~/MyHandlers/CoolStuff/Quote.ashx handler but will fail due to web.config security) &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note that you can still make requests using the file extensions: SmartyRoute doesn’t block any current functionality (not really, anyway).&lt;/p&gt;

&lt;h1&gt;Feedback, Please!&lt;/h1&gt;

&lt;p&gt;I’d love to hear whether people find this sort of routing functionality useful. The key advantage of this simplified routing system is that you, the developer, don’t have to specify any URL route formats, yet you get most of the advantages of ASP.NET Routing: Extensionless URLs, custom data in the path info, better SEO.&lt;/p&gt;

&lt;p&gt;Would you use this in an application that you are building?&lt;/p&gt;

&lt;p&gt;Are you already doing something similar in an existing application?&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7224924" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/c_2300_/default.aspx">c#</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/Routing/default.aspx">Routing</category></item><item><title>The String or the Cat: A New .NET Framework Library</title><link>http://weblogs.asp.net/leftslipper/archive/2009/04/01/the-string-or-the-cat-a-new-net-framework-library.aspx</link><pubDate>Wed, 01 Apr 2009 10:00:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7018239</guid><dc:creator>Eilon</dc:creator><slash:comments>50</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=7018239</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2009/04/01/the-string-or-the-cat-a-new-net-framework-library.aspx#comments</comments><description>&lt;P&gt;For years applications have been built that accept user input. Most user input starts out as a string. Strings are a universal representation of arbitrary data coming into a computer. However, most data does not remain as a string for very long. User input often ends up getting parsed or converted into another data type, such as an integer, Boolean value, or a date.&lt;/P&gt;
&lt;P&gt;The concepts presented here are based on a &lt;A href="http://en.wikipedia.org/wiki/Schr%C3%B6dinger%27s_cat" mce_href="http://en.wikipedia.org/wiki/Schr%C3%B6dinger%27s_cat"&gt;thought experiment&lt;/A&gt; proposed by scientist &lt;A href="http://en.wikipedia.org/wiki/Erwin_Schr%C3%B6dinger" mce_href="http://en.wikipedia.org/wiki/Erwin_Schr%C3%B6dinger"&gt;Erwin Schrödinger&lt;/A&gt;. While an understanding of quantum physics will help to understand the new types and APIs, it is not required.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image002_2.jpg" mce_href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image002_2.jpg"&gt;&lt;IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; BORDER-TOP: 0px; BORDER-RIGHT: 0px" border=0 alt=clip_image002 src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image002_thumb.jpg" width=387 height=226 mce_src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image002_thumb.jpg"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Mutation of data types leaves a software developer in an interesting situation if the data was not formatted properly and thus could not be mutated. For example, the string “abc123” cannot be parsed into an integer. Many frameworks deal with this situation by immediately reporting an error condition. That error could be an exception that was thrown or a Boolean value of false to indicate failure. Keeping track of these states can easily introduce uncertainty into an application.&lt;/P&gt;
&lt;H2&gt;StringOr&amp;lt;TOther&amp;gt;&lt;/H2&gt;
&lt;P&gt;The first class being introduced is the StringOr class. It is a generic class that encapsulates both the original string user input as well as the result of an attempted conversion operation.&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;namespace &lt;/SPAN&gt;System.QuantumEntanglement {
    &lt;SPAN style="COLOR: blue"&gt;public class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;StringOr&lt;/SPAN&gt;&amp;lt;TOther&amp;gt; {
        &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;StringOr(&lt;SPAN style="COLOR: blue"&gt;string &lt;/SPAN&gt;stringValue, TOther otherValue);

        &lt;SPAN style="COLOR: blue"&gt;public string &lt;/SPAN&gt;StringValue { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; }
        &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;TOther OtherValue { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; }
    }
}&lt;/PRE&gt;
&lt;P&gt;The usage of the StringOr class is quite simple. An API that wishes to return data that might not have been parsed successfully can use the StringOr class to represent the dual state of its return value.&lt;/P&gt;
&lt;P&gt;For example, a typical application might have a TextBox for entering an integer quantity:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image004_2.jpg" mce_href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image004_2.jpg"&gt;&lt;IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; BORDER-TOP: 0px; BORDER-RIGHT: 0px" border=0 alt=clip_image004 src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image004_thumb.jpg" width=489 height=208 mce_src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image004_thumb.jpg"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;If the consumer of this API wants the original value, they can use the StringValue property. Otherwise they can use the OtherValue property, which in this case is the successfully parsed integer.&lt;/P&gt;
&lt;P&gt;The following diagram illustrates the dichotomy with a scenario familiar to many physicists:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image006_2.jpg" mce_href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image006_2.jpg"&gt;&lt;IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; BORDER-TOP: 0px; BORDER-RIGHT: 0px" border=0 alt=clip_image006 src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image006_thumb.jpg" width=370 height=260 mce_src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image006_thumb.jpg"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;H2&gt;SchrodingOr&amp;lt;TDead, TAlive&amp;gt;&lt;/H2&gt;
&lt;P&gt;The second class being introduced is the SchrodingOr class. It is similar to the StringOr, but with a distinct difference regarding its states. The SchrodingOr can represent any two data types: It is not restricted to one of the types being a string.&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;namespace &lt;/SPAN&gt;System.QuantumEntanglement {
    &lt;SPAN style="COLOR: blue"&gt;public class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;SchrodingOr&lt;/SPAN&gt;&amp;lt;TDead, TAlive&amp;gt; {
        &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;SchrodingOr(TDead dead, TAlive alive);

        &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;TAlive Alive { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; }
        &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;TDead Dead { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; }
    }
}&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;The usage of the SchrodingOr class is also similar to the StringOr. An API that wishes to return data that might be either of two data types, but never both data types at the same time, can return a SchrodingOr. The following code sample demonstrates a case where an API returns a value that can be either a bool or a DateTime.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image008_2.jpg" mce_href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image008_2.jpg"&gt;&lt;IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; BORDER-TOP: 0px; BORDER-RIGHT: 0px" border=0 alt=clip_image008 src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image008_thumb.jpg" width=401 height=224 mce_src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image008_thumb.jpg"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Depending on the effects of quantum mechanics one of the two properties will return its value, while the other will throw a HeisenburgException. As before, the following diagram illustrates the dichotomy of the two possible values:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image010_2.jpg" mce_href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image010_2.jpg"&gt;&lt;IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; BORDER-TOP: 0px; BORDER-RIGHT: 0px" border=0 alt=clip_image010 src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image010_thumb.jpg" width=370 height=261 mce_src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/TheStringortheCatANe.NETFrameworkLibrary_1186B/clip_image010_thumb.jpg"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;H2&gt;System.QuantumEntanglement Community Technology Preview&lt;/H2&gt;
&lt;P&gt;While the new .NET Framework library is still in relatively early stages of development, the team has decided to release a sneak preview to get feedback from our users. The link below contains the full source code for the new library, as well as unit tests that demonstrate proper usage of the libraries.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/SchrodingOr.zip" mce_href="http://weblogs.asp.net/blogs/leftslipper/SchrodingOr.zip"&gt;Class library with unit tests&lt;/A&gt; (requires Visual Studio 2008 Professional and higher)&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Please send all questions, comments, and suggestions to &lt;A href="mailto:aprilfools@example.com" mce_href="mailto:aprilfools@example.com"&gt;string.or@microsoft.com&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;Many thanks,&lt;/P&gt;
&lt;P&gt;The .NET Framework Quantum Mechanics Team&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7018239" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/c_2300_/default.aspx">c#</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/unit+test/default.aspx">unit test</category></item><item><title>ASP.NET MVC Release Candidate 2: I declare myself to be declarative!</title><link>http://weblogs.asp.net/leftslipper/archive/2009/03/03/asp-net-mvc-release-candidate-2-i-declare-myself-to-be-declarative.aspx</link><pubDate>Wed, 04 Mar 2009 00:15:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6936777</guid><dc:creator>Eilon</dc:creator><slash:comments>36</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=6936777</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2009/03/03/asp-net-mvc-release-candidate-2-i-declare-myself-to-be-declarative.aspx#comments</comments><description>&lt;P&gt;Today is a happy day: we released &lt;A href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&amp;amp;FamilyID=ee4b2e97-8a72-449a-82d2-2f720d421031" mce_href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&amp;amp;FamilyID=ee4b2e97-8a72-449a-82d2-2f720d421031"&gt;ASP.NET MVC Release Candidate 2&lt;/A&gt;. We're getting ever-so-close to the final (RTM/RTW) release of ASP.NET MVC - it won't be long! We think we fixed all the highest priority issues so that everyone out there can build ASP.NET MVC applications without worrying that we're going to make some sudden changes that will break you. Please see &lt;A href="http://www.haacked.com/archive/2009/03/03/aspnetmvc-changes-for-rc2.aspx" mce_href="http://www.haacked.com/archive/2009/03/03/aspnetmvc-changes-for-rc2.aspx"&gt;Phil's blog post announcing the release&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;In this blog post I'll introduce you to a feature that's not even part of the main ASP.NET MVC download. It's part of the separate MVC Futures download, which includes prototypes of features that we're thinking of including in a future version of ASP.NET MVC.&lt;/P&gt;
&lt;H2&gt;Introduction to the MVC Controls&lt;/H2&gt;
&lt;P&gt;Before we dig into the details, let's create a simple ASP.NET MVC application that uses the MVC Controls.&lt;/P&gt;
&lt;P&gt;1. Download the &lt;A href="http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24142" mce_href="http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24142"&gt;MVC Futures binary&lt;/A&gt; from CodePlex.&lt;/P&gt;
&lt;P&gt;2. Create a new MVC Web Application Project (if asked, feel free to not create a unit test project). Please note that you must have Release Candidate 2 installed. Each release of ASP.NET MVC has a matching release of MVC Futures. Mixing releases is not supported and usually doesn't work.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/01-NewProject_2.png" mce_href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/01-NewProject_2.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=418 alt=01-NewProject src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/01-NewProject_thumb.png" width=689 border=0 mce_src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/01-NewProject_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;3. Add a reference to the MVC Futures binary. Right-click on the References node in Solution Explorer and choose "Add Reference". Select the "Browse" tab and navigate to the location to which you saved Microsoft.Web.Mvc.dll, select the file, and select OK.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/02-AddReference_2.png" mce_href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/02-AddReference_2.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=279 alt=02-AddReference src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/02-AddReference_thumb.png" width=334 border=0 mce_src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/02-AddReference_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/03-References_2.png" mce_href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/03-References_2.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=410 alt=03-References src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/03-References_thumb.png" width=486 border=0 mce_src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/03-References_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;4. Edit the web.config in the root of the application to include tag mappings to the MVC Futures namespace. This tells the ASP.NET parser where to locate the controls when you type in an &amp;lt;mvc:SomeControl&amp;gt; tag. There should already be some tag mappings listed - the only new tag mapping is the third one with "mvc" as the tag prefix.&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;pages&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;
  &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;controls&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;tagPrefix&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;asp&lt;/SPAN&gt;" &lt;SPAN style="COLOR: red"&gt;namespace&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;System.Web.UI&lt;/SPAN&gt;" &lt;SPAN style="COLOR: red"&gt;assembly&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;/&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;tagPrefix&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;asp&lt;/SPAN&gt;" &lt;SPAN style="COLOR: red"&gt;namespace&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;System.Web.UI.WebControls&lt;/SPAN&gt;" &lt;SPAN style="COLOR: red"&gt;assembly&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;/&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;tagPrefix&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;mvc&lt;/SPAN&gt;" &lt;SPAN style="COLOR: red"&gt;namespace&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;Microsoft.Web.Mvc.Controls&lt;/SPAN&gt;" &lt;SPAN style="COLOR: red"&gt;assembly&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;Microsoft.Web.Mvc&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;/&amp;gt;
  &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;controls&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;
&lt;/SPAN&gt;  ...&lt;/PRE&gt;
&lt;P&gt;5. Start using the controls!&lt;/P&gt;
&lt;P&gt;Let's start out with a simple scenario of updating some of the Account and Membership features of the default template to use the MVC Controls.&lt;/P&gt;
&lt;P&gt;1. Open up the ~/Views/Account/LogOn.aspx view page. The markup there should include this text box:&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="BACKGROUND: #ffee62"&gt;&amp;lt;%&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;= &lt;/SPAN&gt;Html.TextBox(&lt;SPAN style="COLOR: #a31515"&gt;"username"&lt;/SPAN&gt;) &lt;SPAN style="BACKGROUND: #ffee62"&gt;%&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;2. Change the text box markup to use the MVC TextBox control:&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;mvc&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;TextBox &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;runat&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="server" &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Name&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="username" /&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;(Please note that it sometimes takes Visual Studio a few moments to recognize new tag mappings. If Intellisense doesn't show up, please just give it a minute.)&lt;/P&gt;
&lt;P&gt;3. Run the application and click "Log On" at the top-right of the page.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/04-Login_2.png" mce_href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/04-Login_2.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=173 alt=04-Login src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/04-Login_thumb.png" width=300 border=0 mce_src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/04-Login_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;4. If all is well, the page should continue to have the exact same behavior as before. For example, if you immediately click "Log On" without typing in a username or password you should see the red highlight on the text box indicating an error.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/05-errors_2.png" mce_href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/05-errors_2.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=484 alt=05-errors src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/05-errors_thumb.png" width=603 border=0 mce_src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/05-errors_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;The idea of the MVC Controls is that they are largely modeled after the HtmlHelpers, and thus try to preserve all their behavior. This includes naming conventions, the markup they render, and usage of model state.&lt;/P&gt;
&lt;H2&gt;Advanced MVC Controls&lt;/H2&gt;
&lt;P&gt;For a more advanced scenario involving the MVC Controls I'd like to introduce the MVC Repeater control. In many ways it is very similar to the ASP.NET Repeater control, but the main difference is of course that the MVC Repeater has specific knowledge of ViewData.&lt;/P&gt;
&lt;P&gt;1. In the application you already created, open ~/Controllers/HomeController.cs (Sorry, I don't have a VB sample!) and add this new action method and two classes:&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ActionResult &lt;/SPAN&gt;ProductList() {
    &lt;SPAN style="COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Distributor&lt;/SPAN&gt;&amp;gt; distributors = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Distributor&lt;/SPAN&gt;&amp;gt; {
        &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Distributor &lt;/SPAN&gt;{ DistributorID = 501, Name = &lt;SPAN style="COLOR: #a31515"&gt;"Joe's Shop"&lt;/SPAN&gt;, Location = &lt;SPAN style="COLOR: #a31515"&gt;"Redmond, WA" &lt;/SPAN&gt;},
        &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Distributor &lt;/SPAN&gt;{ DistributorID = 502, Name = &lt;SPAN style="COLOR: #a31515"&gt;"Jill's Shop"&lt;/SPAN&gt;, Location = &lt;SPAN style="COLOR: #a31515"&gt;"Los Angeles, CA" &lt;/SPAN&gt;},
        &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Distributor &lt;/SPAN&gt;{ DistributorID = 503, Name = &lt;SPAN style="COLOR: #a31515"&gt;"Jeremy's Shop"&lt;/SPAN&gt;, Location = &lt;SPAN style="COLOR: #a31515"&gt;"Boston, MA" &lt;/SPAN&gt;},
    };

    &lt;SPAN style="COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Product&lt;/SPAN&gt;&amp;gt; products = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Product&lt;/SPAN&gt;&amp;gt; {
        &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Product &lt;/SPAN&gt;{
            ProductID = 1001, 
            Name = &lt;SPAN style="COLOR: #a31515"&gt;"LEGO Technic Off Roader"&lt;/SPAN&gt;, 
            UnitPrice = 119.99m,
            Distributors = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Distributor&lt;/SPAN&gt;&amp;gt; { distributors[0], distributors[1] } },
        &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Product &lt;/SPAN&gt;{ 
            ProductID = 1002, 
            Name = &lt;SPAN style="COLOR: #a31515"&gt;"Ferrari F430"&lt;/SPAN&gt;, 
            UnitPrice = 189000m, 
            Distributors = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Distributor&lt;/SPAN&gt;&amp;gt; { distributors[0], distributors[1], distributors[2] } },
        &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Product &lt;/SPAN&gt;{ 
            ProductID = 1003, 
            Name = &lt;SPAN style="COLOR: #a31515"&gt;"Five bedroom house in Bellevue, WA"&lt;/SPAN&gt;,
            UnitPrice = 540000m, 
            Distributors = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Distributor&lt;/SPAN&gt;&amp;gt; { } },
        &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Product &lt;/SPAN&gt;{ 
            ProductID = 1004, 
            Name = &lt;SPAN style="COLOR: #a31515"&gt;"Dell 2007FP LCD monitor"&lt;/SPAN&gt;, 
            UnitPrice = 439m,
            Distributors = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Distributor&lt;/SPAN&gt;&amp;gt; { distributors[2] } },
    };

    ViewData[&lt;SPAN style="COLOR: #a31515"&gt;"products"&lt;/SPAN&gt;] = products;

    &lt;SPAN style="COLOR: blue"&gt;return &lt;/SPAN&gt;View();
}

&lt;SPAN style="COLOR: blue"&gt;public class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Product &lt;/SPAN&gt;{
    &lt;SPAN style="COLOR: blue"&gt;public int &lt;/SPAN&gt;ProductID { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
    &lt;SPAN style="COLOR: blue"&gt;public string &lt;/SPAN&gt;Name { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
    &lt;SPAN style="COLOR: blue"&gt;public decimal &lt;/SPAN&gt;UnitPrice { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
    &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Distributor&lt;/SPAN&gt;&amp;gt; Distributors { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
}

&lt;SPAN style="COLOR: blue"&gt;public class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Distributor &lt;/SPAN&gt;{
    &lt;SPAN style="COLOR: blue"&gt;public int &lt;/SPAN&gt;DistributorID { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
    &lt;SPAN style="COLOR: blue"&gt;public string &lt;/SPAN&gt;Name { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
    &lt;SPAN style="COLOR: blue"&gt;public string &lt;/SPAN&gt;Location { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
}&lt;/PRE&gt;
&lt;P&gt;2. Right-click anywhere in the action method and choose Add View with the default options and select "Add":&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/06-addview_2.png" mce_href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/06-addview_2.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=443 alt=06-addview src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/06-addview_thumb.png" width=418 border=0 mce_src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/06-addview_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;3. In the newly created view add this ASPX markup to the second content placeholder (right below the &amp;lt;h2&amp;gt; tag):&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;mvc&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Repeater &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;runat&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="server" &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Name&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="products"&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;ItemTemplate&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;
        &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;b&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;mvc&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Label &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;runat&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="server" &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Name&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="Name" /&amp;gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;b&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;
        &lt;/SPAN&gt;(PID#&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;mvc&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Label &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;runat&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="server" &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Name&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="ProductID" /&amp;gt;&lt;/SPAN&gt;)
        $&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;mvc&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Label &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;runat&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="server" &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Name&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="UnitPrice" /&amp;gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;br &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;/&amp;gt;
        &lt;/SPAN&gt;Distributors:&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;br &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;/&amp;gt;
        &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;mvc&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Repeater &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;runat&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="server" &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Name&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="distributors"&amp;gt;
            &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;ItemTemplate&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;
                &lt;/SPAN&gt;- &lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;b&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;mvc&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Label &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;runat&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="server" &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Name&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="Name" /&amp;gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;b&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;
                &lt;/SPAN&gt;(DID#&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;mvc&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Label &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;runat&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="server" &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Name&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="DistributorID" /&amp;gt;&lt;/SPAN&gt;),
                located in &lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;mvc&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Label &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;runat&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="server" &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;Name&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="Location" /&amp;gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;br &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;/&amp;gt;
            &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;ItemTemplate&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;
            &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;EmptyDataTemplate&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;
                &lt;/SPAN&gt;- Sorry, there are no distributors for this item&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;br &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;/&amp;gt;
            &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;EmptyDataTemplate&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;
        &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;mvc&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Repeater&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;
        &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;br &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;/&amp;gt;
    &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;ItemTemplate&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;
&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;mvc&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Repeater&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;Please note that when you paste in the code Visual Studio might add an "ID" attribute to every control tag. You can delete all those attributes if you don't want them - but it's fine to leave them. 
&lt;P&gt;4. Run the page and you will get this nested databound rendering:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/07-rendering_2.png" mce_href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/07-rendering_2.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=341 alt=07-rendering src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/07-rendering_thumb.png" width=418 border=0 mce_src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/07-rendering_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;H2&gt;Advantages of MVC Controls Over Code Nuggets&lt;/H2&gt;
&lt;P&gt;If you've used the default WebFormViewEngine in ASP.NET MVC, you've certainly used this syntax somewhere in your views:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&amp;lt;%= Html.TextBox("FirstName") %&amp;gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;What you might not know is that this syntax is called a "code nugget." While there is nothing inherently wrong with using code nuggets, one advantage of using MVC Controls is that they can provide a rich design-time experience. Many developers, even those who are familiar with the intricacies of HTML and CSS, like to get an accurate preview of what their page will look like without running the application.&lt;/P&gt;
&lt;P&gt;If you've used ASP.NET Web Forms and controls such as the SqlDataSource and the GridView, you've seen how rich a design-time experience can be. Those controls include design time rendering previews, advanced template editing, and even wizards that walk you through the steps of configuring the controls.&lt;/P&gt;
&lt;P&gt;The MVC Controls in the MVC Futures download are just a start: they certainly don't have the fit and finish that is seen in the SqlDataSource design-time experience. Like many &lt;EM&gt;rumors &lt;/EM&gt;about ASP.NET MVC itself have stated, the beginnings of the MVC Controls were &lt;EM&gt;in fact &lt;/EM&gt;written on an airplane!&lt;/P&gt;
&lt;P&gt;Compare the areas in the following screen shot of the text box we created earlier to see the difference. The MVC Control has a proper preview, whereas the HTML Helper doesn't render at all.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/08-DesignView_2.png" mce_href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/08-DesignView_2.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=626 alt=08-DesignView src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/08-DesignView_thumb.png" width=521 border=0 mce_src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCReleaseCandidate2Ideclaremysel_BBDA/08-DesignView_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;H2&gt;Disadvantages of MVC Controls&lt;/H2&gt;
&lt;P&gt;One of the biggest disadvantages of the MVC Controls is that there is a rather immediate limit to how you can use them. For example, take this relatively simple scenario with the regular TextBox HtmlHelper:&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="BACKGROUND: #ffee62"&gt;&amp;lt;%&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;= &lt;/SPAN&gt;Html.TextBox(&lt;SPAN style="COLOR: #a31515"&gt;"FirstName"&lt;/SPAN&gt;, Model.FirstName.ToUpper()) &lt;SPAN style="BACKGROUND: #ffee62"&gt;%&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;There is no simple way to do this with the MVC Controls because there is no place to add your own code to pre-process the values.&lt;/P&gt;
&lt;P&gt;Another disadvantage is that the MVC Controls work only with the WebFormViewEngine. There are several other view engines out there that people have been using with ASP.NET MVC. Some of the popular third party view engines out there are &lt;A href="http://dev.dejardin.org/documentation" mce_href="http://dev.dejardin.org/documentation"&gt;Spark view engine&lt;/A&gt;, &lt;A class="" href="http://code.google.com/p/nhaml/" mce_href="http://code.google.com/p/nhaml/"&gt;NHaml&lt;/A&gt;,&amp;nbsp;and the view engines included in the &lt;A href="http://www.mvccontrib.org/"&gt;MVC Contrib&lt;/A&gt; project, which are Brail, NVelocity, and XSLT.&lt;/P&gt;
&lt;P&gt;For ASP.NET MVC 1.0 we decided on the MVC team to focus our efforts on features that have the widest possible benefit. In this case it meant writing helpers that worked with as many different view engines as possible.&lt;/P&gt;
&lt;P&gt;As a slight bit of humor (though it's in fact serious), please refer to &lt;A href="http://blogs.msdn.com/ericlippert/default.aspx" mce_href="http://blogs.msdn.com/ericlippert/default.aspx"&gt;Eric Lippert's&lt;/A&gt; blog post &lt;A href="http://blogs.msdn.com/ericlippert/archive/2003/10/28/53298.aspx" mce_href="http://blogs.msdn.com/ericlippert/archive/2003/10/28/53298.aspx"&gt;How many Microsoft employees does it take to change a lightbulb?&lt;/A&gt;&lt;/P&gt;
&lt;H2&gt;The Future of the MVC Controls&lt;/H2&gt;
&lt;P&gt;As I mentioned in the top of the post, the MVC Controls are just a prototype. They are not complete; they are not set in stone; and there is no guarantee that they will ever be part of the main ASP.NET MVC download.&lt;/P&gt;
&lt;P&gt;I already have a long list of improvements to make to the MVC Controls. I plan to add many more controls as well as more advanced features to existing controls.&lt;/P&gt;
&lt;P&gt;If you have any feedback, comments, or suggestions on the MVC Controls feel free to post them here. We take all feedback seriously!&lt;/P&gt;
&lt;P&gt;Some questions to think about:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Do you see yourself using the MVC Controls? 
&lt;UL&gt;
&lt;LI&gt;If so, why? &lt;/LI&gt;
&lt;LI&gt;If not, why not? &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;What MVC Controls would you see yourself using the most? (Even ones that don't exist yet.) &lt;/LI&gt;&lt;/OL&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6936777" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/aspnetmvc/default.aspx">aspnetmvc</category></item><item><title>Opening an ASP.NET MVC project without having ASP.NET MVC installed: The project type is not supported by this installation</title><link>http://weblogs.asp.net/leftslipper/archive/2009/01/20/opening-an-asp-net-mvc-project-without-having-asp-net-mvc-installed-the-project-type-is-not-supported-by-this-installation.aspx</link><pubDate>Tue, 20 Jan 2009 13:00:24 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6845149</guid><dc:creator>Eilon</dc:creator><slash:comments>15</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=6845149</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2009/01/20/opening-an-asp-net-mvc-project-without-having-asp-net-mvc-installed-the-project-type-is-not-supported-by-this-installation.aspx#comments</comments><description>&lt;p&gt;Projects built with &lt;a href="http://www.asp.net/mvc/"&gt;ASP.NET MVC&lt;/a&gt; are what are known as &amp;quot;&lt;a href="http://msdn.microsoft.com/en-us/library/bb166488.aspx"&gt;flavored projects&lt;/a&gt;.&amp;quot; This means that instead of being an entirely new project type, ASP.NET MVC projects merely extend a different kind of existing project type. Specifically, the projects extend the Web Application Project type.&lt;/p&gt;  &lt;p&gt;If you try to open a flavored project and don't have that particular flavored project system installed, you get to see this little slice of heaven:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/OpeninganASP.NETMVCproje.NETMVCinstalled_BDFD/image_2.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="216" alt="Visual Studio error message: The project type is not supported by this installation" src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/OpeninganASP.NETMVCproje.NETMVCinstalled_BDFD/image_thumb.png" width="500" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;If you select &amp;quot;OK&amp;quot; then Visual Studio will continue, but the project will not be loaded:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/OpeninganASP.NETMVCproje.NETMVCinstalled_BDFD/image_4.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="107" alt="Solution Explorer: Project unavailable" src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/OpeninganASP.NETMVCproje.NETMVCinstalled_BDFD/image_thumb_1.png" width="339" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Well, then, what do you do to continue? All you have to do is edit the project file to remove the flavoring. Right-click on the project, and select &amp;quot;Edit MyProjectName.vbproj&amp;quot;.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/OpeninganASP.NETMVCproje.NETMVCinstalled_BDFD/image_6.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="208" alt="image" src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/OpeninganASP.NETMVCproje.NETMVCinstalled_BDFD/image_thumb_2.png" width="341" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;This will launch Visual Studio's project file editor (with Intellisense, in case you didn't know!). Towards the top you'll see a list of project types associated with this project, each one represented by a &lt;a href="http://en.wikipedia.org/wiki/GUID"&gt;GUID&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;pre&gt;&lt;span class="kwrd"&gt;  &amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ProjectTypeGuids&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;{603c0e0b-db56-11dc-be95-000d561079b0};{349c5851-65df-11da-9384-00065b846f21};{F184B08F-C81C-45F6-A57F-5ABD9991F28F}&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ProjectTypeGuids&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;
.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; }&lt;/style&gt;&lt;style type="text/css"&gt;


.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; }&lt;/style&gt;

&lt;p&gt;The first GUID there (the one that starts with &amp;quot;603c&amp;quot;) is the one used by ASP.NET MVC projects. Remove that GUID so you end up with:&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre&gt;&lt;span class="kwrd"&gt;  &amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ProjectTypeGuids&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;{349c5851-65df-11da-9384-00065b846f21};{F184B08F-C81C-45F6-A57F-5ABD9991F28F}&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ProjectTypeGuids&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;
.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; }&lt;/style&gt;

&lt;p&gt;Save the project file and close it.&lt;/p&gt;

&lt;p&gt;Now reload the project:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/OpeninganASP.NETMVCproje.NETMVCinstalled_BDFD/image_8.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="207" alt="image" src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/OpeninganASP.NETMVCproje.NETMVCinstalled_BDFD/image_thumb_3.png" width="340" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you'll be able to work on the project once again. The only thing you won't be able to use is MVC project-specific features such as the &amp;quot;Add View&amp;quot; menu option.&lt;/p&gt;

&lt;p&gt;I find myself doing this very often since my work machine is always in a bizarre state with respect to ASP.NET MVC and I often don't have the project type installed. This is much faster than trying to install MVC just so I can inspect a project.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6845149" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/aspnetmvc/default.aspx">aspnetmvc</category></item><item><title>Optimizing your route collection for URL generation in ASP.NET MVC (and more!)</title><link>http://weblogs.asp.net/leftslipper/archive/2008/12/17/optimizing-your-route-collection-for-url-generation-in-asp-net-mvc-and-more.aspx</link><pubDate>Thu, 18 Dec 2008 05:00:49 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6793945</guid><dc:creator>Eilon</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=6793945</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2008/12/17/optimizing-your-route-collection-for-url-generation-in-asp-net-mvc-and-more.aspx#comments</comments><description>&lt;p&gt;If you're used &lt;a href="http://www.asp.net/mvc/"&gt;ASP.NET MVC&lt;/a&gt; or &lt;a href="http://www.asp.net/DynamicData/"&gt;ASP.NET Dynamic Data&lt;/a&gt;, you've using ASP.NET's new Routing feature. ASP.NET Routing is the feature that lets you easily create so-called &amp;quot;pretty&amp;quot; URLs. Pretty URLs are the ones that look the way you &lt;em&gt;want&lt;/em&gt; them to look (e.g. ~/products/beverages), not the way your web application platform &lt;em&gt;forces&lt;/em&gt; them to look (e.g. ~/products.aspx?categoryname=beverages).&lt;/p&gt;  &lt;p&gt;Many people, including myself, have blogged about the various features of Routing, but this post is about optimizing your routes to get the most out of them.&lt;/p&gt;  &lt;p&gt;Here are some tricks to make URL generation more performant in your application: &lt;/p&gt;  &lt;h2&gt;1. Use named routes&lt;/h2&gt;  &lt;p&gt;Named routes are an optional feature of routing. The names are only used for URL generation; they are never used for matching incoming URLs. When you specify a name when generating a URL we will only try to match the one route with that name. This means that even if the named route you specified is the 100th route in the route table we'll jump straight to it and try to match. Otherwise we'd try every single route until we get to the 100th route. Here's an example of using named routes in an MVC application:&lt;/p&gt;  &lt;p&gt;// Global.asax.cs&lt;/p&gt;  &lt;pre class="code"&gt;routes.MapRoute(
    &lt;span style="color: #a31515"&gt;&amp;quot;products-route&amp;quot;&lt;/span&gt;,
    &lt;span style="color: #a31515"&gt;&amp;quot;products/{category}&amp;quot;&lt;/span&gt;,
    &lt;span style="color: blue"&gt;new &lt;/span&gt;{
        controller = &lt;span style="color: #a31515"&gt;&amp;quot;products&amp;quot;&lt;/span&gt;,
        action = &lt;span style="color: #a31515"&gt;&amp;quot;category&amp;quot;&lt;/span&gt;,
    });&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;// Views/Home/Index.aspx&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;= &lt;/span&gt;Html.RouteLink(&lt;span style="color: #a31515"&gt;&amp;quot;Show Beverages&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;products-route&amp;quot;&lt;/span&gt;, &lt;span style="color: blue"&gt;new &lt;/span&gt;{ category = &lt;span style="color: #a31515"&gt;&amp;quot;beverages&amp;quot; &lt;/span&gt;}) &lt;span style="background: #ffee62"&gt;%&amp;gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Note that if we hadn't specified the name route, we would probably get a different route to match. Also, because we used the named route, we didn't have to specify any extra route values such as the controller or action name.&lt;/p&gt;

&lt;h2&gt;2. Put your most common routes at the beginning of the route table&lt;/h2&gt;

&lt;p&gt;This will improve performance of both URL generation as well as processing incoming URLs. The Routing system works on a very simple rule: the first match wins. If the first match happens to be the 100th route in your route table, then that means it had to try 99 other routes and none of them matched. By putting your most common routes towards the top of the route collection, they will match sooner.&lt;/p&gt;

&lt;p&gt;However, be careful: Changing the order of your routes can affect how they match. Only change the order of the routes if you're sure that it won't cause a conflict.&lt;/p&gt;

&lt;h2&gt;3. Don't use URL generation &lt;img alt="smile_sad" src="http://spaces.live.com/rte/emoticons/smile_sad.gif" /&gt;&lt;/h2&gt;

&lt;p&gt;Some people like URL generation and some people don't. It's a bit tricky to master URL generation. It's nice to use URL generation if your URLs are very dynamic and you don't want to update your whole site when you make changes to your URL structure. But it can be a bit of a hassle when you have very few URLs to begin with and perhaps you don't care about exactly what they look like.&lt;/p&gt;

&lt;h2&gt;My favorite&lt;/h2&gt;

&lt;p&gt;My favorite option is #1, using named routes, primarily since it's super easy to use. It also makes URL generation more deterministic from the app developer's perspective (that's you!). By giving things names and then specifying exactly what you won't, it eliminates the guessing game of routes.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6793945" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/aspnetmvc/default.aspx">aspnetmvc</category></item><item><title>Upcoming talks: Microsoft Tech Ed South Africa</title><link>http://weblogs.asp.net/leftslipper/archive/2008/07/22/upcoming-talks-microsoft-tech-ed-south-africa.aspx</link><pubDate>Wed, 23 Jul 2008 05:55:02 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6434383</guid><dc:creator>Eilon</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=6434383</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2008/07/22/upcoming-talks-microsoft-tech-ed-south-africa.aspx#comments</comments><description>&lt;p&gt;In just a couple of weeks I'll be in Durban, South Africa presenting three sessions at &lt;a href="http://www.teched.co.za/"&gt;Tech Ed&lt;/a&gt;. These are the sessions:&lt;/p&gt;  &lt;h2&gt;WEB304: Introduction to MVC Web Development&lt;/h2&gt;  &lt;p&gt;&lt;strong&gt;Day:&lt;/strong&gt; Monday, 04 August 2008, 09:15 - 10:30    &lt;br /&gt;&lt;strong&gt;Location:&lt;/strong&gt; Session Room 07    &lt;br /&gt;One of the benefits of using a MVC methodology is that it helps enforce a clean separation of concerns between the models, views, and controllers within an application. In the very near future, ASP.NET will include support for developing Web applications using an MVC-based architecture. The MVC pattern can also help enable red/green test-driven development (TDD) where you implement automated unit tests, which define and verify the requirements of new code, before you actually write the code itself. Join us for a dive into the new MVC Framework and learn how to leverage this new alternative in your own applications. &lt;/p&gt;  &lt;h2&gt;WEB306: What's new in Visual Studio 2008 for ASP.NET developers&lt;/h2&gt;  &lt;p&gt;&lt;strong&gt;Day:&lt;/strong&gt; Monday, 04 August 2008, 16:15 - 17:15    &lt;br /&gt;&lt;strong&gt;Location:&lt;/strong&gt; Session Room 08    &lt;br /&gt;Check out the latest and greatest with Microsoft Visual Studio 2008. From the CSS designer to JavaScript Intellisense, Visual Studio 2008 packs a powerful punch for building rich web applications. You&amp;#8217;ll also see how to use LINQ data access and unit testing in a web application.&lt;/p&gt;  &lt;h2&gt;WEB307: A Tour of What&amp;#8217;s New in ASP.NET 3.5&lt;/h2&gt;  &lt;p&gt;&lt;strong&gt;Day:&lt;/strong&gt; Tuesday, 05 August 2008, 16:45 - 17:45    &lt;br /&gt;&lt;strong&gt;Location:&lt;/strong&gt; Session Room 07    &lt;br /&gt;Discover how you can take advantage of the latest enhancements to ASP.NET and Visual Studio 2008 for building Web applications in your real-world applications. Enhance your web application with AJAX, Silverlight, and LINQ data access. You&amp;#8217;ll also see how to use ASP.NET Dynamic Data to build a data entry site in a matter of minutes. &lt;/p&gt;  &lt;p&gt;* Dates, times, and locations can change, so check your schedules!&lt;/p&gt;  &lt;p&gt;I hope to see some of you there, so please stop by and say hi!&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6434383" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/Speaking/default.aspx">Speaking</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/aspnetmvc/default.aspx">aspnetmvc</category></item><item><title>HttpContext.IsCustomErrorEnabled - One of ASP.NET's hidden gems</title><link>http://weblogs.asp.net/leftslipper/archive/2008/07/13/httpcontext-iscustomerrorenabled-one-of-asp-net-s-hidden-gems.aspx</link><pubDate>Mon, 14 Jul 2008 03:30:26 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6398779</guid><dc:creator>Eilon</dc:creator><slash:comments>7</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=6398779</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2008/07/13/httpcontext-iscustomerrorenabled-one-of-asp-net-s-hidden-gems.aspx#comments</comments><description>&lt;p&gt;Calling a property a gem might be a bit of an exaggeration, but this particular property is still rather valuable. In many situations a developer wants to enable a feature or part of a feature only for debugging and testing purposes. The &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.httpcontext.iscustomerrorenabled.aspx"&gt;IsCustomErrorEnabled property&lt;/a&gt; combines three values to tell you whether custom errors are enabled for a particular request. This isn't as simple as reading the web.config file to check the &amp;lt;customErrors&amp;gt; section. There's a bit more going on behind the scenes to truly determine whether custom errors are enabled.&lt;/p&gt;  &lt;p&gt;The property looks at these three values:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;The &lt;a href="http://msdn.microsoft.com/en-us/library/ms228298(VS.80).aspx"&gt;web.config's &amp;lt;deployment&amp;gt; section's retail property&lt;/a&gt;. This is a useful property to set when deploying your application to a production server. This overrides any other settings for custom errors.&lt;/li&gt;    &lt;li&gt;The &lt;a href="http://msdn.microsoft.com/en-us/library/h0hfz6fc.aspx"&gt;web.config's &amp;lt;customErrors&amp;gt; section's mode property&lt;/a&gt;. This setting indicates whether custom errors are enabled at all, and if so whether they are enabled only for remote requests.&lt;/li&gt;    &lt;li&gt;The &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.httprequest.islocal.aspx"&gt;HttpRequest object's IsLocal property&lt;/a&gt;. If custom errors are enabled only for remote requests, you need to know whether the request is from a remote computer.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;The property is used in several places in ASP.NET to determine what type of error message to display to the user. When custom errors are enabled, the error messages tend to be terse so as not to disclose any secret information. When custom errors are disabled, more extensive information is displayed to the user including stack traces, type names, and file paths. One of the nice things about this property is that it works in all trust levels (well, at least Medium trust and higher - I'm not sure about Low and Minimal). It's also nice that you don't have to worry about reading from web.config manually.&lt;/p&gt;  &lt;p&gt;Just recently in &lt;a href="http://www.asp.net/mvc/"&gt;ASP.NET MVC&lt;/a&gt; we added a feature where we used this property to determine whether to show a generic error message such as &amp;quot;Your site is broken!&amp;quot; instead of full stack traces and debugging information. I hope this property ends up getting called by your ASP.NET applications and controls!&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6398779" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>MVC: Unit testing controller actions that use TempData</title><link>http://weblogs.asp.net/leftslipper/archive/2008/04/13/mvc-unit-testing-controller-actions-that-use-tempdata.aspx</link><pubDate>Mon, 14 Apr 2008 04:00:52 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6095674</guid><dc:creator>Eilon</dc:creator><slash:comments>12</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=6095674</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2008/04/13/mvc-unit-testing-controller-actions-that-use-tempdata.aspx#comments</comments><description>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;Part of the &amp;quot;big deal&amp;quot; about &lt;a href="http://www.asp.net/mvc"&gt;ASP.NET MVC&lt;/a&gt;, and of course MVC in general, is that the code you write is more easily unit tested as compared to traditional ASP.NET WebForms. However, if you've used ASP.NET MVC and tried to write a unit test for a controller action that uses TempData, you probably got some exceptions about null references and other crazy stuff. I've seen a number of solutions out there that involve private reflection (which is kind of evil) so I figured I'd show how it can be done without that trickery. (Kudos, though, to those of you who figured out how to do such trickery!)&lt;/p&gt;  &lt;p&gt;The underlying problem is that the TempDataDictionary object tries to read from session state when it's first used. At unit test time ASP.NET is not running so there isn't any session state. The solution is to provide a mock session state object to the TempDataDictionary. We're basically telling TempDataDictionary, &amp;quot;Hey you want some session state??? Here's your session state!!!&amp;quot;&lt;/p&gt;  &lt;p&gt;The controller we're going to test has two actions. The first action adds a value to TempData and then does a redirect. The second action checks for the existence of the value in TempData and renders a view.&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HomeController &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;Controller &lt;/span&gt;{
    &lt;span style="color: blue"&gt;public void &lt;/span&gt;Index() {
        &lt;span style="color: green"&gt;// Save UserID into TempData and redirect to greeting page
        &lt;/span&gt;TempData[&lt;span style="color: #a31515"&gt;&amp;quot;UserID&amp;quot;&lt;/span&gt;] = &lt;span style="color: #a31515"&gt;&amp;quot;user123&amp;quot;&lt;/span&gt;;
        RedirectToAction(&lt;span style="color: #a31515"&gt;&amp;quot;GreetUser&amp;quot;&lt;/span&gt;);
    }

    &lt;span style="color: blue"&gt;public void &lt;/span&gt;GreetUser() {
        &lt;span style="color: green"&gt;// Check that the UserID is present. If it's not
        // there, redirect to error page. If it is, show
        // the greet user view.
        &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;(!TempData.ContainsKey(&lt;span style="color: #a31515"&gt;&amp;quot;UserID&amp;quot;&lt;/span&gt;)) {
            RedirectToAction(&lt;span style="color: #a31515"&gt;&amp;quot;ErrorPage&amp;quot;&lt;/span&gt;);
            &lt;span style="color: blue"&gt;return&lt;/span&gt;;
        }
        ViewData[&lt;span style="color: #a31515"&gt;&amp;quot;NewUserID&amp;quot;&lt;/span&gt;] = TempData[&lt;span style="color: #a31515"&gt;&amp;quot;UserID&amp;quot;&lt;/span&gt;];
        RenderView(&lt;span style="color: #a31515"&gt;&amp;quot;GreetUser&amp;quot;&lt;/span&gt;);
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;In order to write the unit tests I created a mock HttpContext with a mock session state object:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// HttpContext for TempData that uses a custom
// session object.
&lt;/span&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpContext &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;HttpContextBase &lt;/span&gt;{
    &lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpSessionState &lt;/span&gt;_sessionState =
        &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpSessionState&lt;/span&gt;();

    &lt;span style="color: blue"&gt;public override &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HttpSessionStateBase &lt;/span&gt;Session {
        &lt;span style="color: blue"&gt;get &lt;/span&gt;{
            &lt;span style="color: blue"&gt;return &lt;/span&gt;_sessionState;
        }
    }
}

&lt;span style="color: green"&gt;// HttpSessionState for TempData that uses a custom
// session object.
&lt;/span&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpSessionState &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;HttpSessionStateBase &lt;/span&gt;{
    &lt;span style="color: green"&gt;// This string is &amp;quot;borrowed&amp;quot; from the ASP.NET MVC source code
    &lt;/span&gt;&lt;span style="color: blue"&gt;private string &lt;/span&gt;TempDataSessionStateKey = &lt;span style="color: #a31515"&gt;&amp;quot;__ControllerTempData&amp;quot;&lt;/span&gt;;
    &lt;span style="color: blue"&gt;private object &lt;/span&gt;_tempDataObject;

    &lt;span style="color: blue"&gt;public override object this&lt;/span&gt;[&lt;span style="color: blue"&gt;string &lt;/span&gt;name] {
        &lt;span style="color: blue"&gt;get &lt;/span&gt;{
            &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;(
                TempDataSessionStateKey,
                name,
                &lt;span style="color: #a31515"&gt;&amp;quot;Wrong session key used&amp;quot;&lt;/span&gt;);
            &lt;span style="color: blue"&gt;return &lt;/span&gt;_tempDataObject;
        }
        &lt;span style="color: blue"&gt;set &lt;/span&gt;{
            &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;(
                TempDataSessionStateKey,
                name,
                &lt;span style="color: #a31515"&gt;&amp;quot;Wrong session key used&amp;quot;&lt;/span&gt;);
            _tempDataObject = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
        }
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;Each unit test that involves an action that uses TempData needs to create a custom TestTempDataHttpContext object and use that in a new instance of TempDataDictionary:

&lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpContext &lt;/span&gt;tempDataHttpContext = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpContext&lt;/span&gt;();
homeController.TempData = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TempDataDictionary&lt;/span&gt;(tempDataHttpContext);&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;I wrote three unit tests for HomeController:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Test that the Index action sets the right TempData and does a redirect&lt;/li&gt;

  &lt;li&gt;Test that the GreetUser action redirects when the TempData is missing the value&lt;/li&gt;

  &lt;li&gt;Test that the GreetUser action renders the GreetUser view with the right ViewData when the TempData has the right value&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And here are the unit tests:&lt;/p&gt;

&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;TestClass&lt;/span&gt;]
&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HomeControllerTest &lt;/span&gt;{
    [&lt;span style="color: #2b91af"&gt;TestMethod&lt;/span&gt;]
    &lt;span style="color: blue"&gt;public void &lt;/span&gt;IndexSavesUserIDToTempDataAndRedirects() {
        &lt;span style="color: green"&gt;// Setup
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestHomeController &lt;/span&gt;homeController = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestHomeController&lt;/span&gt;();
        &lt;span style="color: #2b91af"&gt;TestTempDataHttpContext &lt;/span&gt;tempDataHttpContext = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpContext&lt;/span&gt;();
        homeController.TempData = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TempDataDictionary&lt;/span&gt;(tempDataHttpContext);

        &lt;span style="color: green"&gt;// Execute
        &lt;/span&gt;homeController.Index();

        &lt;span style="color: green"&gt;// Verify
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.IsTrue(homeController.RedirectValues.ContainsKey(&lt;span style="color: #a31515"&gt;&amp;quot;action&amp;quot;&lt;/span&gt;));
        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual(&lt;span style="color: #a31515"&gt;&amp;quot;GreetUser&amp;quot;&lt;/span&gt;, homeController.RedirectValues[&lt;span style="color: #a31515"&gt;&amp;quot;action&amp;quot;&lt;/span&gt;]);

        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.IsTrue(homeController.TempData.ContainsKey(&lt;span style="color: #a31515"&gt;&amp;quot;UserID&amp;quot;&lt;/span&gt;));
        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual(&lt;span style="color: #a31515"&gt;&amp;quot;user123&amp;quot;&lt;/span&gt;, homeController.TempData[&lt;span style="color: #a31515"&gt;&amp;quot;UserID&amp;quot;&lt;/span&gt;]);
    }

    [&lt;span style="color: #2b91af"&gt;TestMethod&lt;/span&gt;]
    &lt;span style="color: blue"&gt;public void &lt;/span&gt;GreetUserWithNoUserIDRedirects() {
        &lt;span style="color: green"&gt;// Setup
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestHomeController &lt;/span&gt;homeController = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestHomeController&lt;/span&gt;();
        &lt;span style="color: #2b91af"&gt;TestTempDataHttpContext &lt;/span&gt;tempDataHttpContext = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpContext&lt;/span&gt;();
        homeController.TempData = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TempDataDictionary&lt;/span&gt;(tempDataHttpContext);

        &lt;span style="color: green"&gt;// Execute
        &lt;/span&gt;homeController.GreetUser();

        &lt;span style="color: green"&gt;// Verify
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.IsTrue(homeController.RedirectValues.ContainsKey(&lt;span style="color: #a31515"&gt;&amp;quot;action&amp;quot;&lt;/span&gt;));
        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual(&lt;span style="color: #a31515"&gt;&amp;quot;ErrorPage&amp;quot;&lt;/span&gt;, homeController.RedirectValues[&lt;span style="color: #a31515"&gt;&amp;quot;action&amp;quot;&lt;/span&gt;]);

        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual(0, homeController.TempData.Count);
    }

    [&lt;span style="color: #2b91af"&gt;TestMethod&lt;/span&gt;]
    &lt;span style="color: blue"&gt;public void &lt;/span&gt;GreetUserWithUserIDCopiesToViewDataAndRenders() {
        &lt;span style="color: green"&gt;// Setup
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestHomeController &lt;/span&gt;homeController = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestHomeController&lt;/span&gt;();
        &lt;span style="color: #2b91af"&gt;TestTempDataHttpContext &lt;/span&gt;tempDataHttpContext = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpContext&lt;/span&gt;();
        homeController.TempData = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TempDataDictionary&lt;/span&gt;(tempDataHttpContext);
        homeController.TempData[&lt;span style="color: #a31515"&gt;&amp;quot;UserID&amp;quot;&lt;/span&gt;] = &lt;span style="color: #a31515"&gt;&amp;quot;TestUserID&amp;quot;&lt;/span&gt;;

        &lt;span style="color: green"&gt;// Execute
        &lt;/span&gt;homeController.GreetUser();

        &lt;span style="color: green"&gt;// Verify
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;(&lt;span style="color: #a31515"&gt;&amp;quot;GreetUser&amp;quot;&lt;/span&gt;, homeController.RenderViewName);
        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;(&lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Empty, homeController.RenderMasterName);
        &lt;span style="color: #2b91af"&gt;IDictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;object&lt;/span&gt;&amp;gt; viewData =
            homeController.RenderViewData &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IDictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;object&lt;/span&gt;&amp;gt;;
        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.IsNotNull(viewData);
        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.IsTrue(viewData.ContainsKey(&lt;span style="color: #a31515"&gt;&amp;quot;NewUserID&amp;quot;&lt;/span&gt;));
        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual(&lt;span style="color: #a31515"&gt;&amp;quot;TestUserID&amp;quot;&lt;/span&gt;, viewData[&lt;span style="color: #a31515"&gt;&amp;quot;NewUserID&amp;quot;&lt;/span&gt;]);
    }

    &lt;span style="color: green"&gt;// Test-specific subclass for HomeController. This won't be
    // needed in the next release of ASP.NET MVC.
    &lt;/span&gt;&lt;span style="color: blue"&gt;private sealed class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestHomeController &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;HomeController &lt;/span&gt;{
        &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RouteValueDictionary &lt;/span&gt;RedirectValues;
        &lt;span style="color: blue"&gt;public string &lt;/span&gt;RenderViewName;
        &lt;span style="color: blue"&gt;public string &lt;/span&gt;RenderMasterName;
        &lt;span style="color: blue"&gt;public object &lt;/span&gt;RenderViewData;

        &lt;span style="color: blue"&gt;protected override void &lt;/span&gt;RedirectToAction(&lt;span style="color: #2b91af"&gt;RouteValueDictionary &lt;/span&gt;values) {
            RedirectValues = values;
        }

        &lt;span style="color: blue"&gt;protected override void &lt;/span&gt;RenderView(&lt;span style="color: blue"&gt;string &lt;/span&gt;viewName, &lt;span style="color: blue"&gt;string &lt;/span&gt;masterName,
            &lt;span style="color: blue"&gt;object &lt;/span&gt;viewData) {
            RenderViewName = viewName;
            RenderMasterName = masterName;
            RenderViewData = viewData;
        }
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Some notes about the code:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For the unit tests I also needed to create a &lt;a href="http://haacked.com/archive/2007/12/06/test-specific-subclasses-vs-partial-mocks.aspx"&gt;test-specific subclass&lt;/a&gt; for HomeController called TestHomeController in order to capture the values of a call to RedirectToAction and RenderView. In the upcoming preview of ASP.NET MVC this class won't be needed due to some changes we've made.&lt;/li&gt;

  &lt;li&gt;Making TempData easier to unit test is on our list of improvements for a later preview of ASP.NET MVC. We realize it's a bit tricky right now, and we plan to make it much, much easier.&lt;/li&gt;

  &lt;li&gt;Instead of creating concrete classes for the custom HttpContext and session state objects you could use a mock object framework to dynamically generate those instances. I chose not to show that since it might detract from the purpose of the post. If you're already using a mock object framework such as &lt;a href="http://www.ayende.com/projects/rhino-mocks.aspx"&gt;RhinoMocks&lt;/a&gt; or &lt;a href="http://code.google.com/p/moq/"&gt;Moq&lt;/a&gt; it should be easy to modify the code to use those frameworks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you find this sample useful when you're writing your unit tests. If you have any other pain points in ASP.NET MVC please post a comment so we'll know about it.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6095674" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/unit+test/default.aspx">unit test</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/aspnetmvc/default.aspx">aspnetmvc</category></item><item><title>MVC: Locking the RouteCollection</title><link>http://weblogs.asp.net/leftslipper/archive/2008/03/31/mvc-locking-the-routecollection.aspx</link><pubDate>Mon, 31 Mar 2008 22:00:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6050563</guid><dc:creator>Eilon</dc:creator><slash:comments>12</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=6050563</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2008/03/31/mvc-locking-the-routecollection.aspx#comments</comments><description>&lt;P&gt;Since the advent of multithreaded programming, the responsibility of locking collections has always been a contentious issue. Who should lock the collection? When should it be locked? And for how long? The ASP.NET Routing feature that is used by the MVC framework involves a thread-safe collection that contains the list of the application's route definitions. Will your routes be safe? Continue reading to find out (on this amazing journey (into the depths of the RouteCollection)). How's that for a cheesy intro?&lt;/P&gt;
&lt;H1&gt;The problem&lt;/H1&gt;
&lt;P&gt;When the first preview of ASP.NET MVC was released last December, some &lt;A href="http://abombss.com/blog/2007/12/19/ms-mvc-routing-the-good-the-bad-the-restful/" mce_href="http://abombss.com/blog/2007/12/19/ms-mvc-routing-the-good-the-bad-the-restful/"&gt;people&lt;/A&gt; &lt;A href="http://forums.asp.net/t/1194755.aspx" mce_href="http://forums.asp.net/t/1194755.aspx"&gt;noted&lt;/A&gt; that the RouteCollection would lock itself during all read and write operations, which could cause major performance and scaling issues. Well, sort of. The RouteCollection class derives from the generic &lt;A href="http://msdn2.microsoft.com/en-us/library/ms132397.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms132397.aspx"&gt;Collection&amp;lt;T&amp;gt;&lt;/A&gt;, which has a few virtual methods it calls when write operations are performed. Each of those methods was overridden in RouteCollection to take a full lock. The route operations of matching routes to incoming requests and generating URLs also took the same full lock. There were two problems (at least) with this approach:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Taking a full lock means that if anyone is using the collection, any other operation on that collection would have to wait for the first one to be done. Even if two requests just wanted to enumerate the collection (a read-only operation), one request would have to wait. This wasn't a logic bug since it wouldn't prevent anything from working; It was just a performance issue. There was in fact a comment in the code along the lines of "TODO: Shouldn't we use a ReaderWriterLockSlim here or something?" &lt;/LI&gt;
&lt;LI&gt;We weren't locking enough! If someone directly enumerated the collection by calling GetEnumerator (which happens implicitly when you use C# or VB's foreach statement), no lock would be taken. Unfortunately, Collection&amp;lt;T&amp;gt; does not offer any virtual methods that get called during read operations. &lt;/LI&gt;&lt;/OL&gt;
&lt;H1&gt;The solution (or so we thought)&lt;/H1&gt;
&lt;P&gt;We knew we had to do something for &lt;A href="http://www.asp.net/mvc/" mce_href="http://www.asp.net/mvc/"&gt;ASP.NET MVC Preview 2&lt;/A&gt;: We had performance problems as well as bugs in our collection locking. The first thing we did was change the lock to be a multiple-reader, single-writer lock with the &lt;A href="http://msdn2.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx"&gt;ReaderWriterLockSlim&lt;/A&gt; class. Using this class in the RouteCollection allows any number of readers to read the collection at the same time but will fully lock the collection when a write is performed and allow only that one writer to make changes until the write lock is released.&lt;/P&gt;
&lt;P&gt;Before we knew it, though, a bug was found while running some performance tests. When there is contention for the lock, the ReaderWriterLockSlim needs to get the processor count of the server. For some reason or another, getting that count is not permitted in Medium Trust web applications and thus throws a SecurityException. We didn't notice this while we were writing unit tests and web tests because all those tests are single threaded: there is never any contention for the lock.&lt;/P&gt;
&lt;H1&gt;&lt;/H1&gt;
&lt;H1&gt;The final solution&lt;/H1&gt;
&lt;P&gt;We opened a work item for the owners of Environment.ProcessorCount to remove the security requirement since knowing the processor count of the host is hardly top secret information. However, since the ASP.NET Routing feature works on .NET Framework 3.5, bug fixes in a future version wouldn't be sufficient. Thus we changed RouteCollection to use ReaderWriterLock, which is slightly less performant, but works in all web trust levels.&lt;/P&gt;
&lt;P&gt;So we solved the problem of when the collection gets locked and for how long. But what about the very first issue I mentioned: Who should lock the collection?&lt;/P&gt;
&lt;P&gt;Our first solution was to do all the locking internally. Any time you called any member on the collection we'd take the appropriate lock. This meant implementing IList&amp;lt;T&amp;gt; directly since neither Collection&amp;lt;T&amp;gt; nor List&amp;lt;T&amp;gt; provide the necessary hooks. This proved to be a lot of work (but not for me, since I didn't have to write it &lt;IMG alt=smile_regular src="http://spaces.live.com/rte/emoticons/smile_regular.gif" mce_src="http://spaces.live.com/rte/emoticons/smile_regular.gif"&gt;) and left some big holes of functionality. For example, how could someone atomically search for a route in the collection, remove it, and add a new route?&lt;/P&gt;
&lt;P&gt;The solution to that problem was to expose the lock semantics publicly, though without exposing the lock object itself. Thus the RouteCollection has two new methods: GetReadLock and GetWriteLock. Developers can call those methods to get the lock that the RouteCollection uses internally and cooperate with its locking mechanism. However, you only need to get the lock if you're directly accessing the collection. If you're going through any of the typical "end-user" API calls, we do the locking automatically. For example, calling Html.ActionLink, Url.Action, and RouteCollection.GetVirtualPath will automatically lock the collection.&lt;/P&gt;
&lt;P&gt;In case you're wondering, there were several reasons we chose not to expose the lock object itself:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;We wanted to be able to change the lock implementation at any time. This would let us switch back to ReaderWriterLockSlim at some point in the future. &lt;/LI&gt;
&lt;LI&gt;It seemed simpler for users to have a limited API surface. Less is More. &lt;/LI&gt;
&lt;LI&gt;It encourages users to use the dispose pattern with the lock they get, thus ensuring that the lock is released even if an exception is thrown and not caught while the lock is being held. &lt;/LI&gt;&lt;/OL&gt;
&lt;H1&gt;Why you should care&lt;/H1&gt;
&lt;P&gt;There are two takeaways I hope I provided in this article:&lt;/P&gt;
&lt;P&gt;The first takeaway is that if you're implementing a thread-safe collection you have some food for thought. I hope the food was easy to digest!&lt;/P&gt;
&lt;P&gt;The second takeaway is that if you're directly accessing the RouteCollection in an ASP.NET application, make sure you take the lock first! Taking the lock is easy with the dispose pattern:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Lucida Console"&gt;RouteCollection routes = RouteTable.Routes; &lt;BR&gt;using (routes.GetReadLock()) { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (RouteBase route in routes) { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Do something interesting here and be guaranteed that no one is modifying the collection &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;} &lt;BR&gt;// The lock is now released since we exited the "using" statement.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Who would have thought that a simple collection of routes would turn out to be so much fun? Did you ever start coding something that seemed simple and ended up writing a long blog post about it?&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6050563" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/aspnetmvc/default.aspx">aspnetmvc</category></item></channel></rss>
