<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.haacked.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.haacked.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" version="2.0">
    <channel>
        <title>you've been HAACKED</title>
        <link>http://haacked.com/Default.aspx</link>
        <description>...and you like it.</description>
        <language>en-US</language>
        <copyright>Haacked</copyright>
        <managingEditor>haacked@gmail.com</managingEditor>
        <generator>Subtext Version 1.9.5.177</generator>
        <image>
            <title>you've been HAACKED</title>
            <url>http://haacked.com/images/RSS2Image.gif</url>
            <link>http://haacked.com/Default.aspx</link>
            <width>77</width>
            <height>60</height>
        </image>
        <geo:lat>34.03056</geo:lat><geo:long>-118.398043</geo:long><creativeCommons:license>http://creativecommons.org/licenses/by-sa/2.5/</creativeCommons:license><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.haacked.com/haacked" type="application/rss+xml" /><feedburner:emailServiceId xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">527603</feedburner:emailServiceId><feedburner:feedburnerHostname xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://www.feedburner.com</feedburner:feedburnerHostname><item>
            <title>DotNetRocks Part Deux</title>
            <category>ASP.NET</category>
            <category>ASP.NET MVC</category>
            <category>Personal</category>
            <link>http://haacked.com/archive/2008/05/06/dotnetrocks-part-deux.aspx</link>
            <description>&lt;p&gt;I did another interview with those wild and crazy guys, &lt;a title="Carl" rel="friend met" href="http://www.intellectualhedonism.com/"&gt;Carl&lt;/a&gt; and &lt;a title="Richard Campbell" rel="friend met" href="http://www.campbellassociates.ca/blog/default.aspx"&gt;Richard&lt;/a&gt;. My first time (show 261) being on .NET Rocks was &lt;a title="Phil on .NET Rocks" href="http://www.dotnetrocks.com/default.aspx?showNum=261"&gt;back in August of 2007&lt;/a&gt; when I talked about Subtext, Open Source, and my blog.&lt;/p&gt;
&lt;p&gt;&lt;a title="This time" href="http://www.dotnetrocks.com/default.aspx?showNum=339"&gt;This time&lt;/a&gt; (show 339), the interview focused on my experiences with working at Microsoft and the work I do on the ASP.NET MVC project. Notice that my profile pic hasn’t changed at all. I should do something about that.&lt;/p&gt;
&lt;p&gt;I haven’t listened to it yet as I hate hearing myself talk. Even worse is seeing &lt;a title="What will it take to RTM MVC?" href="http://weblogs.asp.net/craigshoemaker/archive/2008/05/01/what-s-it-gonna-take-to-get-asp-net-mvc-to-rtm.aspx"&gt;myself on video&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In any case, if you are interested, take a listen to the latest &lt;a title="Me on .NET Rocks" href="http://www.dotnetrocks.com/default.aspx?showNum=339"&gt;&lt;strong&gt;.NET Rocks show&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Oh, and I was also a guest &lt;a title="Hanselminutes" href="http://www.hanselminutes.com/default.aspx?showID=129"&gt;on Hanselminutes recently&lt;/a&gt;. That talk was recorded at ALT.NET Open Spaces in Seattle. It’s only a coincidence that these two interviews came out a week apart. They were recorded more than a week apart. Honestly, I’m not a microphone whore. I’m more of a camera whore. ;)&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:593fb061-1373-471a-8b26-d5c59acce349"&gt;Technorati Tags: &lt;a rel="tag" href="http://technorati.com/tags/dotnetrocks"&gt;dotnetrocks&lt;/a&gt;&lt;/div&gt;&lt;img src="http://haacked.com/aggbug/18483.aspx" width="1" height="1" /&gt;
&lt;p&gt;&lt;a href="http://feeds.haacked.com/~a/haacked?a=WBX3DJ"&gt;&lt;img src="http://feeds.haacked.com/~a/haacked?i=WBX3DJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.haacked.com/~f/haacked?a=3SdJah"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=3SdJah" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=kW7AMh"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=kW7AMh" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=R5UaJH"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=R5UaJH" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>Haacked</dc:creator>
            <guid isPermaLink="false">http://haacked.com/archive/2008/05/06/dotnetrocks-part-deux.aspx</guid>
            <pubDate>Tue, 06 May 2008 20:09:54 GMT</pubDate>
            <wfw:comment>http://haacked.com/comments/18483.aspx</wfw:comment>
            <comments>http://haacked.com/archive/2008/05/06/dotnetrocks-part-deux.aspx#feedback</comments>
            <slash:comments>4</slash:comments>
            <wfw:commentRss>http://haacked.com/comments/commentRss/18483.aspx</wfw:commentRss>
        </item>
        <item>
            <title>RouteEvaluator For Unit Testing Routes</title>
            <category>ASP.NET</category>
            <category>ASP.NET MVC</category>
            <link>http://haacked.com/archive/2008/05/05/routeevaluator-for-unit-testing-routes.aspx</link>
            <description>&lt;p&gt;A while back I wrote a &lt;a title="URL Routing Debugger" href="http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx"&gt;routing debugger&lt;/a&gt; which is useful for testing your routes and seeing which routes would match a given URL. &lt;a title="Rob Conery" rel="friend met co-worker" href="http://blog.wekeroad.com/"&gt;Rob&lt;/a&gt; suggested we have something like this for unit tests, so I whipped something simple up.&lt;/p&gt;
&lt;p&gt;This is a class that allows you to test multiple different URLs quickly. You simply create the &lt;code&gt;RouteEvaluator&lt;/code&gt; giving it a collection of routes and then &lt;code&gt;GetMatches&lt;/code&gt; which returns a &lt;code&gt;List&amp;lt;RouteData&amp;gt;&lt;/code&gt; containing a &lt;code&gt;RouteData&lt;/code&gt; instance for every route that matches, not just the first one.&lt;/p&gt;
&lt;p&gt;Here's a sample of usage.&lt;/p&gt;
&lt;div class="dropshadow code"&gt;
&lt;div class="innerbox"&gt;
&lt;pre class="csharpcode"&gt;[Test]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CanMatchUsingRouteEvaluator()
{
  var routes = &lt;span class="kwrd"&gt;new&lt;/span&gt; RouteCollection();
  GlobalApplication.RegisterRoutes(routes);

  var evaluator = &lt;span class="kwrd"&gt;new&lt;/span&gt; RouteEvaluator(routes);
  var matchingRouteData = evaluator.GetMatches(&lt;span class="str"&gt;"~/foo/bar"&lt;/span&gt;);
  Assert.IsTrue(matchingRouteData.Count &amp;gt; 0);
  matchingRouteData = evaluator.GetMatches(&lt;span class="str"&gt;"~/foo/bar/baz/billy"&lt;/span&gt;);
  Assert.AreEqual(0, matchingRouteData.Count);
}&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p class="clear"&gt;And here’s the code. Note that my implementation relies on &lt;a title="Moq on Google Code" href="http://code.google.com/p/moq/"&gt;Moq&lt;/a&gt;, but you could easily implement it without using Moq if you wanted to.&lt;/p&gt;
&lt;div class="dropshadow code"&gt;
&lt;div class="innerbox"&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; RouteEvaluator
{
  RouteCollection routes;
    
  &lt;span class="kwrd"&gt;public&lt;/span&gt; RouteEvaluator(RouteCollection routes)
  {
    &lt;span class="kwrd"&gt;this&lt;/span&gt;.routes = routes;
  }

  &lt;span class="kwrd"&gt;public&lt;/span&gt; IList&amp;lt;RouteData&amp;gt; GetMatches(&lt;span class="kwrd"&gt;string&lt;/span&gt; virtualPath)
  {
    &lt;span class="kwrd"&gt;return&lt;/span&gt; GetMatches(virtualPath, &lt;span class="str"&gt;"GET"&lt;/span&gt;);
  }

  &lt;span class="kwrd"&gt;public&lt;/span&gt; IList&amp;lt;RouteData&amp;gt; GetMatches(&lt;span class="kwrd"&gt;string&lt;/span&gt; virtualPath, &lt;span class="kwrd"&gt;string&lt;/span&gt; httpMethod)
  {
    List&amp;lt;RouteData&amp;gt; matchingRouteData = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;RouteData&amp;gt;();

    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var route &lt;span class="kwrd"&gt;in&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.routes)
    {
      var context = &lt;span class="kwrd"&gt;new&lt;/span&gt; Mock&amp;lt;HttpContextBase&amp;gt;();
      var request = &lt;span class="kwrd"&gt;new&lt;/span&gt; Mock&amp;lt;HttpRequestBase&amp;gt;();

      context.Expect(ctx =&amp;gt; ctx.Request).Returns(request.Object);
      request.Expect(req =&amp;gt; req.PathInfo).Returns(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty);
      request.Expect(req =&amp;gt; 
req.AppRelativeCurrentExecutionFilePath).Returns(virtualPath);
      &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(httpMethod))
      {
        request.Expect(req =&amp;gt; req.HttpMethod).Returns(httpMethod);
      }

      RouteData routeData = &lt;span class="kwrd"&gt;this&lt;/span&gt;.routes.GetRouteData(context.Object);
      &lt;span class="kwrd"&gt;if&lt;/span&gt; (routeData != &lt;span class="kwrd"&gt;null&lt;/span&gt;) {
        matchingRouteData.Add(routeData);
      }
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; matchingRouteData;
  }
}&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p class="clear"&gt;Let me know if this ends up being useful to you.&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:d9dca632-2f05-4fde-b3c3-67820f639b0e" style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;Technorati Tags: &lt;a rel="tag" href="http://technorati.com/tags/aspnetmvc"&gt;aspnetmvc&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/ASP.NET"&gt;ASP.NET&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/routing"&gt;routing&lt;/a&gt;&lt;/div&gt;&lt;img src="http://haacked.com/aggbug/18482.aspx" width="1" height="1" /&gt;
&lt;p&gt;&lt;a href="http://feeds.haacked.com/~a/haacked?a=smA6wG"&gt;&lt;img src="http://feeds.haacked.com/~a/haacked?i=smA6wG" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.haacked.com/~f/haacked?a=0EiCbh"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=0EiCbh" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=l9E4ih"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=l9E4ih" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=CkYktH"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=CkYktH" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>Haacked</dc:creator>
            <guid isPermaLink="false">http://haacked.com/archive/2008/05/05/routeevaluator-for-unit-testing-routes.aspx</guid>
            <pubDate>Mon, 05 May 2008 23:32:15 GMT</pubDate>
            <wfw:comment>http://haacked.com/comments/18482.aspx</wfw:comment>
            <comments>http://haacked.com/archive/2008/05/05/routeevaluator-for-unit-testing-routes.aspx#feedback</comments>
            <slash:comments>9</slash:comments>
            <wfw:commentRss>http://haacked.com/comments/commentRss/18482.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Code Based Repeater for ASP.NET MVC</title>
            <category>ASP.NET</category>
            <category>ASP.NET MVC</category>
            <category>Software Development</category>
            <link>http://haacked.com/archive/2008/05/03/code-based-repeater-for-asp.net-mvc.aspx</link>
            <description>&lt;p&gt;Not long ago, my compadre &lt;a title="Scott Hanselman's Blog" href="http://www.hanselman.com/blog/" rel="friend met co-worker"&gt;Scott Hanselman&lt;/a&gt; related the &lt;a title="ASP.NET MVC Webforms unplugged" href="http://www.hanselman.com/blog/ASPNETMVCWebFormsUnplugged.aspx"&gt;following story&lt;/a&gt;...&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;In a recent MVC design meeting someone said something like "we’ll need a Repeater control" and a powerful and very technical boss-type said: &lt;/p&gt;    &lt;p&gt;"We’ve got a repeater control, it’s called a foreach loop."&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I beg to differ. I think we can do better than a &lt;code&gt;foreach&lt;/code&gt; loop. A &lt;code&gt;foreach &lt;/code&gt;loop doesn’t help you handle alternating items, for example. My response to this story is, “The &lt;code&gt;foreach&lt;/code&gt; loop is not our repeater control. Our repeater control is an iterating extension method with lambdas!”. Because who doesn’t &lt;a title="Rob Conery's Personal Lambda crusade" href="http://blog.wekeroad.com/2008/03/17/my-personal-lambda-crusade/"&gt;love lambdas&lt;/a&gt;?&lt;/p&gt;  &lt;p&gt;Not many people realize that within an ASPX template, it’s possible to pass sections of the template into a lambda. Here, let me show you the end result of using my &lt;code&gt;Repeater&amp;lt;T&amp;gt;&lt;/code&gt; helper method. It’s an extension method of the &lt;code&gt;HtmlHelper&lt;/code&gt; class in ASP.NET MVC.&lt;/p&gt;  &lt;div class="dropshadow code"&gt;   &lt;div class="innerbox"&gt;     &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;table&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt; Html.Repeater&amp;lt;Hobby&amp;gt;(&lt;span class="str"&gt;"Hobbies"&lt;/span&gt;, hobby =&amp;gt; { &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="row"&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;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;= hobby.Title &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&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;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt; }, hobbyAlt =&amp;gt; { &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="alt-row"&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;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;= hobbyAlt.Title &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&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;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt; }); &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;table&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p class="clear"&gt;This renders a table with alternating rows. The Repeater method takes in two lambdas, one which represents the item template, and another that represents the alternating item template.&lt;/p&gt;

&lt;p&gt;This particular overload of the Repeater method takes in a key to the &lt;code&gt;ViewData&lt;/code&gt; dictionary and casts that to an &lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt;. In this case, it tries to cast &lt;code&gt;ViewData["Hobbies"]&lt;/code&gt; to &lt;code&gt;IEnumerable&amp;lt;Hobby&amp;gt;&lt;/code&gt;. I’ve included overloads that allow you to explicitly specify the items to repeat over.&lt;/p&gt;

&lt;p&gt;This isn't very remarkable when you think a bout it. What the above template code translates to is the following (roughly speaking)...&lt;/p&gt;

&lt;div class="dropshadow code"&gt;
  &lt;div class="innerbox"&gt;
    &lt;pre class="csharpcode"&gt;Response.Write(&lt;span class="str"&gt;"&amp;lt;table&amp;gt;"&lt;/span&gt;);

Html.Repeater&amp;lt;Hobby&amp;gt;(&lt;span class="str"&gt;"Hobbies"&lt;/span&gt;, hobby =&amp;gt; {
    Response.Write(&lt;span class="str"&gt;"  &amp;lt;tr class=\"row\"&amp;gt;"&lt;/span&gt;);
    Response.Write(&lt;span class="str"&gt;"    &amp;lt;td&amp;gt;"&lt;/span&gt;);
    Response.Write(hobby.Title);
    Response.Write(&lt;span class="str"&gt;"    &amp;lt;/td&amp;gt;"&lt;/span&gt;);
    Response.Write(&lt;span class="str"&gt;"  &amp;lt;/tr&amp;gt;"&lt;/span&gt;);
  }, hobbyAlt =&amp;gt; { 
    Response.Write(&lt;span class="str"&gt;"  &amp;lt;tr class=\"alt-row\"&amp;gt;"&lt;/span&gt;);
    Response.Write(&lt;span class="str"&gt;"    &amp;lt;td&amp;gt;"&lt;/span&gt;);
    Response.Write(hobbyAlt.Title);
    Response.Write(&lt;span class="str"&gt;"    &amp;lt;/td&amp;gt;"&lt;/span&gt;);
    Response.Write(&lt;span class="str"&gt;"  &amp;lt;/tr&amp;gt;"&lt;/span&gt;);
  });

Response.Write(&lt;span class="str"&gt;"&amp;lt;/table&amp;gt;"&lt;/span&gt;);&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p class="clear"&gt;The code for the &lt;code&gt;Repeater&lt;/code&gt; method is simple, short, and sweet.&lt;/p&gt;

&lt;div class="dropshadow code"&gt;
  &lt;div class="innerbox"&gt;
    &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Repeater&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt; HtmlHelper html
  , IEnumerable&amp;lt;T&amp;gt; items
  , Action&amp;lt;T&amp;gt; render
  , Action&amp;lt;T&amp;gt; renderAlt)
{
  &lt;span class="kwrd"&gt;if&lt;/span&gt; (items == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
    &lt;span class="kwrd"&gt;return&lt;/span&gt;;

  &lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0;
  items.ForEach(item =&amp;gt; {
    &lt;span class="kwrd"&gt;if&lt;/span&gt;(i++ % 2 == 0 ) 
      render(item);
    &lt;span class="kwrd"&gt;else&lt;/span&gt;
      renderAlt(item); 
  });
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Repeater&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt; HtmlHelper html
  , Action&amp;lt;T&amp;gt; render
  , Action&amp;lt;T&amp;gt; renderAlt)
{
  var items = html.ViewContext.ViewData &lt;span class="kwrd"&gt;as&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt;;
  html.Repeater(items, render, renderAlt);
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Repeater&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt; HtmlHelper html
  , &lt;span class="kwrd"&gt;string&lt;/span&gt; viewDataKey
  , Action&amp;lt;T&amp;gt; render
  , Action&amp;lt;T&amp;gt; renderAlt)
{
  var items = html.ViewContext.ViewData &lt;span class="kwrd"&gt;as&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt;;
  var viewData = html.ViewContext.ViewData &lt;span class="kwrd"&gt;as&lt;/span&gt; IDictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;,&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;;
  &lt;span class="kwrd"&gt;if&lt;/span&gt; (viewData != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
  {
    items = viewData[viewDataKey] &lt;span class="kwrd"&gt;as&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt;;
  }
  &lt;span class="kwrd"&gt;else&lt;/span&gt;
  {
    items = &lt;span class="kwrd"&gt;new&lt;/span&gt; ViewData(viewData)[viewDataKey] &lt;span class="kwrd"&gt;as&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt;;
  }
  html.Repeater(items, render, renderAlt);
}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p class="clear"&gt;Some of the &lt;code&gt;ViewData&lt;/code&gt; machinations you see here is due to the fact that &lt;code&gt;ViewData&lt;/code&gt; might be a dictionary, or it might be an unknown type, in which case we perform the equivalent of a &lt;code&gt;DataBinder.Eval&lt;/code&gt; call on it using the supplied view data key.&lt;/p&gt;

&lt;p&gt;It turns out that the regular &lt;code&gt;&amp;lt;asp:Repeater /&amp;gt;&lt;/code&gt; control works just fine with ASP.NET MVC, so there’s no need for such an ugly method call. I just thought it was fun to try out and provides an alternative approach that doesn’t require databinding.&lt;/p&gt;

&lt;p class="update"&gt;UPDATE: I wanted to end this post here, but my compadre and others took exception to my implementation. Read on to see my improvement...&lt;/p&gt;

&lt;p&gt;As astute readers of my blog noted, the example I used forces me to repeat a lot of template code in the alternative item case. The point of this post was on how to mimic the repeater, not in building a better one. Maybe you &lt;em&gt;want&lt;/em&gt; to have a completely different layout in the alternate item case. I was going to build a another one that relied only on one template, but I figured I would leave that to the reader. But noooo, you had to complain. ;)&lt;/p&gt;

&lt;p&gt;So the following is an example of a repeater method that follows the most common pattern in an alternating repeater. In this common case, you generally want to simply change the CSS class and nothing else. So with these overloads, you specify two CSS classes - one for items and one for alternating items. Here’s an example of usage.&lt;/p&gt;

&lt;div class="dropshadow code"&gt;
  &lt;div class="innerbox"&gt;
    &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;table&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt; Html.Repeater&amp;lt;Hobby&amp;gt;(&lt;span class="str"&gt;"Hobbies"&lt;/span&gt;, &lt;span class="str"&gt;"row"&lt;/span&gt;, &lt;span class="str"&gt;"row-alt"&lt;/span&gt;, (hobby, css) =&amp;gt; { &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="&amp;lt;%= css %&amp;gt;"&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;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;= hobby.Title&lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&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;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt; }); &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;table&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p class="clear"&gt;And here’s the source for the extra overloads. Note that I refactored the code for getting the enumerable from the &lt;code&gt;ViewData&lt;/code&gt; into its own method.&lt;/p&gt;

&lt;div class="dropshadow code"&gt;
  &lt;div class="innerbox"&gt;
    &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Repeater&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt; HtmlHelper html
  , IEnumerable&amp;lt;T&amp;gt; items
  , &lt;span class="kwrd"&gt;string&lt;/span&gt; className
  , &lt;span class="kwrd"&gt;string&lt;/span&gt; classNameAlt
  , Action&amp;lt;T, &lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; render)
{
  &lt;span class="kwrd"&gt;if&lt;/span&gt; (items == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
    &lt;span class="kwrd"&gt;return&lt;/span&gt;;

  &lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0;
  items.ForEach(item =&amp;gt;
  {
    render(item, (i++ % 2 == 0) ? className: classNameAlt
  });
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Repeater&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt; HtmlHelper html
  , &lt;span class="kwrd"&gt;string&lt;/span&gt; viewDataKey
  , &lt;span class="kwrd"&gt;string&lt;/span&gt; cssClass
  , &lt;span class="kwrd"&gt;string&lt;/span&gt; altCssClass
  , Action&amp;lt;T, &lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; render)
{
  var items = GetViewDataAsEnumerable&amp;lt;T&amp;gt;(html, viewDataKey);

  &lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0;
  items.ForEach(item =&amp;gt;
  {
    render(item, (i++ % 2 == 0) ? cssClass : altCssClass);
  });
}

&lt;span class="kwrd"&gt;static&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; GetViewDataAsEnumerable&amp;lt;T&amp;gt;(HtmlHelper html, &lt;span class="kwrd"&gt;string&lt;/span&gt; viewDataKey)
{
  var items = html.ViewContext.ViewData &lt;span class="kwrd"&gt;as&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt;;
  var viewData = html.ViewContext.ViewData &lt;span class="kwrd"&gt;as&lt;/span&gt; IDictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;;
  &lt;span class="kwrd"&gt;if&lt;/span&gt; (viewData != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
  {
    items = viewData[viewDataKey] &lt;span class="kwrd"&gt;as&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt;;
  }
  &lt;span class="kwrd"&gt;else&lt;/span&gt;
  {
    items = &lt;span class="kwrd"&gt;new&lt;/span&gt; ViewData(viewData)[viewDataKey] 
      &lt;span class="kwrd"&gt;as&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt;;
  }
  &lt;span class="kwrd"&gt;return&lt;/span&gt; items;
}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p class="clear"&gt;Hopefully that gets some people off my back now. ;)&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:ba1525e1-a3c3-4d0c-a72b-291270c74629" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/aspnetmvc" rel="tag"&gt;aspnetmvc&lt;/a&gt;,&lt;a href="http://technorati.com/tags/asp.net" rel="tag"&gt;asp.net&lt;/a&gt;&lt;/div&gt;&lt;img src="http://haacked.com/aggbug/18481.aspx" width="1" height="1" /&gt;
&lt;p&gt;&lt;a href="http://feeds.haacked.com/~a/haacked?a=2DhFGU"&gt;&lt;img src="http://feeds.haacked.com/~a/haacked?i=2DhFGU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.haacked.com/~f/haacked?a=sSgB3h"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=sSgB3h" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=a17eKh"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=a17eKh" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=gMx7CH"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=gMx7CH" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>Haacked</dc:creator>
            <guid isPermaLink="false">http://haacked.com/archive/2008/05/03/code-based-repeater-for-asp.net-mvc.aspx</guid>
            <pubDate>Sun, 04 May 2008 03:55:13 GMT</pubDate>
            <wfw:comment>http://haacked.com/comments/18481.aspx</wfw:comment>
            <comments>http://haacked.com/archive/2008/05/03/code-based-repeater-for-asp.net-mvc.aspx#feedback</comments>
            <slash:comments>42</slash:comments>
            <wfw:commentRss>http://haacked.com/comments/commentRss/18481.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Anatomy of a "Small" Software Design Change</title>
            <category>ASP.NET MVC</category>
            <category>Software Development</category>
            <link>http://haacked.com/archive/2008/04/24/anatomy-of-a-design-change.aspx</link>
            <description>&lt;p&gt;File this one away for the next time your boss comes in and asks,&lt;a href="http://haacked.com/images/haacked_com/WindowsLiveWriter/AnatomyofaDesignChange_7EB2/lumberg%5B1%5D_2.jpg"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="179" alt="lumberg[1]" width="179" align="right" border="0" src="http://haacked.com/images/haacked_com/WindowsLiveWriter/AnatomyofaDesignChange_7EB2/lumberg%5B1%5D_thumb.jpg" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;font style="BACKGROUND-COLOR: #ffffff" face="Trebuchet MS" size="3"&gt;Yeaaah, I’m going to need you to make that little change to the code. It’ll only take you a couple hours, right?&lt;/font&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Software has this deceptive property in which some changes that seem quite big and challenging to the layman end up being quite trivial, while other changes that seem quite trivial, end up requiring a lot of thought, care, and work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Often, little changes add up to a lot.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I’m going to walk through a change we made that seemed like a no-brainer but ended up having a lot of interesting consequences that were invisible to most onlookers.&lt;/p&gt;
&lt;h2&gt;The Setup&lt;/h2&gt;
&lt;p&gt;I’ll provide just enough context to understand the change. The project I work on, ASP.NET MVC allows you to call methods on a class via the URL.&lt;/p&gt;
&lt;p&gt;For example, a request for &lt;strong&gt;/product/list&lt;/strong&gt; might call a method on a class named &lt;code&gt;ProductController&lt;/code&gt; with a method named &lt;code&gt;List&lt;/code&gt;. Likewise a request for &lt;strong&gt;/product/index&lt;/strong&gt; would call the method named &lt;code&gt;Index&lt;/code&gt;. We call these “web callable” methods, &lt;em&gt;Actions&lt;/em&gt;. Nothing new here.&lt;/p&gt;
&lt;p&gt;There were a couple rules in place for this to happen:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;The controller class must inherit from the Controller class. &lt;/li&gt;
    &lt;li&gt;The action method must be annotated with the &lt;code&gt;[ControllerAction]&lt;/code&gt; attribute applied to it. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We received a lot of feedback on the requirement for having that attribute. There were a lot of good reasons to have it there, but there were also a lot of good reasons to remove it.&lt;/p&gt;
&lt;p&gt;Removing that requirement should be pretty simple, right? Just find the line of code that checks for the existence of the attribute and change it to not check at all.&lt;/p&gt;
&lt;h2&gt;The Consequences&lt;/h2&gt;
&lt;p&gt;Ahhh, if only it were that easy my friend. There were many consequences to that change. The solutions to these consequences were mostly easy. The hard part was making sure we caught all of them. After all, you don’t know what you don’t know.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Base Classes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So we removed the check for the attribute and the first thing we noticed is “&lt;em&gt;Hey! Now I can make a request for &lt;strong&gt;/product/gethashcode&lt;/strong&gt;, Cool!&lt;/em&gt;”&lt;/p&gt;
&lt;p&gt;Not so cool. Since every object ultimately inherits from &lt;code&gt;System.Object&lt;/code&gt;, every object has several public methods: &lt;code&gt;ToString()&lt;/code&gt;, &lt;code&gt;GetHashCode()&lt;/code&gt;, &lt;code&gt;GetType()&lt;/code&gt;, and &lt;code&gt;Equals()&lt;/code&gt;, and so on... In fact, our Controller class itself has a few public methods.&lt;/p&gt;
&lt;p&gt;The solution here is conceptually easy, we only look at public methods on classes that derive from our Controller class. In other words, we ignore methods on &lt;code&gt;Controller&lt;/code&gt; and on &lt;code&gt;Object&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Controller Inheritance&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;One of the rationales for removing the attribute is that in general, there isn’t much of a reason to have a public method on a controller class that isn’t available from the web. But that isn’t always true. Let’s look at one situation. Suppose you have the following abstract base controller.&lt;/p&gt;
&lt;div class="dropshadow code"&gt;
&lt;div class="innerbox"&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CoolController : Controller
{
  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Smokes() {...}

  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Gambles() {...}

  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Drinks() {...}
}&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p class="clear"&gt;It is soooo cool!&lt;/p&gt;
&lt;p class="clear"&gt;You might want to write a controller that uses the &lt;code&gt;CoolController&lt;/code&gt; as its base class rather than &lt;code&gt;Controller&lt;/code&gt; because &lt;code&gt;CoolController&lt;/code&gt; does some cool stuff. &lt;/p&gt;
&lt;p class="clear"&gt;However, you don’t think smoking is cool at all. Too bad, &lt;code&gt;Smokes()&lt;/code&gt; is a public method and thus an action, so it is callable. At this point, we realized we need a &lt;code&gt;[NonAction]&lt;/code&gt; attribute we can apply to an action to say that even though it is public, it is not an action.&lt;/p&gt;
&lt;p class="clear"&gt;With this attribute, I can do this:&lt;/p&gt;
&lt;div class="dropshadow code"&gt;
&lt;div class="innerbox"&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyReallyCoolController : CoolController
{
  [NonAction]
  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Smokes()
  {
    throws &lt;span class="kwrd"&gt;new&lt;/span&gt; NotImplementedException();
  }
}&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p class="clear"&gt;Now &lt;code&gt;MyReallyCoolController&lt;/code&gt; doesn’t smoke, which is really cool.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interfaces&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Another issue that came up is interfaces. Suppose I implement an interface with public methods.  Should those methods by default be callable? A good example is &lt;code&gt;IDisposable&lt;/code&gt;. If I implement that interface, suddenly I can call Dispose() via a request for &lt;strong&gt;/product/dispose&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Since we already implemented the &lt;code&gt;[NonAction]&lt;/code&gt; attribute, we decided that yes, they are callable if you implicitly implement them because they are public methods on your class and you have a means to make them not callable.&lt;/p&gt;
&lt;p&gt;We also decided that if you explicitly implement an interface, those methods would not be callable. That would be one way to implement an interface without making every method an action and would not require you to annotate every interface method.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Special Methods&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Keep in mind that in C# and VB.NET, property setters and getters are nothing more than syntactic sugar. When compiled to IL, they end up being methods named &lt;code&gt;&lt;strong&gt;get_&lt;em&gt;PropertyName()&lt;/em&gt;&lt;/strong&gt;&lt;/code&gt; and &lt;code&gt;&lt;strong&gt;set_&lt;em&gt;PropertyName()&lt;/em&gt;&lt;/strong&gt;&lt;/code&gt;. The constructor is implemented as a method named &lt;code&gt;&lt;strong&gt;.ctor()&lt;/strong&gt;&lt;/code&gt;. When you have an indexer on a class, that gets compiled to &lt;code&gt;&lt;strong&gt;get_Item()&lt;/strong&gt;&lt;/code&gt;. &lt;/p&gt;
&lt;p&gt;I’m not saying it was hard to deal with this, but we did have to remember to consider this. We needed to get a list of methods on the controller that are methods in the “typical” sense and not in some funky compiler-generated or specially named sense.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge Cases&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now we started to get into various edge cases. For example, what if you inherit a base controller class, but use the &lt;code&gt;new&lt;/code&gt; keyword on your action of the same name as an action on the base class? What if you have multiple overloads of the same method? And so on. I won’t bore you with all the details. The point is, it was interesting to see all these consequences bubble up for such a simple change.&lt;/p&gt;
&lt;h2&gt;Is This Really Going To Help You With Your Boss?&lt;/h2&gt;
&lt;p&gt;Who am I kidding here? Of course not. :) Well..., maybe. &lt;/p&gt;
&lt;p&gt;If your boss is technical, it may be a nice reminder that software is often like an iceberg. It is easy to see the 10% of work necessary, but the other 90% of work doesn’t become apparent till you dig deeper. &lt;/p&gt;
&lt;p&gt;If your boss is not technical, we may well be speaking a different language here. I need to find an analogy that a business manager would understand. A situation in their world in which something that seems simple on the surface ends up being a lot of work in actuality. If you have such examples, be a pal and post them in the comments. The goal here is to find common ground and a shared language for describing the realities of software to non-software developers.&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:c6f3b00e-ddac-4d21-bb16-ceaa85b8aef8" style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;Technorati Tags: &lt;a rel="tag" href="http://technorati.com/tags/Software"&gt;Software&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/Software%20Design"&gt;Software Design&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/ASP.NET%20MVC"&gt;ASP.NET MVC&lt;/a&gt;&lt;/div&gt;&lt;img src="http://haacked.com/aggbug/18480.aspx" width="1" height="1" /&gt;
&lt;p&gt;&lt;a href="http://feeds.haacked.com/~a/haacked?a=fmcWOz"&gt;&lt;img src="http://feeds.haacked.com/~a/haacked?i=fmcWOz" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.haacked.com/~f/haacked?a=2EzKMPg"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=2EzKMPg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=AkM6BUg"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=AkM6BUg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=JiUv0sG"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=JiUv0sG" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>Haacked</dc:creator>
            <guid isPermaLink="false">http://haacked.com/archive/2008/04/24/anatomy-of-a-design-change.aspx</guid>
            <pubDate>Fri, 25 Apr 2008 00:44:49 GMT</pubDate>
            <wfw:comment>http://haacked.com/comments/18480.aspx</wfw:comment>
            <comments>http://haacked.com/archive/2008/04/24/anatomy-of-a-design-change.aspx#feedback</comments>
            <slash:comments>35</slash:comments>
            <wfw:commentRss>http://haacked.com/comments/commentRss/18480.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Defining ASP.NET MVC Routes and Views in IronRuby</title>
            <category>ASP.NET</category>
            <category>ASP.NET MVC</category>
            <category>Software Development</category>
            <link>http://haacked.com/archive/2008/04/22/defining-asp.net-mvc-routes-and-views-in-ironruby.aspx</link>
            <description>&lt;p&gt;In a &lt;a title="Dynamic Language DSL vs XML Config" href="http://haacked.com/archive/2008/04/18/dynamic-language-dsl-vs-xml-configuration.aspx"&gt;recent post&lt;/a&gt; I expressed a few thoughts on using a DSL instead of an XML config file. I followed that up with a technical look at &lt;a title="Monkey Patching" href="http://haacked.com/archive/2008/04/18/monkey-patching-clr-objects.aspx"&gt;monkey patching CLR objects using IronRuby&lt;/a&gt;, which explores a tiny bit of interop.&lt;/p&gt;  &lt;p&gt;These posts were precursors to this post in which I apply these ideas to an implementation that allows me to define ASP.NET MVC Routes using IronRuby. Also included in this download is an incomplete implementation of an IronRuby view engine. I haven't yet implemented layouts.&lt;/p&gt;  &lt;p&gt;&lt;a title="IronRubyMvcDemo.zip" href="http://haacked.com/code/IronRubyMvcDemo.zip"&gt;&lt;strong&gt;IronRubyMvcDemo.zip Download (4.93 MB)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;This implementation works with the latest &lt;a title="CodePlex release" href="http://www.codeplex.com/aspnet/Release/ProjectReleases.aspx?ReleaseId=12640"&gt;CodePlex drop of MVC&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;To use routes written in Ruby, reference the IronRubyMvcLibrary from your MVC Web Application and import the &lt;code&gt;IronRubyMvcLibrary.Routing&lt;/code&gt; namespace into your &lt;code&gt;Global.asax&lt;/code&gt; code behind file. From there, you can just call an extension method on &lt;code&gt;RouteCollection&lt;/code&gt; like so...&lt;/p&gt;  &lt;div class="dropshadow code"&gt;   &lt;div class="innerbox"&gt;     &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; GlobalApplication : System.Web.HttpApplication
{
  &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Start()
  {
    RouteTable.Routes.LoadFromRuby();
  }
}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p class="clear"&gt;This will look for a &lt;code&gt;&lt;strong&gt;Routes.rb&lt;/strong&gt;&lt;/code&gt; file within the webroot and use that file to load routes. Here's a look at mine:&lt;/p&gt;

&lt;div class="dropshadow code"&gt;
  &lt;div class="innerbox"&gt;
    &lt;pre class="csharpcode"&gt;$routes.map &lt;span class="str"&gt;"products/{action}/{id}"&lt;/span&gt;
  , {:controller =&amp;gt; &lt;span class="str"&gt;'products'&lt;/span&gt;, :action =&amp;gt; &lt;span class="str"&gt;'categories'&lt;/span&gt;, :id =&amp;gt; &lt;span class="str"&gt;''&lt;/span&gt;}
$routes.map &lt;span class="str"&gt;"{controller}/{action}/{id}"&lt;/span&gt;, {:id =&amp;gt; &lt;span class="str"&gt;''&lt;/span&gt;}
$routes.map &lt;span class="str"&gt;"{controller}"&lt;/span&gt;, {:action =&amp;gt; &lt;span class="str"&gt;'index'&lt;/span&gt;}, {:controller =&amp;gt; &lt;span class="str"&gt;'[^\.]*'&lt;/span&gt;}
$routes.map &lt;span class="str"&gt;"default.aspx"&lt;/span&gt;, {:controller =&amp;gt; &lt;span class="str"&gt;'home'&lt;/span&gt;, :action =&amp;gt; &lt;span class="str"&gt;'index'&lt;/span&gt;}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p class="clear"&gt;That’s it. No other cruft in there. I tried experimenting with lining up each segment using tabs so it looks like an actual table of data, rather than simply code definitions.&lt;/p&gt;

&lt;p&gt;Also included in this download is a sample web app that makes use of the &lt;code&gt;IronRubyViewEngine&lt;/code&gt;. You can see how I applied Monkey Patching to make referencing view data cleaner. Within an IronRuby view, you can access the view data via a global variable, $model. The nice part is, whether you pass strongly typed data or not to the view, you can always reference view data via &lt;code&gt;$model.property_name&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the case where the view data is a view data dictionary, this will perform a dictionary lookup using the property name as the key.&lt;/p&gt;

&lt;p&gt;Be sure to check out the unit tests which provide over 95% code coverage of my code if you want to understand this code and improve on it. Next stop, Controllers in IronRuby...&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:e23b6f8e-1195-4679-b6ab-e2c67ded8481" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/ironruby" rel="tag"&gt;ironruby&lt;/a&gt;,&lt;a href="http://technorati.com/tags/ruby" rel="tag"&gt;ruby&lt;/a&gt;,&lt;a href="http://technorati.com/tags/aspnetmvc" rel="tag"&gt;aspnetmvc&lt;/a&gt;,&lt;a href="http://technorati.com/tags/aspnet" rel="tag"&gt;aspnet&lt;/a&gt;,&lt;a href="http://technorati.com/tags/dsl" rel="tag"&gt;dsl&lt;/a&gt;&lt;/div&gt;&lt;img src="http://haacked.com/aggbug/18479.aspx" width="1" height="1" /&gt;
&lt;p&gt;&lt;a href="http://feeds.haacked.com/~a/haacked?a=f2Xur9"&gt;&lt;img src="http://feeds.haacked.com/~a/haacked?i=f2Xur9" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.haacked.com/~f/haacked?a=PNHJlLg"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=PNHJlLg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=JdK3HNg"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=JdK3HNg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=KECcAkG"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=KECcAkG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=XuGfTJG"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=XuGfTJG" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>Haacked</dc:creator>
            <guid isPermaLink="false">http://haacked.com/archive/2008/04/22/defining-asp.net-mvc-routes-and-views-in-ironruby.aspx</guid>
            <pubDate>Tue, 22 Apr 2008 15:48:11 GMT</pubDate>
            <wfw:comment>http://haacked.com/comments/18479.aspx</wfw:comment>
            <comments>http://haacked.com/archive/2008/04/22/defining-asp.net-mvc-routes-and-views-in-ironruby.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://haacked.com/comments/commentRss/18479.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Monkey Patching CLR Objects</title>
            <category>Software Development</category>
            <link>http://haacked.com/archive/2008/04/18/monkey-patching-clr-objects.aspx</link>
            <description>&lt;p&gt;In &lt;a title="Dynamic Language vs XML" href="http://haacked.com/archive/2008/04/18/dynamic-language-dsl-vs-xml-configuration.aspx"&gt;my last post&lt;/a&gt; I set the stage for this post by discussing some of my personal opinions around integrating a dynamic language into a .NET application. Using a DSL written in a dynamic language, such as IronRuby, to set up configuration for a .NET application is an interesting approach to application configuration.&lt;/p&gt;  &lt;p&gt;With that in mind, I was playing around with some IronRuby interop with the CLR recently. Ruby has this concept called &lt;em&gt;&lt;a title="Monkey Patching on wikipedia" href="http://en.wikipedia.org/wiki/Monkey_patch"&gt;Monkey Patching&lt;/a&gt;&lt;/em&gt;. You can read the definition in the Wikipedia link I provided, but in short, it is a way to modify the behavior of a class or instance of a class at runtime without changing the source of that class or instance. Kind of like extension methods in C#, but more powerful. Let me provide a demonstration.&lt;/p&gt;  &lt;p&gt;I want to pass a C# object instance that happens to have an indexer to a Ruby script via IronRuby. In C#, you can access an indexer property using square brackets like so:&lt;/p&gt;  &lt;div class="dropshadow code"&gt;   &lt;div class="innerbox"&gt;     &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;object&lt;/span&gt; &lt;span class="kwrd"&gt;value&lt;/span&gt; = indexer[&lt;span class="str"&gt;"key"&lt;/span&gt;];&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p class="clear"&gt;Being able to use braces to access this property is merely syntactic sugar by the C# language. Under the hood, this gets compiled to IL as a method named &lt;code&gt;get_Item&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So when passing this object to IronRuby, I need to do the following:&lt;/p&gt;

&lt;div class="dropshadow code"&gt;
  &lt;div class="innerbox"&gt;
    &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;value&lt;/span&gt; = $indexer.get_Item(&lt;span class="str"&gt;"key"&lt;/span&gt;);&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p class="clear"&gt;That’s not soooo bad (ok, maybe it is), but we’re not taking advantage of any of the power of Ruby. So what I did was monkey patch the &lt;code&gt;method_missing&lt;/code&gt; method onto my object and used the method name as the key to the dictionary. This method allows you to handle unknown method calls on an object instance. You can &lt;a title="More Ruby: method_missing" href="http://blog.mauricecodik.com/2005/12/more-ruby-methodmissing.html"&gt;read this post&lt;/a&gt; for a nice brief explanation.&lt;/p&gt;

&lt;p&gt;So this allows me now to access the indexer from within Ruby as if it were a simple property access like so:&lt;/p&gt;

&lt;div class="dropshadow code"&gt;
  &lt;div class="innerbox"&gt;
    &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;value&lt;/span&gt; = $indexerObject.key&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p class="clear"&gt;The code for doing this is the following, based on the &lt;a title="IronRuby in RubyForge" href="http://rubyforge.org/projects/ironruby"&gt;latest IronRuby code in RubyForge&lt;/a&gt;.&lt;/p&gt;

&lt;div class="dropshadow code"&gt;
  &lt;div class="innerbox"&gt;
    &lt;pre class="csharpcode"&gt;ScriptRuntime runtime = IronRuby.CreateRuntime();
ScriptEngine rubyengine = IronRuby.GetEngine(runtime);
RubyExecutionContext ctx = IronRuby.GetExecutionContext(runtime);

ctx.DefineGlobalVariable(&lt;span class="str"&gt;"indexer"&lt;/span&gt;, new Indexer());
&lt;span class="kwrd"&gt;string&lt;/span&gt; requires = 
&lt;span class="str"&gt;@"require 'My.NameSpace, Version=1.0.0.0, Culture=neutral, PublicKeyToken=...'

def $indexer.method_missing(methodname)
  $indexer.get_Item(methodname.to_s)
end
"&lt;/span&gt;;

&lt;span class="rem"&gt;//pretend we got the ruby script I really want to run from somewhere else&lt;/span&gt;
&lt;span class="kwrd"&gt;string&lt;/span&gt; rubyScript = GetRubyCode();

&lt;span class="kwrd"&gt;string&lt;/span&gt; script = requires + rubyScript;
ScriptSource source = rubyengine.CreateScriptSourceFromString(script);
runtime.ExecuteSourceUnit(source);&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p class="clear"&gt;What’s going on here is that we instantiate the IronRuby runtime and script engine and context (I still need to learn exactly what each of these things are responsible for apart from each other). I then set a global variable and set it to an instance of a CLR object written in C#.&lt;/p&gt;

&lt;p class="clear"&gt;After that, I start constructing a string that contains the beginning of the Ruby script I want to execute. I will pre-append this beginning section with the actual script I want to run.&lt;/p&gt;

&lt;p&gt;The beginning of the Ruby script imports the .NET namespace that contains my CLR type to IronRuby (&lt;em&gt;I believe that by default you don’t need to import mscorlib and System&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;I then added a &lt;code&gt;missing_method&lt;/code&gt; method to that CLR instance within the Ruby code via this snippet.&lt;/p&gt;

&lt;div class="dropshadow code"&gt;
  &lt;div class="innerbox"&gt;
    &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;def&lt;/span&gt; $indexer.method_missing(methodname);
  $indexer.get_Item(methodname.to_s)
&lt;span class="kwrd"&gt;end&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p class="clear"&gt;At that point now, when I execute the rest of the ruby script, any calls from within Ruby to this CLR object can take advantage of this new method we patched onto the instance.&lt;/p&gt;

&lt;p&gt;Pretty nifty, eh?&lt;/p&gt;

&lt;p&gt;In my next post, I will show you the concrete instance of using this and supply source code.&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:841369bd-033d-43d4-8819-02f21cc5c481" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/DLR" rel="tag"&gt;DLR&lt;/a&gt;,&lt;a href="http://technorati.com/tags/IronRuby" rel="tag"&gt;IronRuby&lt;/a&gt;,&lt;a href="http://technorati.com/tags/DSL" rel="tag"&gt;DSL&lt;/a&gt;&lt;/div&gt;&lt;img src="http://haacked.com/aggbug/18478.aspx" width="1" height="1" /&gt;
&lt;p&gt;&lt;a href="http://feeds.haacked.com/~a/haacked?a=3ge5cS"&gt;&lt;img src="http://feeds.haacked.com/~a/haacked?i=3ge5cS" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.haacked.com/~f/haacked?a=Lh6EARg"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=Lh6EARg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=TQkulcg"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=TQkulcg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=MFoOtpG"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=MFoOtpG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=xl8M2wG"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=xl8M2wG" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>Haacked</dc:creator>
            <guid isPermaLink="false">http://haacked.com/archive/2008/04/18/monkey-patching-clr-objects.aspx</guid>
            <pubDate>Fri, 18 Apr 2008 22:18:01 GMT</pubDate>
            <wfw:comment>http://haacked.com/comments/18478.aspx</wfw:comment>
            <comments>http://haacked.com/archive/2008/04/18/monkey-patching-clr-objects.aspx#feedback</comments>
            <slash:comments>8</slash:comments>
            <wfw:commentRss>http://haacked.com/comments/commentRss/18478.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Dynamic Language DSL vs Xml Configuration</title>
            <category>Software Development</category>
            <link>http://haacked.com/archive/2008/04/18/dynamic-language-dsl-vs-xml-configuration.aspx</link>
            <description>&lt;p&gt;&lt;em&gt;Disclaimer: My opinions only, not anyone else’s. Nothing official here. I shouldn’t have to say this, but past history suggests I should. P.S. I’m not an expert on DSLs and Dynamic Languages ;)&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;This week I attended a talk by &lt;a title="John Lam on Software" href="http://www.iunknown.com/" rel="friend met co-worker"&gt;John Lam&lt;/a&gt; on &lt;a title="IronRuby" href="http://www.ironruby.net/"&gt;IronRuby&lt;/a&gt; in which he trotted out the Uncle Ben line, &lt;em&gt;with great power comes great responsibility&lt;/em&gt;. He was of course referring to the power in a dynamic language like Ruby.&lt;/p&gt;  &lt;p&gt;Another quip he made stuck with me. He talked about how his brain sometimes gets twisted in a knot reading Ruby code written using &lt;a title="Metaprogramming" href="http://en.wikipedia.org/wiki/Metaprogramming"&gt;metaprogramming&lt;/a&gt; techniques for hours at a time. It takes great concentration comprehending code on a meta and meta-meta level in which the code is manipulating and even rewriting code at runtime. Perhaps this is why C# will remain my primary language in the near term while I try and expand my brain to work on a higher level. ;)&lt;/p&gt;  &lt;p&gt;However, the type of code I think he is referring to is the code for implementing a DSL itself. Once a DSL is written though, the code on top of that DSL ought to be quite readable. This is the nook where I see myself adopting IronRuby prior to using it as my primary language.I can see myself creating and using mini-DSLs (Domain Specific Languages) here and there as replacement for configuration.&lt;/p&gt;  &lt;p&gt;Ahhh... configuration. I sometimes think this is a misnomer. At least in the way that the Java and .NET community have approached config in practice. We’ve had this trend in which we started jamming everything into XML configuration.&lt;/p&gt;  &lt;p&gt;So much so, we often get asked to provide XML to configure features I think ought to be set in code along with unit tests. We’ve turned XML into a programming language, and a crappy one at that. Ayende &lt;a title="Cannot postpone -Source Control" href="http://www.ayende.com/Blog/archive/2008/04/17/Source-control-is-not-a-feature-you-can-postphone-to.aspx"&gt;talks about one issue&lt;/a&gt; with sweeping piles of XML configuration under a tool. This is not an intractable problem, but it highlights the fact that XML is code, but it is code with a lot of &lt;em&gt;ceremony&lt;/em&gt; compared to the amount of &lt;em&gt;essence&lt;/em&gt;. To understand what I mean by ceremony vs essence read &lt;a title="Ceremony vs Essence" href="http://blog.thinkrelevance.com/2008/4/1/ending-legacy-code-in-our-lifetime"&gt;Ending Legacy Code In Our Lifetime&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;With the ASP.NET MVC project, we’ve taken the approach of &lt;em&gt;&lt;strong&gt;Code First, Config Second&lt;/strong&gt;&lt;/em&gt;. You can see this with our URL Routing feature. You define routes in code, and we might provide configuration for this feature in a future version.&lt;/p&gt;  &lt;p&gt;With this approach, you can write unit tests for your route definitions &lt;strong&gt;which is a good thing&lt;/strong&gt;! Routes basically turn the URL into a method invocation, why wouldn’t you want to have tests for that?&lt;/p&gt;  &lt;p&gt;The reason I write about this now is that I’ve been playing around with IronRuby lately and want to post on some of the interesting stuff I’ve been doing in my own time. This post sets the context for why I am looking into this, apart from it just being plain fun and coming from a haacker ethic of wanting to see how things work.&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:630c4a70-aacd-41d1-b407-6c634ef24433" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/DLR" rel="tag"&gt;DLR&lt;/a&gt;,&lt;a href="http://technorati.com/tags/IronRuby" rel="tag"&gt;IronRuby&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Configuration" rel="tag"&gt;Configuration&lt;/a&gt;,&lt;a href="http://technorati.com/tags/DSL" rel="tag"&gt;DSL&lt;/a&gt;&lt;/div&gt;&lt;img src="http://haacked.com/aggbug/18477.aspx" width="1" height="1" /&gt;
&lt;p&gt;&lt;a href="http://feeds.haacked.com/~a/haacked?a=TEmGVn"&gt;&lt;img src="http://feeds.haacked.com/~a/haacked?i=TEmGVn" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.haacked.com/~f/haacked?a=nSGOYlg"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=nSGOYlg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=cW2KbJg"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=cW2KbJg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=7tCDCCG"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=7tCDCCG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=YJuciVG"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=YJuciVG" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>Haacked</dc:creator>
            <guid isPermaLink="false">http://haacked.com/archive/2008/04/18/dynamic-language-dsl-vs-xml-configuration.aspx</guid>
            <pubDate>Fri, 18 Apr 2008 22:16:29 GMT</pubDate>
            <wfw:comment>http://haacked.com/comments/18477.aspx</wfw:comment>
            <comments>http://haacked.com/archive/2008/04/18/dynamic-language-dsl-vs-xml-configuration.aspx#feedback</comments>
            <slash:comments>9</slash:comments>
            <wfw:commentRss>http://haacked.com/comments/commentRss/18477.aspx</wfw:commentRss>
        </item>
        <item>
            <title>ASP.NET MVC Preview of a Preview</title>
            <category>ASP.NET</category>
            <category>ASP.NET MVC</category>
            <category>Software Development</category>
            <link>http://haacked.com/archive/2008/04/17/asp.net-mvc-preview-of-a-preview.aspx</link>
            <description>&lt;p class="update"&gt;UPDATE: Just to prove that this is a preview of a preview, we had a signing problem with the initial pre-built VSI download. If you tried building from source, everything should’ve been ok. We apologize for that. Even though this is meant to be a rough preview, we do want to have a high quality bar in that you should be able to try out the code. So if you run into that problem, please do download the VSI again.&lt;/p&gt;
&lt;p&gt;It’s no secret that Microsoft can get better at naming &lt;strong&gt;non RTM&lt;/strong&gt; (Release to Manufacturing) releases. We have terms like CTP, Preview, Alpha, Beta, RC (Release Candidate), and so on. On the other hand, at least Microsoft does try to move things along to RTM rather than keeping products in perpetual Beta.&lt;/p&gt;
&lt;p&gt;With ASP.NET MVC, we also need to add yet another type of release. For now I’ve been calling this a &lt;em&gt;&lt;a title="CodePlex Source Release" href="http://www.codeplex.com/aspnet/Release/ProjectReleases.aspx?ReleaseId=12640"&gt;CodePlex Source Release&lt;/a&gt;&lt;/em&gt; meaning it’s simply sharing source code that is &lt;em&gt;in progress&lt;/em&gt;. &lt;a title="Scott Guthrie" href="http://weblogs.asp.net/scottgu/"&gt;ScottGu&lt;/a&gt; called it a “Preview of a Preview” in my office one day and that name stuck with me. This is really a preview of an upcoming preview. ;)&lt;/p&gt;
&lt;p&gt;Speaking of ScottGu, he posted &lt;a title="ASP.NET MVC Source Refresh Preview" href="http://weblogs.asp.net/scottgu/archive/2008/04/16/asp-net-mvc-source-refresh-preview.aspx"&gt;a detailed description of this release&lt;/a&gt; on his blog last night. I recommend taking a look at it because he covers most of the changes in good detail.&lt;/p&gt;
&lt;p&gt;One aspect of this latest source release that I’m particularly happy about is that we released our unit tests. As Scott mentioned, we are using &lt;a title="Moq" href="http://code.google.com/p/moq/"&gt;MoQ&lt;/a&gt; as a mock framework within our tests. Note that this is not some official endorsement of any particular mock framework. Originally we started out trying to port our tests to Rhino Mocks (which I’ve &lt;a title="Rhino Mocks on Haacked.com" href="http://haacked.com/tags/rhino+mocks/default.aspx"&gt;written a lot about&lt;/a&gt;). MoQ just happened to have a programming model that was closer to the way our internal mock framework works, so we switched over to MoQ.&lt;/p&gt;
&lt;p&gt;I will write more about this release later. But for now, I will leave you with an &lt;strong&gt;&lt;a title="Northwind" href="http://haacked.com/code/NorthwindDemo.zip"&gt;updated Northwind Demo&lt;/a&gt;&lt;/strong&gt; based on this release because &lt;em&gt;there ain’t no party like a Northwind party&lt;/em&gt;.&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:afe8c7be-bf1c-49c5-b648-180a363b69af" style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;Technorati Tags: &lt;a rel="tag" href="http://technorati.com/tags/aspnetmvc"&gt;aspnetmvc&lt;/a&gt;&lt;/div&gt;&lt;img src="http://haacked.com/aggbug/18476.aspx" width="1" height="1" /&gt;
&lt;p&gt;&lt;a href="http://feeds.haacked.com/~a/haacked?a=OURlAK"&gt;&lt;img src="http://feeds.haacked.com/~a/haacked?i=OURlAK" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.haacked.com/~f/haacked?a=m7OPSzg"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=m7OPSzg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=6avH7hg"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=6avH7hg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=9491i0G"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=9491i0G" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=4PMAYtG"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=4PMAYtG" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>Haacked</dc:creator>
            <guid isPermaLink="false">http://haacked.com/archive/2008/04/17/asp.net-mvc-preview-of-a-preview.aspx</guid>
            <pubDate>Thu, 17 Apr 2008 16:47:09 GMT</pubDate>
            <wfw:comment>http://haacked.com/comments/18476.aspx</wfw:comment>
            <comments>http://haacked.com/archive/2008/04/17/asp.net-mvc-preview-of-a-preview.aspx#feedback</comments>
            <slash:comments>15</slash:comments>
            <wfw:commentRss>http://haacked.com/comments/commentRss/18476.aspx</wfw:commentRss>
        </item>
        <item>
            <title>You've Been Haacked In Chinese</title>
            <category>Personal</category>
            <link>http://haacked.com/archive/2008/04/10/youve-been-haacked-in-chinese.aspx</link>
            <description>&lt;p&gt;If ever someone was undeserving of having others spend their valuable time translating his blog, it would be me. But hey, some people from the &lt;a title="Blog Joycode" href="http://blog.joycode.com/"&gt;http://blog.joycode.com/&lt;/a&gt; site went ahead and &lt;a title="My blog in Chinese" href="http://blog.joycode.com/haacked/"&gt;did it anyway&lt;/a&gt;. I must admit that I’m very flattered that anyone would put the effort in.&lt;/p&gt;  &lt;p&gt;Before this, I learned that &lt;a title="Subtext powers china" href="http://haacked.com/archive/2007/10/29/subtext-powers-myspace-china-blogs.aspx"&gt;Subtext powers MySpace&lt;/a&gt; China's blogs, and now my blog is translated to Chinese. As David Hasselhoff says, “I’m big in China”. (&lt;em&gt;To my Chinese audience, that is a joke. I am quite small.&lt;/em&gt;)&lt;/p&gt;  &lt;p&gt;&lt;a href="http://haacked.com/images/haacked_com/WindowsLiveWriter/YouveBeenHaackedInChinese_11C49/david_coleman_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="603" alt="david_coleman" src="http://haacked.com/images/haacked_com/WindowsLiveWriter/YouveBeenHaackedInChinese_11C49/david_coleman_thumb.jpg" width="450" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:4df7c362-868a-4285-848f-1107718141ef" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Chinese" rel="tag"&gt;Chinese&lt;/a&gt;,&lt;a href="http://technorati.com/tags/China" rel="tag"&gt;China&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Blogging" rel="tag"&gt;Blogging&lt;/a&gt;&lt;/div&gt;&lt;img src="http://haacked.com/aggbug/18475.aspx" width="1" height="1" /&gt;
&lt;p&gt;&lt;a href="http://feeds.haacked.com/~a/haacked?a=zfAMZE"&gt;&lt;img src="http://feeds.haacked.com/~a/haacked?i=zfAMZE" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.haacked.com/~f/haacked?a=1btHlog"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=1btHlog" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=tLb6ZPg"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=tLb6ZPg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=CM27mKG"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=CM27mKG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=9pYfnzG"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=9pYfnzG" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>Haacked</dc:creator>
            <guid isPermaLink="false">http://haacked.com/archive/2008/04/10/youve-been-haacked-in-chinese.aspx</guid>
            <pubDate>Fri, 11 Apr 2008 03:31:33 GMT</pubDate>
            <wfw:comment>http://haacked.com/comments/18475.aspx</wfw:comment>
            <comments>http://haacked.com/archive/2008/04/10/youve-been-haacked-in-chinese.aspx#feedback</comments>
            <slash:comments>5</slash:comments>
            <wfw:commentRss>http://haacked.com/comments/commentRss/18475.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Upcoming Changes In Routing</title>
            <category>ASP.NET</category>
            <category>ASP.NET MVC</category>
            <category>Software Development</category>
            <link>http://haacked.com/archive/2008/04/10/upcoming-changes-in-routing.aspx</link>
            <description>&lt;p class="update"&gt;Made a few corrections on having default.aspx in the root due to a minor bug we just found. Isn’t preview code so much fun?&lt;/p&gt;
&lt;p&gt;We’ve been making some changes to routing to make it more powerful and useful. But as Uncle Ben says, with more power comes more responsibility. I’ll list out the changes first and then discuss some of the implication of the changes.&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Routes no longer treat the . character as a separator.&lt;/strong&gt; Currently, routes treat the . and / characters as special. They are separator characters. The upcoming release of routing will only treat the / as separator. &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Routes may have multiple (non-adjacent) url parameters in a segment.&lt;/strong&gt; Currently, URL parameters in a route must fill up the space between separators. For example, &lt;em&gt;&lt;code&gt;&lt;em&gt;{param1}/{param2}.{param3}&lt;/em&gt;&lt;/code&gt;&lt;/em&gt;. With the upcoming release, a URL segment may have more than one parameter as long as they are separated by a literal. For example &lt;em&gt;&lt;code&gt;&lt;em&gt;{param1}.{ext}/{param3}-{param4}&lt;/em&gt;&lt;/code&gt; &lt;/em&gt;is now valid&lt;em&gt;.&lt;/em&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Passing Parameter Values With Dots&lt;/h3&gt;
&lt;p&gt;With this change, the dot character becomes just another literal. It’s no longer “special”. What does this buy us? Suppose you are building a site that can present information about other sites. For example, you might want to support URLs like this:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;http://site-info.example.com&lt;strong&gt;/site/www.haacked.com/rss&lt;/strong&gt; &lt;/li&gt;
    &lt;li&gt;http://site-info.example.com&lt;strong&gt;/site/www.haacked.com/stats&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That first URL will display information about the RSS feed at www.haacked.com while the second one will show general site stats. To make this happen, you might define a route like this.&lt;/p&gt;
&lt;div class="dropshadow code"&gt;
&lt;div class="innerbox"&gt;
&lt;pre class="csharpcode"&gt;routes.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Route(&lt;span class="str"&gt;"site/{domain}/{action}"&lt;/span&gt; 
  , &lt;span class="kwrd"&gt;new&lt;/span&gt; MvcRouteHandler()) 
{ 
  Defaults=&lt;span class="kwrd"&gt;new&lt;/span&gt; RouteValueDictionary(&lt;span class="kwrd"&gt;new&lt;/span&gt; {controller=&lt;span class="str"&gt;"site"&lt;/span&gt;})  
});&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p class="clear"&gt;Which routes to the following controller and action method.&lt;/p&gt;
&lt;div class="dropshadow code"&gt;
&lt;div class="innerbox"&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SiteController : Controller
{
  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Rss(&lt;span class="kwrd"&gt;string&lt;/span&gt; domain)
  {
    RssData rss = GetRssData(domain);
    RenderView(&lt;span class="str"&gt;"Rss"&lt;/span&gt;, rss);
  }

  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Stats(&lt;span class="kwrd"&gt;string&lt;/span&gt; domain)
  {
    SiteStatistics stats = GetSiteStatistics(domain);
    RenderView(&lt;span class="str"&gt;"Stats"&lt;/span&gt;, stats);
  }
}&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p class="clear"&gt;The basic idea here is that the domain (such as www.haacked.com in the example URLs above) would get passed to the &lt;code&gt;domain &lt;/code&gt;parameter of the action methods. The only problem is, it does not work with the previous routing system because routing considered the dot character in the URL as a separator. You would have had to define routes with URLs like &lt;code&gt;site/{sub}.{domain}.{toplevel}/{action} &lt;/code&gt;but then that doesn't work for URLs with two sub-domains or no sub-domain.&lt;/p&gt;
&lt;p&gt;Since we no longer treat the dot as special, this scenario is now possible.&lt;/p&gt;
&lt;h3&gt;Multiple URL Segments&lt;/h3&gt;
&lt;p&gt;What does adding multiple URL segments buy us? Well it continues to allow using routing with URLs that do have extensions. For example, suppose you want to route a request to the following action method: &lt;code&gt;&lt;strong&gt;public void List(string category, string format)&lt;/strong&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;With both the previous and new routing, you can match the request for the URL...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&lt;strong&gt;/products/list/beverages.xml&lt;/strong&gt;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;with the route&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&lt;strong&gt;{controller}/{action}/{category}.{format}&lt;/strong&gt;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To call that action method. But suppose you don’t want to use file extensions, but still want to specify the format in a special way. With the new routing, you can use any character as a separator. For example, maybe you want to use the dash character to separate the category from the format. You could then match the URL&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&lt;strong&gt;/products/list/beverages-xml&lt;/strong&gt;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;with the route&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;{controller}/{action}/{category}-{format}&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;and still call that action method.&lt;/p&gt;
&lt;p&gt;Note that we now allow any character (allowed in the URL and that is not a dash) to pretty much be a separator. So if you really wanted to, though not sure why you would, you could use &lt;em&gt;&lt;code&gt;BLAH&lt;/code&gt;&lt;/em&gt; to separate out the format. Thus you could match the route&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&lt;strong&gt;/products/list/beveragesBLAHxml&lt;/strong&gt;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;with the route&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&lt;strong&gt;{controller}/{action}/{category}BLAH{format}&lt;/strong&gt;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;and it would still route to the same &lt;code&gt;List&lt;/code&gt; method above.&lt;/p&gt;
&lt;h3&gt;Consequences&lt;/h3&gt;
&lt;p&gt;This makes routing more powerful, but there are consequences to be aware of. &lt;/p&gt;
&lt;p&gt;For example, using the default routes as defined in the ASP.NET MVC Preview 2 project template, a request for &lt;code&gt;&lt;code&gt;&lt;em&gt;“/&lt;code&gt;&lt;code&gt;&lt;em&gt;Default.aspx”&lt;/em&gt;&lt;/code&gt;&lt;/code&gt;&lt;/em&gt;&lt;/code&gt;&lt;/code&gt; fails because it can’t find a controller with the name &lt;code&gt;&lt;code&gt;&lt;em&gt;“&lt;code&gt;&lt;code&gt;&lt;em&gt;Default.aspx”&lt;/em&gt;&lt;/code&gt;&lt;/code&gt;&lt;/em&gt;&lt;/code&gt;&lt;/code&gt;. Huh? Well &lt;code&gt;&lt;code&gt;&lt;em&gt;“/&lt;code&gt;&lt;code&gt;&lt;em&gt;Default.aspx”&lt;/em&gt;&lt;/code&gt;&lt;/code&gt;&lt;/em&gt;&lt;/code&gt;&lt;/code&gt; now matches the route &lt;em&gt;&lt;code&gt;&lt;em&gt;{controller}/{action}/{id}&lt;/em&gt;&lt;/code&gt;&lt;/em&gt; (&lt;em&gt;because of the defaults for {id} and {action}&lt;/em&gt;) because we don’t treat the dot as special.&lt;/p&gt;
&lt;p&gt;Not only that, what about a request for &lt;code&gt;/images/jpegs/foo.jpg&lt;/code&gt;? Wouldn’t routing try to route that to controller="images", action="jpegs", id="foo.jpg" now?&lt;/p&gt;
&lt;p&gt;The decision we made in this case was that &lt;strong&gt;by default, routing should not apply to files on disk&lt;/strong&gt;. That is, routing now checks to see if the file is on disk before attempting to route (via the Virtual Path Provider).&lt;/p&gt;
&lt;p&gt;If the file is on disk, we pop out and don’t route and let the web server handle the request normally. If the file doesn’t exist, we attempt to apply routing. This makes sure we don’t screw around with requests for static resources on disk. Of course, this default can be changed by setting the property &lt;code&gt;RouteTable.Routes.RouteExistingFiles&lt;/code&gt; to be &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Why Blog This Now?&lt;/h3&gt;
&lt;p&gt;The Dynamic Data team is scooping the MVC team on these routing changes. ;) They are &lt;a title="ASP.NET Dynamic Data Preview" href="http://code.msdn.microsoft.com/dynamicdata"&gt;releasing a preview&lt;/a&gt; of their latest changes to Dynamic Data which includes using our new routing dll. &lt;/p&gt;
&lt;p&gt;Check out &lt;a title="Dynamic Data Preview" href="http://weblogs.asp.net/scottgu/archive/2008/04/10/asp-net-dynamic-data-preview-available.aspx"&gt;ScottGu’s post on the subject&lt;/a&gt;. I really feel Dynamic Data is the most underrated new technology coming out from the ASP.NET team. When you dig into it, it is really cool. The “scaffolding” part is only the tip of the iceberg.&lt;/p&gt;
&lt;p&gt;Installing the Dynamic Data preview requires installing the routing assembly into the GAC. &lt;strong&gt;If you install this, it may break existing MVC Preview 2 sites &lt;/strong&gt;because the assembly loader favors the GAC when the assembly is the same version. And the routing assembly is the same version as the one in Preview 2.&lt;/p&gt;
&lt;p&gt;The Dynamic Data Preview readme has the steps to update your MVC Preview 2 project to work with the new routing. You’ll notice that the readme recommends having a Default.aspx file in the root which redirects to &lt;em&gt;&lt;em&gt;/Home&lt;/em&gt;&lt;/em&gt;. Technically, the Default.aspx file in the root won’t be necessary in the final release because of the suggested routing changes (it is necessary now due to a minor bug). Unfortunately, Cassini doesn’t work correctly when you make a request for "/" and there is no default document. It doesn’t run any of the ASP.NET Modules. So we kept the file in the root, but you &lt;strike&gt;can&lt;/strike&gt; will be able to remove it when deploying to IIS 7. So to recap this last point, &lt;em&gt;the Default.aspx in the project root is to make sure that Cassini works correctly. It's will not be needed for IIS 7 in the future, but is needed for the time being.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We will have a new &lt;a title="CodePlex" href="http://codeplex.com/ASPNET"&gt;CodePlex source code push&lt;/a&gt; in a couple of weeks with an updated version of MVC that supports the new routing engine.&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:862a32db-d3c1-474b-9e97-41f2244c5718" style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;Technorati Tags: &lt;a rel="tag" href="http://technorati.com/tags/ASP.NET%20MVC"&gt;ASP.NET MVC&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/ASP.NET"&gt;ASP.NET&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/Routing"&gt;Routing&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/Dynamic%20Data"&gt;Dynamic Data&lt;/a&gt;&lt;/div&gt;&lt;img src="http://haacked.com/aggbug/18474.aspx" width="1" height="1" /&gt;
&lt;p&gt;&lt;a href="http://feeds.haacked.com/~a/haacked?a=EzZpbw"&gt;&lt;img src="http://feeds.haacked.com/~a/haacked?i=EzZpbw" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.haacked.com/~f/haacked?a=FBEfu3g"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=FBEfu3g" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=4LpMCkg"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=4LpMCkg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=q1FZfuG"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=q1FZfuG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.haacked.com/~f/haacked?a=cfxxVWG"&gt;&lt;img src="http://feeds.haacked.com/~f/haacked?i=cfxxVWG" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>Haacked</dc:creator>
            <guid isPermaLink="false">http://haacked.com/archive/2008/04/10/upcoming-changes-in-routing.aspx</guid>
            <pubDate>Thu, 10 Apr 2008 18:14:54 GMT</pubDate>
            <wfw:comment>http://haacked.com/comments/18474.aspx</wfw:comment>
            <comments>http://haacked.com/archive/2008/04/10/upcoming-changes-in-routing.aspx#feedback</comments>
            <slash:comments>22</slash:comments>
            <wfw:commentRss>http://haacked.com/comments/commentRss/18474.aspx</wfw:commentRss>
        </item>
    </channel>
</rss>
