<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" version="2.0">
  <channel>
    <title>Eleutian SpeakENG Development Blog - code generation</title>
    <link>http://blog.eleutian.com/</link>
    <description />
    <language>en-us</language>
    <copyright>Eleutian Technology</copyright>
    <lastBuildDate>Thu, 12 Apr 2007 01:41:13 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.0.7226.0</generator>
    <managingEditor>aaron@eleutian.com</managingEditor>
    <webMaster>aaron@eleutian.com</webMaster>
    <item>
      <trackback:ping>http://blog.eleutian.com/Trackback.aspx?guid=e20768db-4b5a-4af6-b1c6-ca15dfc1012a</trackback:ping>
      <pingback:server>http://blog.eleutian.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.eleutian.com/PermaLink,guid,e20768db-4b5a-4af6-b1c6-ca15dfc1012a.aspx</pingback:target>
      <dc:creator>Jacob</dc:creator>
      <wfw:comment>http://blog.eleutian.com/CommentView,guid,e20768db-4b5a-4af6-b1c6-ca15dfc1012a.aspx</wfw:comment>
      <wfw:commentRss>http://blog.eleutian.com/SyndicationService.asmx/GetEntryCommentsRss?guid=e20768db-4b5a-4af6-b1c6-ca15dfc1012a</wfw:commentRss>
      <slash:comments>13</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
We were on the phone today with <a href="http://codebetter.com/blogs/scott.bellware/">Scott
Bellware</a> and he asked us if we could toss together a simple MonoRail project that
showed the Castle.Tools.CodeGenerator stuff in action. A few other people have been
asking us to do something similar for the other things we've been discussing on our
blog. So, Aaron and I sat down and pair-programmed out some source that does just
that. It shows several things:
</p>
        <ul>
          <li>
An Action/View map is generated using Castle.Tools.CodeGenerator, and used to do view
renderings, and (if desired) action redirections and the like.</li>
          <li>
PropertyBag wrappers are created using the IDictionaryAdapterFactory code that Lee
contributed.</li>
          <li>
We show how we test our controllers using the test fixture code Aaron has been
posting about.</li>
          <li>
It has a small service layer that roughly shows how we architecture our code around
here.</li>
          <li>
It uses Windsor integration, so you can see how that's used if you've been curious.</li>
        </ul>
        <p>
Please keep in mind this took us about an hour to whip up and we did not actually
practice full TDD with it. Enjoy!
</p>
        <p>
          <a href="http://blog.eleutian.com/download/MonoRail.Example.zip">Source</a>
        </p>
        <img width="0" height="0" src="http://blog.eleutian.com/aggbug.ashx?id=e20768db-4b5a-4af6-b1c6-ca15dfc1012a" />
      </body>
      <title>Example MonoRail Solution</title>
      <guid isPermaLink="false">http://blog.eleutian.com/PermaLink,guid,e20768db-4b5a-4af6-b1c6-ca15dfc1012a.aspx</guid>
      <link>http://blog.eleutian.com/2007/04/12/ExampleMonoRailSolution.aspx</link>
      <pubDate>Thu, 12 Apr 2007 01:41:13 GMT</pubDate>
      <description>&lt;p&gt;
We were on the phone today with &lt;a href="http://codebetter.com/blogs/scott.bellware/"&gt;Scott
Bellware&lt;/a&gt; and he asked us if we could toss together a simple MonoRail project that
showed the Castle.Tools.CodeGenerator stuff in action. A few other people have been
asking us to do something similar for the other things we've been discussing on our
blog. So, Aaron and I sat down and pair-programmed out some source that does just
that. It shows several things:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
An Action/View map is generated using Castle.Tools.CodeGenerator, and used to do view
renderings, and (if desired) action redirections and the like.&lt;/li&gt;
&lt;li&gt;
PropertyBag wrappers are created using the IDictionaryAdapterFactory code that Lee
contributed.&lt;/li&gt;
&lt;li&gt;
We show how&amp;nbsp;we test our controllers using the test fixture code Aaron has been
posting about.&lt;/li&gt;
&lt;li&gt;
It has a small service layer that roughly shows how we architecture our code around
here.&lt;/li&gt;
&lt;li&gt;
It uses Windsor integration, so you can see how that's used if you've been curious.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Please keep in mind this took us about an hour to whip up and we did not actually
practice full TDD with it. Enjoy!
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://blog.eleutian.com/download/MonoRail.Example.zip"&gt;Source&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.eleutian.com/aggbug.ashx?id=e20768db-4b5a-4af6-b1c6-ca15dfc1012a" /&gt;</description>
      <comments>http://blog.eleutian.com/CommentView,guid,e20768db-4b5a-4af6-b1c6-ca15dfc1012a.aspx</comments>
      <category>code generation</category>
      <category>monorail</category>
      <category>open source</category>
      <category>source</category>
      <category>test driven development</category>
    </item>
    <item>
      <trackback:ping>http://blog.eleutian.com/Trackback.aspx?guid=b454e935-2813-4bb9-b8f3-a724a2a81458</trackback:ping>
      <pingback:server>http://blog.eleutian.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.eleutian.com/PermaLink,guid,b454e935-2813-4bb9-b8f3-a724a2a81458.aspx</pingback:target>
      <dc:creator>Jacob</dc:creator>
      <wfw:comment>http://blog.eleutian.com/CommentView,guid,b454e935-2813-4bb9-b8f3-a724a2a81458.aspx</wfw:comment>
      <wfw:commentRss>http://blog.eleutian.com/SyndicationService.asmx/GetEntryCommentsRss?guid=b454e935-2813-4bb9-b8f3-a724a2a81458</wfw:commentRss>
      <slash:comments>4</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
        </p>
        <p>
I spent yesterday and today refactoring the code for the Controller Action/View map
generator tool. I made some improvements, wrote some tests and I'm pleased to announce
the first release. I saw Brian had implemented his as an MsBuild task and I liked
that idea, so that's how ours runs now. First, things aren't as "drop in and
go" as I would like because it's still evolving in and around our, already large,
code base. It's my hope that over time the tool evolves as peoples needs change, etc...
we can add some more configuration, that sort of thing. I'm more than willing to hear
suggestions and such. Anway, here we go...
</p>
        <p>
So in order to get yourself up and running, you'll need to do a few things. First,
you'll need to add the task to your MsBuild. Simply open your csproj and add the following:
</p>
        <pre class="csharpcode">
          <span class="kwrd">&lt;</span>
          <span class="html">UsingTask</span>
          <span class="attr">TaskName</span>
          <span class="kwrd">="Eleutian.Tools.CodeGenerator.MsBuild.GenerateMonoRailSiteTreeTask"</span>
          <span class="attr">AssemblyFile</span>
          <span class="kwrd">="Eleutian.Tools.CodeGenerator.dll"</span>
          <span class="kwrd">/&gt;</span>
          <span class="kwrd">&lt;</span>
          <span class="html">ItemGroup</span>
          <span class="kwrd">&gt;</span>
          <span class="kwrd"> &lt;</span>
          <span class="html">ViewSources</span>
          <span class="attr">Include</span>
          <span class="kwrd">="../YourViewsDirectory/**/*.brail"</span>
          <span class="kwrd">&gt;</span>
          <span class="kwrd"> &lt;</span>
          <span class="html">InProject</span>
          <span class="kwrd">&gt;</span>false<span class="kwrd">&lt;/</span><span class="html">InProject</span><span class="kwrd">&gt;</span><span class="kwrd"> &lt;/</span><span class="html">ViewSources</span><span class="kwrd">&gt;</span><span class="kwrd">&lt;/</span><span class="html">ItemGroup</span><span class="kwrd">&gt;</span><span class="kwrd">&lt;</span><span class="html">ItemGroup</span><span class="kwrd">&gt;</span><span class="kwrd"> &lt;</span><span class="html">ControllerSources</span><span class="attr">Include</span><span class="kwrd">="Controllers/**/*.cs"</span><span class="kwrd">&gt;</span><span class="kwrd"> &lt;</span><span class="html">InProject</span><span class="kwrd">&gt;</span>false<span class="kwrd">&lt;/</span><span class="html">InProject</span><span class="kwrd">&gt;</span><span class="kwrd"> &lt;/</span><span class="html">ControllerSources</span><span class="kwrd">&gt;</span><span class="kwrd">&lt;/</span><span class="html">ItemGroup</span><span class="kwrd">&gt;</span><span class="kwrd">&lt;</span><span class="html">Target</span><span class="attr">Name</span><span class="kwrd">="BeforeBuild"</span><span class="attr">Inputs</span><span class="kwrd">="@(Compile)"</span><span class="attr">Outputs</span><span class="kwrd">="$(ProjectDir)\SiteMap.generated.cs"</span><span class="kwrd">&gt;</span><span class="kwrd"> &lt;</span><span class="html">GenerateMonoRailSiteTreeTask</span><span class="attr">File</span><span class="kwrd">="SiteMap.generated.cs"</span><span class="attr">Namespace</span><span class="kwrd">="YourNamespace.SiteMap"</span><span class="attr">ControllerSources</span><span class="kwrd">="@(ControllerSources)"</span><span class="attr">ViewSources</span><span class="kwrd">="@(ViewSources)"</span><span class="kwrd">&gt;</span><span class="kwrd"> &lt;/</span><span class="html">GenerateMonoRailSiteTreeTask</span><span class="kwrd">&gt;</span><span class="kwrd">&lt;/</span><span class="html">Target</span><span class="kwrd">&gt;</span></pre>
        <p>
You'll notice a few things in here. ViewSources is just the collection of view files
(be it .vm or .brail, etc..). It will use the paths of those files to add the View
nodes into the map. ControllerSources is the C# source files for your controllers
only, specifying this helps speed up parsing. I'll get to why in a bit. And for the
Sources attribute on the task you should specify all the sources in the assembly,
which @(Compile) works great for.
</p>
        <p>
With the task added, you should be able to build and have a SiteMap.generated.cs file,
now you'll need to tweak your "base" Controller class. If you're like us, you have
a Controller class that you made yourself that all of your Controller's inherit from.
In that class you'll need to add some code like the following:
</p>
        <pre class="csharpcode">
          <span class="kwrd">private</span> ICodeGeneratorServices _services; <span class="kwrd">public</span> ICodeGeneratorServices
CodeGeneratorServices { get { <span class="kwrd">return</span> _services; } } <span class="kwrd">public</span> RootAreaNode
Site { get { <span class="kwrd">return</span><span class="kwrd">new</span> RootAreaNode(<span class="kwrd">this</span>.ControllerServices);
} } <span class="kwrd">protected</span><span class="kwrd">virtual</span><span class="kwrd">void</span> PerformGeneratedInitialize()
{ _services = <span class="kwrd">new</span> DefaultCodeGeneratorServices( <span class="kwrd">new</span> DefaultControllerReferenceFactory(), <span class="kwrd">new</span> AspDotNetRedirectService()
); _services.Controller = <span class="kwrd">this</span>; } </pre>
        <p>
First is the member variable, _services. You can do this however you like, but it's
consumed by the ControllerAction/ViewReference classes to do various likes. CodeGeneratorServices
is a property the partial controller code uses to create the MyActions and MyViews
node instances. Site is just an easy way to get the top, root level node. PerformGeneratorInitialize
is overridden in the partial controller classes to add the MyViews and MyActions nodes
to the PropertyBag so they are available in the views. So there you go. If I'm not
missing anything, that should do the trick. Let me know if I did and I'll append to
this post.
</p>
        <p>
Oh, the reason for specifying the ControllerSources is to cut down on the number of
classes/types we visit when generating the internal "tree" that the source code is
generated from. At first glance it seems like you should just be able to parse the
ControllerSources only. We coudln't really do that because we needed to gather information
on the other types in the assembly so we'd be able to use them in the arguments of
our actions, etc... 
</p>
        <p>
I have to stress that the code is relatively new, having undergone a major refactor
to isolate it from the rest of our project. I make no promises that I won't have to
upload a new copy, with a fix. :)
</p>
        <p>
          <a href="http://blog.eleutian.com/download/Eleutian.Tools.CodeGenerator-20070220.zip">Source
and Binaries</a>
        </p>
        <img width="0" height="0" src="http://blog.eleutian.com/aggbug.ashx?id=b454e935-2813-4bb9-b8f3-a724a2a81458" />
      </body>
      <title>Eleutian.Tools.CodeGenerator Source</title>
      <guid isPermaLink="false">http://blog.eleutian.com/PermaLink,guid,b454e935-2813-4bb9-b8f3-a724a2a81458.aspx</guid>
      <link>http://blog.eleutian.com/2007/02/21/EleutianToolsCodeGeneratorSource.aspx</link>
      <pubDate>Wed, 21 Feb 2007 02:36:46 GMT</pubDate>
      <description>&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
I spent yesterday and today refactoring the code for the Controller Action/View map
generator tool. I made some improvements, wrote some tests and I'm pleased to announce
the first release. I saw Brian had implemented his as an MsBuild task and I liked
that idea, so that's how ours runs now.&amp;nbsp;First, things aren't as "drop in and
go" as I would like because it's still evolving in and around our, already large,
code base. It's my hope that over time the tool evolves as peoples needs change, etc...
we can add some more configuration, that sort of thing. I'm more than willing to hear
suggestions and such. Anway, here we go...
&lt;/p&gt;
&lt;p&gt;
So in order to get yourself up and running, you'll need to do a few things. First,
you'll need to add the task to your MsBuild. Simply open your csproj and add the following:
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;UsingTask&lt;/span&gt; &lt;span class="attr"&gt;TaskName&lt;/span&gt;&lt;span class="kwrd"&gt;="Eleutian.Tools.CodeGenerator.MsBuild.GenerateMonoRailSiteTreeTask"&lt;/span&gt; &lt;span class="attr"&gt;AssemblyFile&lt;/span&gt;&lt;span class="kwrd"&gt;="Eleutian.Tools.CodeGenerator.dll"&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;ItemGroup&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;ViewSources&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;="../YourViewsDirectory/**/*.brail"&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;InProject&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;false&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;InProject&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;ViewSources&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;ItemGroup&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;ItemGroup&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;ControllerSources&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;="Controllers/**/*.cs"&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;InProject&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;false&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;InProject&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;ControllerSources&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;ItemGroup&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;="BeforeBuild"&lt;/span&gt; &lt;span class="attr"&gt;Inputs&lt;/span&gt;&lt;span class="kwrd"&gt;="@(Compile)"&lt;/span&gt; &lt;span class="attr"&gt;Outputs&lt;/span&gt;&lt;span class="kwrd"&gt;="$(ProjectDir)\SiteMap.generated.cs"&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;GenerateMonoRailSiteTreeTask&lt;/span&gt; &lt;span class="attr"&gt;File&lt;/span&gt;&lt;span class="kwrd"&gt;="SiteMap.generated.cs"&lt;/span&gt; &lt;span class="attr"&gt;Namespace&lt;/span&gt;&lt;span class="kwrd"&gt;="YourNamespace.SiteMap"&lt;/span&gt; &lt;span class="attr"&gt;ControllerSources&lt;/span&gt;&lt;span class="kwrd"&gt;="@(ControllerSources)"&lt;/span&gt; &lt;span class="attr"&gt;ViewSources&lt;/span&gt;&lt;span class="kwrd"&gt;="@(ViewSources)"&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;GenerateMonoRailSiteTreeTask&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;p&gt;
You'll notice a few things in here. ViewSources is just the collection of view files
(be it .vm or .brail, etc..). It will use the paths of those files to add the View
nodes into the map. ControllerSources is the C# source files for your controllers
only, specifying this helps speed up parsing. I'll get to why in a bit. And for the
Sources attribute on the task you should specify all the sources in the assembly,
which @(Compile) works great for.
&lt;/p&gt;
&lt;p&gt;
With the task added, you should be able to build and have a SiteMap.generated.cs file,
now you'll need to tweak your "base" Controller class. If you're like us, you have
a Controller class that you made yourself that all of your Controller's inherit from.
In that class you'll need to add some code like the following:
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; ICodeGeneratorServices _services; &lt;span class="kwrd"&gt;public&lt;/span&gt; ICodeGeneratorServices
CodeGeneratorServices { get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _services; } } &lt;span class="kwrd"&gt;public&lt;/span&gt; RootAreaNode
Site { get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; RootAreaNode(&lt;span class="kwrd"&gt;this&lt;/span&gt;.ControllerServices);
} } &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; PerformGeneratedInitialize()
{ _services = &lt;span class="kwrd"&gt;new&lt;/span&gt; DefaultCodeGeneratorServices( &lt;span class="kwrd"&gt;new&lt;/span&gt; DefaultControllerReferenceFactory(), &lt;span class="kwrd"&gt;new&lt;/span&gt; AspDotNetRedirectService()
); _services.Controller = &lt;span class="kwrd"&gt;this&lt;/span&gt;; } &lt;/pre&gt;
&lt;p&gt;
First is the member variable, _services. You can do this however you like, but it's
consumed by the ControllerAction/ViewReference classes to do various likes. CodeGeneratorServices
is a property the partial controller code uses to create the MyActions and MyViews
node instances. Site is just an easy way to get the top, root level node. PerformGeneratorInitialize
is overridden in the partial controller classes to add the MyViews and MyActions nodes
to the PropertyBag so they are available in the views. So there you go. If I'm not
missing anything, that should do the trick. Let me know if I did and I'll append to
this post.
&lt;/p&gt;
&lt;p&gt;
Oh, the reason for specifying the ControllerSources is to cut down on the number of
classes/types we visit when generating the internal "tree" that the source code is
generated from. At first glance it seems like you should just be able to parse the
ControllerSources only. We coudln't really do that because we needed to gather information
on the other types in the assembly so we'd be able to use them in the arguments of
our actions, etc...&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
I have to stress that the code is relatively new, having undergone a major refactor
to isolate it from the rest of our project. I make no promises that I won't have to
upload a new copy, with a fix. :)
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://blog.eleutian.com/download/Eleutian.Tools.CodeGenerator-20070220.zip"&gt;Source
and Binaries&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.eleutian.com/aggbug.ashx?id=b454e935-2813-4bb9-b8f3-a724a2a81458" /&gt;</description>
      <comments>http://blog.eleutian.com/CommentView,guid,b454e935-2813-4bb9-b8f3-a724a2a81458.aspx</comments>
      <category>code generation</category>
      <category>development</category>
      <category>monorail</category>
      <category>source</category>
      <category>tools</category>
    </item>
    <item>
      <trackback:ping>http://blog.eleutian.com/Trackback.aspx?guid=e6b41de9-34c0-48e7-b440-72a7f0ca48de</trackback:ping>
      <pingback:server>http://blog.eleutian.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.eleutian.com/PermaLink,guid,e6b41de9-34c0-48e7-b440-72a7f0ca48de.aspx</pingback:target>
      <dc:creator>Jacob</dc:creator>
      <wfw:comment>http://blog.eleutian.com/CommentView,guid,e6b41de9-34c0-48e7-b440-72a7f0ca48de.aspx</wfw:comment>
      <wfw:commentRss>http://blog.eleutian.com/SyndicationService.asmx/GetEntryCommentsRss?guid=e6b41de9-34c0-48e7-b440-72a7f0ca48de</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Hello everyone. I just wanted to let those who responded to the string literal posts know
what was "going on". Basically, we're still trying to find a way that we can release
the source to some of our tools. I apologize for dragging my feet. I manage
to keep pretty busy. Heh.
</p>
        <p>
I was catching up on the castle-project's mailing list and found <a href="http://groups.google.com/group/castle-project-devel/browse_frm/thread/aa65cfb118250109">this
post</a> by Lee Henson. He's tossed together an implementation of a PropertyBag
wrapper generator and posted the source. It's very similar to our approach. One main
difference is that we do our generation at runtime so we don't have to generate and
reference another assembly. We have an IViewFactory interface and a PropertyBagViewFactory
implementation that hands them out. In tests we have an IViewFactory that pulls the
views out of the MockRepository. 
</p>
        <p>
Incidentally, our code that does this lies with some other code for generating
Control.Invoke proxies for our System.Windows.Forms view interfaces. It seems we're
not the only people who do that particular type of generation. Rüdiger Klaehn
has an article <a href="http://www.codeproject.com/csharp/threadsafeforms.asp?print=true">here</a> about
it. I strongly suggest reading it if you do any kind of SWF work.
</p>
        <p>
In the thread I found a link to <a href="http://www.brianromanko.com/2007/02/monorail-code-generation.html">Brian
Romanko's</a> post about his implementation of the controller action/view SiteMap,
as well as the PropertyBag wrapper. So just in case anybody gets impatient they can
find something to tinker with over there. While his implementation is different from
ours, the end result is very similar. I like his idea of generating a property for
actions to refer to them without parameters.
</p>
        <p>
I mentioned that for the SiteMap code generation we used CodeDom. CodeDom is
great and means we don't have to use StringBuilder to construct C#. It also abstracts
the language away. For those who are interested in this kind of code inspection/generation,
I strongly suggest taking a look at <a href="http://wiki.sharpdevelop.net/default.aspx/SharpDevelop.NRefactory">N
Refactory</a>, it's a great library for parsing C#/VB.NET source. It's what we use
and I've been incredibly happy with it. The only real hurdle when doing that kind
or work is type resolution. I'll try and make a post about that in the near future. 
</p>
        <img width="0" height="0" src="http://blog.eleutian.com/aggbug.ashx?id=e6b41de9-34c0-48e7-b440-72a7f0ca48de" />
      </body>
      <title>We're Glad Everybody Hates String Literals</title>
      <guid isPermaLink="false">http://blog.eleutian.com/PermaLink,guid,e6b41de9-34c0-48e7-b440-72a7f0ca48de.aspx</guid>
      <link>http://blog.eleutian.com/2007/02/19/WereGladEverybodyHatesStringLiterals.aspx</link>
      <pubDate>Mon, 19 Feb 2007 03:04:16 GMT</pubDate>
      <description>&lt;p&gt;
Hello everyone. I just wanted to let those who responded to the string literal posts&amp;nbsp;know
what was "going on". Basically, we're still trying to find a way that we can release
the source to some of our tools.&amp;nbsp;I apologize for dragging&amp;nbsp;my feet. I manage
to keep pretty busy. Heh.
&lt;/p&gt;
&lt;p&gt;
I was catching up on the castle-project's mailing list and found &lt;a href="http://groups.google.com/group/castle-project-devel/browse_frm/thread/aa65cfb118250109"&gt;this
post&lt;/a&gt;&amp;nbsp;by Lee Henson. He's tossed together an implementation of a PropertyBag
wrapper generator and posted the source. It's very similar to our approach. One main
difference is that we do our generation at runtime so we don't have to generate and
reference another assembly. We have an IViewFactory interface and a PropertyBagViewFactory
implementation that hands them out. In tests we have an IViewFactory that pulls the
views out of the MockRepository. 
&lt;/p&gt;
&lt;p&gt;
Incidentally, our code that does&amp;nbsp;this lies with some other code for generating
Control.Invoke proxies for our System.Windows.Forms view interfaces. It seems&amp;nbsp;we're
not the only&amp;nbsp;people who do that particular type of generation. Rüdiger Klaehn
has an article &lt;a href="http://www.codeproject.com/csharp/threadsafeforms.asp?print=true"&gt;here&lt;/a&gt; about
it. I strongly suggest reading&amp;nbsp;it if you do any kind of SWF work.
&lt;/p&gt;
&lt;p&gt;
In the thread I found a link to &lt;a href="http://www.brianromanko.com/2007/02/monorail-code-generation.html"&gt;Brian
Romanko's&lt;/a&gt;&amp;nbsp;post about his implementation of the controller&amp;nbsp;action/view&amp;nbsp;SiteMap,
as well as the PropertyBag wrapper. So just in case anybody gets impatient they can
find something to tinker with over there. While his implementation is different from
ours, the end result is very similar. I like his idea of generating a property for
actions to refer to them without parameters.
&lt;/p&gt;
&lt;p&gt;
I mentioned that for the SiteMap code&amp;nbsp;generation we used CodeDom. CodeDom is
great and means we don't have to use StringBuilder to construct C#. It also abstracts
the language away. For those who are interested in this kind of code inspection/generation,
I strongly suggest taking a look at &lt;a href="http://wiki.sharpdevelop.net/default.aspx/SharpDevelop.NRefactory"&gt;N
Refactory&lt;/a&gt;, it's a great library for parsing C#/VB.NET source. It's what we use
and I've been incredibly happy with it. The only real hurdle when doing that kind
or work is type resolution. I'll try and make a post about that in the near future. 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.eleutian.com/aggbug.ashx?id=e6b41de9-34c0-48e7-b440-72a7f0ca48de" /&gt;</description>
      <comments>http://blog.eleutian.com/CommentView,guid,e6b41de9-34c0-48e7-b440-72a7f0ca48de.aspx</comments>
      <category>code generation</category>
      <category>development</category>
      <category>emit</category>
      <category>source</category>
    </item>
    <item>
      <trackback:ping>http://blog.eleutian.com/Trackback.aspx?guid=ba5b573d-9863-456f-8e0d-be8871883eca</trackback:ping>
      <pingback:server>http://blog.eleutian.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.eleutian.com/PermaLink,guid,ba5b573d-9863-456f-8e0d-be8871883eca.aspx</pingback:target>
      <dc:creator>Jacob</dc:creator>
      <wfw:comment>http://blog.eleutian.com/CommentView,guid,ba5b573d-9863-456f-8e0d-be8871883eca.aspx</wfw:comment>
      <wfw:commentRss>http://blog.eleutian.com/SyndicationService.asmx/GetEntryCommentsRss?guid=ba5b573d-9863-456f-8e0d-be8871883eca</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I figured I might as well continue on the string literal kick I started with my last
post and talk about another situation where we've eliminated string literals. Take
the following code from inside a MonoRail action method:
</p>
        <pre class="csharpcode">PropertyBag[<span class="str">"User"</span>] = ourUser; PropertyBag[<span class="str">"TwoStates"</span>]
= <span class="kwrd">new</span><span class="kwrd">string</span>[] { <span class="str">"WA"</span>, <span class="str">"CA"</span> };
PropertyBag[<span class="str">"IsAdmin"</span>] = <span class="kwrd">true</span>;</pre>
        <p>
String literals, used as keys into dictionaries carry a cetain degree of code smell
(for us) and we try to avoid them. It reminds me too much code that does something
similar, but in the opposite direction:
</p>
        <pre class="csharpcode">
          <span class="kwrd">int</span> id = Int32.Parse(<span class="kwrd">this</span>.Params[<span class="str">"id"</span>])</pre>
        <p>
Thankfully, this kind of code is eliminated when using MonoRail and its SmartDispatchController.
We found ourselves thinking of how the same code would look in a SWF application.
We would be populating views, only those views would be interfaces that the various
forms/controls implemented. Well, this is exactly what we wanted in MonoRail, to wrap
the PropertyBag with an interface!
</p>
        <p>
After a few hours playing with Reflection.Emit, I had a code generator that would
take an interface:
</p>
        <pre class="csharpcode">
          <span class="kwrd">public</span>
          <span class="kwrd">interface</span> IEditMyProfileView
{ <span class="kwrd">string</span> Name { get; set; } DateTime Birthday { get; set;
} IList&lt;TimeZone&gt; TimeZones { get; set; } } </pre>
        <p>
And produce a class like the following:
</p>
        <pre class="csharpcode">
          <span class="kwrd">public</span>
          <span class="kwrd">class</span> EditMyProfileViewPropertyBagManipulator
: IEditMyProfileView { <span class="kwrd">private</span> IDictionary _bag; <span class="kwrd">public</span> EditMyProfileViewPropertyBagManipulator(IDictionary
bag) { _bag = bag; } <span class="kwrd">public</span><span class="kwrd">string</span> Name
{ get { <span class="kwrd">return</span> (<span class="kwrd">string</span>)_bag[<span class="str">"Name"</span>];
} set { _bag[<span class="str">"Name"</span>] = <span class="kwrd">value</span>; }
} <span class="kwrd">public</span> DateTime Birthday { get { <span class="kwrd">return</span> (DateTime)_bag[<span class="str">"Birthday"</span>];
} set { _bag[<span class="str">"Birthday"</span>] = <span class="kwrd">value</span>;
} } <span class="kwrd">public</span> IList&lt;TimeZone&gt; TimeZones { get { <span class="kwrd">return</span> (IList&lt;TimeZone&gt;)_bag[<span class="str">"TimeZones"</span>];
} set { _bag[<span class="str">"TimeZones"</span>] = <span class="kwrd">value</span>;
} } } </pre>
        <p>
This has the advantage of keeping our interactions with the PropertyBag as type safe
as they can be. Changing the interface, breaks the build. Where as changing the type
of a value inserted into the PropertyBag will (hopefully) only break tests if even
that. This is another example of us trying to turn run-time failures into compile-time
failures.
</p>
        <p>
This kind of thing also makes tests more elegant. Instead of:
</p>
        <pre class="csharpcode">Assert.Equals(<span class="str">"Jacob"</span>, PropertyBag[<span class="str">"Name"</span>]);</pre>
        <p>
In our controller tests, we can continue to leverage the use of RhinoMocks to ensure
the views are properly initialized:
</p>
        <pre class="csharpcode">
          <span class="kwrd">using</span> (_mocks.Unordered()) { _view.Name
= <span class="str">"Jacob"</span>; } _mocks.ReplayAll(); _controller.Action(); _mocks.Verify(_view);</pre>
        <p>
All we've done here is created a mock from the view interface, rather than emitting
the wrapper class. Again, another added benefit is if the view changes, compiling
the tests will also break. The sooner things break after a change the better, and
the build is pretty soon. Although, with ReSharper, it's nice to see red squiggles
appear as that's even sooner.
</p>
        <img width="0" height="0" src="http://blog.eleutian.com/aggbug.ashx?id=ba5b573d-9863-456f-8e0d-be8871883eca" />
      </body>
      <title>We Still Hate String Literals</title>
      <guid isPermaLink="false">http://blog.eleutian.com/PermaLink,guid,ba5b573d-9863-456f-8e0d-be8871883eca.aspx</guid>
      <link>http://blog.eleutian.com/2007/01/31/WeStillHateStringLiterals.aspx</link>
      <pubDate>Wed, 31 Jan 2007 04:31:07 GMT</pubDate>
      <description>&lt;p&gt;
I figured I might as well continue on the string literal kick I started with my last
post and talk about another situation where we've eliminated string literals. Take
the following code from inside a MonoRail action method:
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;PropertyBag[&lt;span class="str"&gt;"User"&lt;/span&gt;] = ourUser; PropertyBag[&lt;span class="str"&gt;"TwoStates"&lt;/span&gt;]
= &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] { &lt;span class="str"&gt;"WA"&lt;/span&gt;, &lt;span class="str"&gt;"CA"&lt;/span&gt; };
PropertyBag[&lt;span class="str"&gt;"IsAdmin"&lt;/span&gt;] = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;
String literals, used as keys into dictionaries carry a cetain degree of code smell
(for us) and we try to avoid them. It reminds me too much code that does something
similar, but in the opposite direction:
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;int&lt;/span&gt; id = Int32.Parse(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Params[&lt;span class="str"&gt;"id"&lt;/span&gt;])&lt;/pre&gt;
&lt;p&gt;
Thankfully, this kind of code is eliminated when using MonoRail and its SmartDispatchController.
We found ourselves thinking of how the same code would look in a SWF application.
We would be populating views, only those views would be interfaces that the various
forms/controls implemented. Well, this is exactly what we wanted in MonoRail, to wrap
the PropertyBag with an interface!
&lt;/p&gt;
&lt;p&gt;
After a few hours playing with Reflection.Emit, I had a code generator that would
take an interface:
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IEditMyProfileView
{ &lt;span class="kwrd"&gt;string&lt;/span&gt; Name { get; set; } DateTime Birthday { get; set;
} IList&amp;lt;TimeZone&amp;gt; TimeZones { get; set; } } &lt;/pre&gt;
&lt;p&gt;
And produce a class like the following:
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; EditMyProfileViewPropertyBagManipulator
: IEditMyProfileView { &lt;span class="kwrd"&gt;private&lt;/span&gt; IDictionary _bag; &lt;span class="kwrd"&gt;public&lt;/span&gt; EditMyProfileViewPropertyBagManipulator(IDictionary
bag) { _bag = bag; } &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name
{ get { &lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;)_bag[&lt;span class="str"&gt;"Name"&lt;/span&gt;];
} set { _bag[&lt;span class="str"&gt;"Name"&lt;/span&gt;] = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
} &lt;span class="kwrd"&gt;public&lt;/span&gt; DateTime Birthday { get { &lt;span class="kwrd"&gt;return&lt;/span&gt; (DateTime)_bag[&lt;span class="str"&gt;"Birthday"&lt;/span&gt;];
} set { _bag[&lt;span class="str"&gt;"Birthday"&lt;/span&gt;] = &lt;span class="kwrd"&gt;value&lt;/span&gt;;
} } &lt;span class="kwrd"&gt;public&lt;/span&gt; IList&amp;lt;TimeZone&amp;gt; TimeZones { get { &lt;span class="kwrd"&gt;return&lt;/span&gt; (IList&amp;lt;TimeZone&amp;gt;)_bag[&lt;span class="str"&gt;"TimeZones"&lt;/span&gt;];
} set { _bag[&lt;span class="str"&gt;"TimeZones"&lt;/span&gt;] = &lt;span class="kwrd"&gt;value&lt;/span&gt;;
} } } &lt;/pre&gt;
&lt;p&gt;
This has the advantage of keeping our interactions with the PropertyBag as type safe
as they can be. Changing the interface, breaks the build. Where as changing the type
of a value inserted into the PropertyBag will (hopefully) only break tests if even
that. This is another example of us trying to turn run-time failures into compile-time
failures.
&lt;/p&gt;
&lt;p&gt;
This kind of thing also makes tests more elegant. Instead of:
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;Assert.Equals(&lt;span class="str"&gt;"Jacob"&lt;/span&gt;, PropertyBag[&lt;span class="str"&gt;"Name"&lt;/span&gt;]);&lt;/pre&gt;
&lt;p&gt;
In our controller tests, we can continue to leverage the use of RhinoMocks to ensure
the views are properly initialized:
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; (_mocks.Unordered()) { _view.Name
= &lt;span class="str"&gt;"Jacob"&lt;/span&gt;; } _mocks.ReplayAll(); _controller.Action(); _mocks.Verify(_view);&lt;/pre&gt;
&lt;p&gt;
All we've done here is created a mock from the view interface, rather than emitting
the wrapper class. Again, another added benefit is if the view changes, compiling
the tests will also break. The sooner things break after a change the better, and
the build is pretty soon. Although, with ReSharper, it's nice to see red squiggles
appear as that's even sooner.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.eleutian.com/aggbug.ashx?id=ba5b573d-9863-456f-8e0d-be8871883eca" /&gt;</description>
      <comments>http://blog.eleutian.com/CommentView,guid,ba5b573d-9863-456f-8e0d-be8871883eca.aspx</comments>
      <category>code generation</category>
      <category>development</category>
      <category>monorail</category>
      <category>emit</category>
    </item>
    <item>
      <trackback:ping>http://blog.eleutian.com/Trackback.aspx?guid=088e158b-cd3c-4920-8df5-a3628013cc1d</trackback:ping>
      <pingback:server>http://blog.eleutian.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.eleutian.com/PermaLink,guid,088e158b-cd3c-4920-8df5-a3628013cc1d.aspx</pingback:target>
      <dc:creator>Jacob</dc:creator>
      <wfw:comment>http://blog.eleutian.com/CommentView,guid,088e158b-cd3c-4920-8df5-a3628013cc1d.aspx</wfw:comment>
      <wfw:commentRss>http://blog.eleutian.com/SyndicationService.asmx/GetEntryCommentsRss?guid=088e158b-cd3c-4920-8df5-a3628013cc1d</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I was trying to think of a way to introduce this post, and I realize that here at
Eleutian, we hate strings. We don't hate all strings, it's mostly string literals
that we hate. Not even all string literals. But most of them. A good portion of the
work we do to make our code more solid involves removing string literals. Anybody
familiar with MonoRail has seen lines similar to the following:
</p>
        <pre class="csharpcode">RenderView(<span class="str">"Home"</span>, <span class="str">"Action"</span>);</pre>
        <pre class="csharpcode">
          <span class="kwrd">&lt;</span>
          <span class="html">a</span>
          <span class="attr">href</span>
          <span class="kwrd">="${siteRoot}/Home/Action.rails"</span>
          <span class="kwrd">&gt;</span>...<span class="kwrd">&lt;/</span><span class="html">a</span><span class="kwrd">&gt;</span> ${UrlHelper.LinkTo("Home",
"Action")}</pre>
        <p>
And so on, see all those string literals that refer to things that aren't really string
literals? At first glance, we can get rid of the Controller string by doing something
with typeof(HomeController).Name and chopping off the Controller suffix. That'd
be an ugly static method call everywhere and still leaves "Action" to be dealt with.
We want things to break if HomeController changes names and we want to know where
HomeController is referenced.
</p>
        <p>
          <strong>One of our rules is to turn potential run-time errors into potential
compile time errors if at all possible.</strong>
        </p>
        <p>
It's funny, but the compiler is our first test, and a good one at that. We found ourselves
using those controller names, area names, and action names in a variety of situations
- redirections, view rendering, generating url's in the views, etc... Anytime I see
this I'm annoyed:
</p>
        <pre class="csharpcode">Redirect(<span class="str">"AnotherAction.rails?parameter=34"</span>);</pre>
        <p>
or even worse:
</p>
        <pre>Dictionary query = <span class="kwrd">new</span> Dictionary(); query[<span class="str">"parameter"</span>]
= 34; Redirect(<span class="str">"AnotherAction.rails"</span>, query);</pre>
        <p>
You'll notice that our life would be much easier if methods were first-class objects.
They aren't in C# 2.0... or even in 3.0 (without lambda functions) and so
this is where we are.
</p>
        <p>
Aaron and I talked things over, complaining on end about how frustrating things were.
Our problem boiled down to turning the controller action's into something we could
reference, so we decided to try a little code generation magic. We wanted to be able
to write code like the following:
</p>
        <pre class="csharpcode">MyActions.Action().Render()

Site.AdministrativeArea.Home.Action(24, <span class="str">"Jacob"</span>).Redirect()</pre>
        <p>
And so on. In order to do this we have a tool that runs as a pre-build step that does
the following:
</p>
        <ul>
          <li>
Walks the source tree, parsing *.cs files, looking for controllers. We have to parse
source, we can't use reflection because the same source files we're parsing will be
using this generated code. 
</li>
          <li>
Look for public methods (the actions) on the controller. 
</li>
          <li>
Generates a class (HomeControllerNode) that has a method, with the same prototype
as the action, that returns a ControllerActionReference:</li>
        </ul>
        <pre class="csharpcode">
          <span class="kwrd">public</span>
          <span class="kwrd">partial</span>
          <span class="kwrd">class</span> HomeControllerNode
{ <span class="kwrd">private</span> IControllerServices _services; <span class="kwrd">public</span> HomeControllerNode(IControllerServices
services) { <span class="kwrd">this</span>._services = services; } <span class="kwrd">public</span><span class="kwrd">virtual</span> HomeControllerViewsNode
Views { get { <span class="kwrd">return</span><span class="kwrd">new</span> HomeControllerViewsNode(<span class="kwrd">this</span>._services);
} } [System.Diagnostics.DebuggerNonUserCodeAttribute()] <span class="kwrd">public</span><span class="kwrd">virtual</span> ControllerActionReference
SomeAction() { <span class="kwrd">return</span><span class="kwrd">this</span>._services.ControllerReferenceFactory.CreateActionReference(<span class="kwrd">this</span>._services.Controller, <span class="kwrd">typeof</span>(HomeController), <span class="str">"Home"</span>, <span class="str">"Administrative"</span>, <span class="str">"SomeAction"</span>, <span class="kwrd">new</span> ActionArgument[0]);
} [System.Diagnostics.DebuggerNonUserCodeAttribute()] <span class="kwrd">public</span><span class="kwrd">virtual</span> ControllerActionReference
AnotherAction(<span class="kwrd">string</span> name) { <span class="kwrd">return</span><span class="kwrd">this</span>._services.ControllerReferenceFactory.CreateActionReference(<span class="kwrd">this</span>._services.Controller, <span class="kwrd">typeof</span>(HomeController), <span class="str">"Home"</span>, <span class="str">"Administrative"</span>, <span class="str">"AnotherAction"</span>, <span class="kwrd">new</span> ActionArgument[]
{ <span class="kwrd">new</span> ActionArgument(<span class="str">"name"</span>, <span class="kwrd">typeof</span>(<span class="kwrd">string</span>),
name)}); } } }</pre>
        <ul>
          <li>
Generates a stub class for area's with properties for each controller in that area
(they return HomeControllerNode instances) We introduce a default root area that all
top level controllers and other areas are children of:</li>
        </ul>
        <pre class="csharpcode">
          <span class="kwrd">public</span>
          <span class="kwrd">partial</span>
          <span class="kwrd">class</span> AdministrativeAreaNode
{ <span class="kwrd">private</span> IControllerServices _services; <span class="kwrd">private</span> HomeControllerNode
_home; <span class="kwrd">public</span> AdministrativeAreaNode(IControllerServices
services) { <span class="kwrd">this</span>._services = services; <span class="kwrd">this</span>._home
= <span class="kwrd">new</span> HomeControllerNode(<span class="kwrd">this</span>._services);
} <span class="kwrd">public</span><span class="kwrd">virtual</span> HomeControllerNode
Home { get { <span class="kwrd">return</span><span class="kwrd">this</span>._home;
} } }</pre>
        <ul>
          <li>
Walks the Views subdirectory looking for *.brail files mapping them onto their controllers. 
</li>
          <li>
Generates a class (HomeControllerViewsNode) with methods for each view that return
a ControllerViewReference.</li>
        </ul>
        <pre class="csharpcode">
          <span class="kwrd">public</span>
          <span class="kwrd">partial</span>
          <span class="kwrd">class</span> HomeControllerViewsNode
{ <span class="kwrd">private</span> IControllerServices _services; <span class="kwrd">public</span> HomeControllerViewsNode(IControllerServices
services) { <span class="kwrd">this</span>._services = services; } [System.Diagnostics.DebuggerNonUserCodeAttribute()] <span class="kwrd">public</span><span class="kwrd">virtual</span> ControllerViewReference
SomeAction { get { <span class="kwrd">return</span><span class="kwrd">this</span>._services.ControllerReferenceFactory.CreateViewReference(<span class="kwrd">this</span>._services.Controller, <span class="kwrd">typeof</span>(HomeController), <span class="str">"Home"</span>, <span class="str">"Administrative"</span>, <span class="str">"SomeAction"</span>);
} } }</pre>
        <ul>
          <li>
Generates a partial class for the controller class itself with two properties - MyViews
and MyActions that return the ControllerNode and ControllerViewsNode instances for
that controller.</li>
        </ul>
        <pre class="csharpcode">
          <span class="kwrd">public</span>
          <span class="kwrd">partial</span>
          <span class="kwrd">class</span> HomeController
{ <span class="kwrd">public</span><span class="kwrd">virtual</span> HomeControllerNode
MyActions { get { <span class="kwrd">return</span><span class="kwrd">new</span> HomeControllerNode(<span class="kwrd">this</span>.ControllerServices);
} } <span class="kwrd">public</span><span class="kwrd">virtual</span> HomeControllerViewsNode
MyViews { get { <span class="kwrd">return</span><span class="kwrd">new</span> HomeControllerViewsNode(<span class="kwrd">this</span>.ControllerServices);
} } <span class="kwrd">protected</span><span class="kwrd">override</span><span class="kwrd">void</span> PerformGeneratedInitialize()
{ <span class="kwrd">base</span>.PerformGeneratedInitialize(); <span class="kwrd">this</span>.PropertyBag[<span class="str">"MyViews"</span>]
= <span class="kwrd">this</span>.MyViews; <span class="kwrd">this</span>.PropertyBag[<span class="str">"MyActions"</span>]
= <span class="kwrd">this</span>.MyActions; } }</pre>
        <p>
In the generated code, we pass a reference to an IControllerServices implementation
down through the hierarchy, which provides the ControllerReferenceFactory that creates
the ControllerActionReference and ControllerViewReference objects. Our EleutianController
class has a property on it <em>-</em> Site, that returns the RootAreaNode so the top
of the site can be reached from anywhere. This is also always placed into the controller's
PropertyBag, along with MyActions and MyViews. The PerformGeneratedInitialize method,
that's called in our base class so that each controller can add it's own MyViews and
MyActions, which don't live in the base class.
</p>
        <p>
Our ControllerActionReference class has Redirect and Transfer methods as well
as a Url property. So now we can do the following:
</p>
        <pre class="csharpcode">
          <span class="kwrd">&lt;</span>
          <span class="html">a</span>
          <span class="attr">href</span>
          <span class="kwrd">="${Site.HomeController.Action(200,
true).Url}"</span>
          <span class="kwrd">&gt;</span>...<span class="kwrd">&lt;/</span><span class="html">a</span><span class="kwrd">&gt;</span></pre>
        <p>
ControllerViewReference has a Render method that does the appropriate RenderView call
on the controller. Now we've accomplished a lot of things:
</p>
        <ol>
          <li>
No more string literals. If we rename something, the build fails. Our views will fail
when they're opened and not when links are followed, it is pretty easy to test that
a view compiles. 
</li>
          <li>
All URLs for redirections/transfers are always well formed and include necessary parameters
with proper type checking. 
</li>
          <li>
Provided ourselves with Intellisense when building URLs in tests and controllers.
(Sexy? Yes.) 
</li>
        </ol>
        <p>
Speaking of testing, in our controller tests we have a custom IControllerReferenceFactory
that returns mock ControllerActionReference instances (via RhinoMocks) So now redirections,
transfers and view renderings are just mocked method calls:
</p>
        <pre class="csharpcode">
          <span class="kwrd">using</span> (_mocks.Unordered()) { _controller.MyViews.AnotherView.Render();
} _mocks.ReplayAll(); _controller.SomeActionThatRendersAnotherView(); _mocks.VerifyAll();</pre>
        <p>
Which is much cleaner than string comparisons on <font face="Courier New">_controller.SelectedViewName</font>,
especially if a redirect with parameters is expected in an action. This has simplified
our life and given us incredible peace of mind, well worth the time to implement -
which was relatively simple. Whew.
</p>
        <img width="0" height="0" src="http://blog.eleutian.com/aggbug.ashx?id=088e158b-cd3c-4920-8df5-a3628013cc1d" />
      </body>
      <title>We Hate String Literals</title>
      <guid isPermaLink="false">http://blog.eleutian.com/PermaLink,guid,088e158b-cd3c-4920-8df5-a3628013cc1d.aspx</guid>
      <link>http://blog.eleutian.com/2007/01/30/WeHateStringLiterals.aspx</link>
      <pubDate>Tue, 30 Jan 2007 02:45:08 GMT</pubDate>
      <description>&lt;p&gt;
I was trying to think of a way to introduce this post, and I realize that here at
Eleutian, we hate strings. We don't hate all strings, it's mostly string literals
that we hate. Not even all string literals. But most of them. A good portion of the
work we do to make our code more solid involves removing string literals. Anybody
familiar with MonoRail has seen&amp;nbsp;lines similar to the following:
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;RenderView(&lt;span class="str"&gt;"Home"&lt;/span&gt;, &lt;span class="str"&gt;"Action"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;a&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="${siteRoot}/Home/Action.rails"&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;a&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; ${UrlHelper.LinkTo("Home",
"Action")}&lt;/pre&gt;
&lt;p&gt;
And so on, see all those string literals that refer to things that aren't really string
literals? At first glance, we can get rid of the Controller string by doing something
with typeof(HomeController).Name&amp;nbsp;and chopping off the Controller suffix. That'd
be an ugly static method call everywhere and still leaves "Action" to be dealt with.
We want things to break if HomeController changes names and we want to know where
HomeController is referenced.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;One of our&amp;nbsp;rules is to&amp;nbsp;turn potential run-time errors into potential
compile time errors if at all possible.&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
It's funny, but the compiler is our first test, and a good one at that. We found ourselves
using those controller names, area names, and action names in a variety of situations
- redirections, view rendering, generating url's in the views, etc... Anytime I see
this I'm annoyed:
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;Redirect(&lt;span class="str"&gt;"AnotherAction.rails?parameter=34"&lt;/span&gt;);&lt;/pre&gt;
&lt;p&gt;
or even worse:
&lt;/p&gt;
&lt;pre&gt;Dictionary query = &lt;span class="kwrd"&gt;new&lt;/span&gt; Dictionary(); query[&lt;span class="str"&gt;"parameter"&lt;/span&gt;]
= 34; Redirect(&lt;span class="str"&gt;"AnotherAction.rails"&lt;/span&gt;, query);&lt;/pre&gt;
&lt;p&gt;
You'll notice that our life would be much easier if methods were first-class objects.
They aren't in C# 2.0... or even&amp;nbsp;in 3.0&amp;nbsp;(without lambda functions) and so
this is where we are.
&lt;/p&gt;
&lt;p&gt;
Aaron and I talked things over, complaining on end about how frustrating things were.
Our problem boiled down to turning the controller action's into something we could
reference, so we decided to try a little code generation magic. We wanted to be able
to write code like the following:
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;MyActions.Action().Render()

Site.AdministrativeArea.Home.Action(24, &lt;span class="str"&gt;"Jacob"&lt;/span&gt;).Redirect()&lt;/pre&gt;
&lt;p&gt;
And so on. In order to do this we have a tool that runs as a pre-build step that does
the following:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Walks the source tree, parsing *.cs files, looking for controllers. We have to parse
source, we can't use reflection because the same source files we're parsing will be
using this generated code. 
&lt;/li&gt;
&lt;li&gt;
Look for public methods (the actions) on the controller. 
&lt;/li&gt;
&lt;li&gt;
Generates a class (HomeControllerNode) that has a method, with the same prototype
as the action, that returns a ControllerActionReference:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; HomeControllerNode
{ &lt;span class="kwrd"&gt;private&lt;/span&gt; IControllerServices _services; &lt;span class="kwrd"&gt;public&lt;/span&gt; HomeControllerNode(IControllerServices
services) { &lt;span class="kwrd"&gt;this&lt;/span&gt;._services = services; } &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; HomeControllerViewsNode
Views { get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; HomeControllerViewsNode(&lt;span class="kwrd"&gt;this&lt;/span&gt;._services);
} } [System.Diagnostics.DebuggerNonUserCodeAttribute()] &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; ControllerActionReference
SomeAction() { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;._services.ControllerReferenceFactory.CreateActionReference(&lt;span class="kwrd"&gt;this&lt;/span&gt;._services.Controller, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(HomeController), &lt;span class="str"&gt;"Home"&lt;/span&gt;, &lt;span class="str"&gt;"Administrative"&lt;/span&gt;, &lt;span class="str"&gt;"SomeAction"&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; ActionArgument[0]);
} [System.Diagnostics.DebuggerNonUserCodeAttribute()] &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; ControllerActionReference
AnotherAction(&lt;span class="kwrd"&gt;string&lt;/span&gt; name) { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;._services.ControllerReferenceFactory.CreateActionReference(&lt;span class="kwrd"&gt;this&lt;/span&gt;._services.Controller, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(HomeController), &lt;span class="str"&gt;"Home"&lt;/span&gt;, &lt;span class="str"&gt;"Administrative"&lt;/span&gt;, &lt;span class="str"&gt;"AnotherAction"&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; ActionArgument[]
{ &lt;span class="kwrd"&gt;new&lt;/span&gt; ActionArgument(&lt;span class="str"&gt;"name"&lt;/span&gt;, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt;),
name)}); } } }&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
Generates a stub class for area's with properties for each controller in that area
(they return HomeControllerNode instances) We introduce a default root area that all
top level controllers and other areas are children of:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AdministrativeAreaNode
{ &lt;span class="kwrd"&gt;private&lt;/span&gt; IControllerServices _services; &lt;span class="kwrd"&gt;private&lt;/span&gt; HomeControllerNode
_home; &lt;span class="kwrd"&gt;public&lt;/span&gt; AdministrativeAreaNode(IControllerServices
services) { &lt;span class="kwrd"&gt;this&lt;/span&gt;._services = services; &lt;span class="kwrd"&gt;this&lt;/span&gt;._home
= &lt;span class="kwrd"&gt;new&lt;/span&gt; HomeControllerNode(&lt;span class="kwrd"&gt;this&lt;/span&gt;._services);
} &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; HomeControllerNode
Home { get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;._home;
} } }&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
Walks the Views subdirectory looking for *.brail files mapping them onto their controllers. 
&lt;/li&gt;
&lt;li&gt;
Generates a class (HomeControllerViewsNode) with methods for each view that return
a ControllerViewReference.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; HomeControllerViewsNode
{ &lt;span class="kwrd"&gt;private&lt;/span&gt; IControllerServices _services; &lt;span class="kwrd"&gt;public&lt;/span&gt; HomeControllerViewsNode(IControllerServices
services) { &lt;span class="kwrd"&gt;this&lt;/span&gt;._services = services; } [System.Diagnostics.DebuggerNonUserCodeAttribute()] &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; ControllerViewReference
SomeAction { get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;._services.ControllerReferenceFactory.CreateViewReference(&lt;span class="kwrd"&gt;this&lt;/span&gt;._services.Controller, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(HomeController), &lt;span class="str"&gt;"Home"&lt;/span&gt;, &lt;span class="str"&gt;"Administrative"&lt;/span&gt;, &lt;span class="str"&gt;"SomeAction"&lt;/span&gt;);
} } }&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
Generates a partial class for the controller class itself with two properties - MyViews
and MyActions that return the ControllerNode and ControllerViewsNode instances for
that controller.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; HomeController
{ &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; HomeControllerNode
MyActions { get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; HomeControllerNode(&lt;span class="kwrd"&gt;this&lt;/span&gt;.ControllerServices);
} } &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; HomeControllerViewsNode
MyViews { get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; HomeControllerViewsNode(&lt;span class="kwrd"&gt;this&lt;/span&gt;.ControllerServices);
} } &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; PerformGeneratedInitialize()
{ &lt;span class="kwrd"&gt;base&lt;/span&gt;.PerformGeneratedInitialize(); &lt;span class="kwrd"&gt;this&lt;/span&gt;.PropertyBag[&lt;span class="str"&gt;"MyViews"&lt;/span&gt;]
= &lt;span class="kwrd"&gt;this&lt;/span&gt;.MyViews; &lt;span class="kwrd"&gt;this&lt;/span&gt;.PropertyBag[&lt;span class="str"&gt;"MyActions"&lt;/span&gt;]
= &lt;span class="kwrd"&gt;this&lt;/span&gt;.MyActions; } }&lt;/pre&gt;
&lt;p&gt;
In the generated code, we pass a reference to&amp;nbsp;an IControllerServices implementation
down through the hierarchy, which provides the ControllerReferenceFactory that creates
the ControllerActionReference and ControllerViewReference objects. Our EleutianController
class has a property on it &lt;em&gt;-&lt;/em&gt; Site, that returns the RootAreaNode so the top
of the site can be reached from anywhere. This is also always placed into the controller's
PropertyBag, along with MyActions and MyViews. The PerformGeneratedInitialize method,
that's called in our base class so that each controller can add it's own MyViews and
MyActions, which don't live in the base class.
&lt;/p&gt;
&lt;p&gt;
Our ControllerActionReference class has Redirect and&amp;nbsp;Transfer methods as well
as a Url property. So now we can do the following:
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;a&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="${Site.HomeController.Action(200,
true).Url}"&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;a&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
ControllerViewReference has a Render method that does the appropriate RenderView call
on the controller. Now we've accomplished a lot of things:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
No more string literals. If we rename something, the build fails. Our views will fail
when they're opened and not when links are followed, it is pretty easy to test that
a view compiles. 
&lt;/li&gt;
&lt;li&gt;
All URLs for redirections/transfers are always well formed and include necessary parameters
with proper type checking. 
&lt;/li&gt;
&lt;li&gt;
Provided ourselves with Intellisense when building URLs in tests and controllers.
(Sexy? Yes.) 
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
Speaking of testing,&amp;nbsp;in our controller tests we have a custom IControllerReferenceFactory
that returns mock ControllerActionReference instances (via RhinoMocks) So now redirections,
transfers and view renderings are just mocked method calls:
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; (_mocks.Unordered()) { _controller.MyViews.AnotherView.Render();
} _mocks.ReplayAll(); _controller.SomeActionThatRendersAnotherView(); _mocks.VerifyAll();&lt;/pre&gt;
&lt;p&gt;
Which is much cleaner than string comparisons on &lt;font face="Courier New"&gt;_controller.SelectedViewName&lt;/font&gt;,
especially if a redirect with parameters is expected in an action. This has simplified
our life and given us incredible peace of mind, well worth the time to implement -
which was relatively simple. Whew.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.eleutian.com/aggbug.ashx?id=088e158b-cd3c-4920-8df5-a3628013cc1d" /&gt;</description>
      <comments>http://blog.eleutian.com/CommentView,guid,088e158b-cd3c-4920-8df5-a3628013cc1d.aspx</comments>
      <category>code generation</category>
      <category>development</category>
      <category>monorail</category>
      <category>productivity</category>
      <category>tools</category>
    </item>
    <item>
      <trackback:ping>http://blog.eleutian.com/Trackback.aspx?guid=2888d63c-96c0-4545-b380-331fb94c16f2</trackback:ping>
      <pingback:server>http://blog.eleutian.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.eleutian.com/PermaLink,guid,2888d63c-96c0-4545-b380-331fb94c16f2.aspx</pingback:target>
      <dc:creator>Aaron</dc:creator>
      <wfw:comment>http://blog.eleutian.com/CommentView,guid,2888d63c-96c0-4545-b380-331fb94c16f2.aspx</wfw:comment>
      <wfw:commentRss>http://blog.eleutian.com/SyndicationService.asmx/GetEntryCommentsRss?guid=2888d63c-96c0-4545-b380-331fb94c16f2</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Previously I mentioned that we switched to MonoRail for all of our new features. Well,
MonoRail doesn't make page localization any easier than Web Forms does.  As a
matter of fact, it actually breaks an important part of ASP.NET's localization (something
I should probably submit a patch for, heh).  Basically, the DefaultResourceFactory
in MonoRail creates IResources that wrap ResourceSets, which will not resolve resources
to their parent resource. In other words, if you have Res.ko-KR.resx which defines
String1 and Res.resx which defines String1 and String2, then calling GetString
on a ResourceSet when your locale is ko-KR with String1 will work, but String2 will
fail.  Calling GetString with any other locale, will return the String2 from
Res.resx. To get around this, we created an IResourceFactory that returns IResources
that wrap ResourceManagers instead of ResourceSets, which are capable of properly
traversing the resource tree.  I'll probably submit this code soon. 
</p>
        <p>
Anyways, in order to localize with MonoRail, you still need to create your resx file,
add an attribute to your controller to map that resx file to something in your view's
property bag, and create, name and initialize each string in your resx file.   
</p>
        <p>
What we did was create a new generator like the one mentioned in my previous post
that converts mybrail files to brail files.  All it does is convert this: 
</p>
        <pre class="csharpcode">${g.Test: Global Text} <span class="kwrd">&lt;</span><span class="html">br</span><span class="kwrd">/&gt;</span> ${v.ViewTest:
View Text} <span class="kwrd">&lt;</span><span class="html">br</span><span class="kwrd">/&gt;</span> ${c.ControllerTest:
Controller Text} <span class="kwrd">&lt;</span><span class="html">br</span><span class="kwrd">/&gt;</span></pre>
        <pre class="csharpcode">
        </pre>
        <p>
To this: 
</p>
        <pre class="csharpcode">${g.Test} <span class="kwrd">&lt;</span><span class="html">br</span><span class="kwrd">/&gt;</span> ${c.Localization_ViewTest} <span class="kwrd">&lt;</span><span class="html">br</span><span class="kwrd">/&gt;</span> ${c.ControllerTest} <span class="kwrd">&lt;</span><span class="html">br</span><span class="kwrd">/&gt;</span> </pre>
        <p>
Now a few things happened here:
</p>
        <ol>
          <li>
A file called Global.resx was created. 
</li>
          <li>
A file called Test.resx was created (Test is the name of the controller) 
</li>
          <li>
A resource called Test was added to Global.resx and initialized with the value "Global
Text" 
</li>
          <li>
A resource called ControllerTest was added to the Test.resx and initialized with the
value "Controller Text" 
</li>
          <li>
A resource called Localization_ViewTest (Localization is the name of the view) was
added to Test.resx and initialized with the value "View Text" 
</li>
          <li>
v.ViewTest was converted to c.Localization_ViewTest</li>
        </ol>
        <p>
Essentially, what you end up with, is one resx for your global strings, and one resx
per controller, with view specific strings being stored in the controller resx with
ViewName_ prefixed to them.  There's still one piece missing to the puzzle, which
is how do the views know what g and c are? Do we attribute each controller with
a g resource and a c resource? No... that would be too much work for us. Instead
what we do is define a new IControllerDescriptorProvider that wraps a DefaultControllerDescriptorProvider
and adds appropriate ResourceDescriptors to the Resources collection of the descriptor
built by the DefaultControllerDescriptorProvider.   
</p>
        <p>
There is some room for improvement, like gracefully handling the case where you define
and give a value for a resource twice in the same file or two seperate files, e.g.
${g.Test: Hi} ${g.Test: Hello}.  In this case, g.Test will be Hello.  In
the case where they're in seperate files, it'll depend on which one was saved last
(ew).  A decent way around this would be to detect this happening and pop
a message box if you try to do this.
</p>
        <img width="0" height="0" src="http://blog.eleutian.com/aggbug.ashx?id=2888d63c-96c0-4545-b380-331fb94c16f2" />
      </body>
      <title>MonoRail Brail preprocessing</title>
      <guid isPermaLink="false">http://blog.eleutian.com/PermaLink,guid,2888d63c-96c0-4545-b380-331fb94c16f2.aspx</guid>
      <link>http://blog.eleutian.com/2007/01/27/MonoRailBrailPreprocessing.aspx</link>
      <pubDate>Sat, 27 Jan 2007 22:05:36 GMT</pubDate>
      <description>&lt;p&gt;
Previously I mentioned that we switched to MonoRail for all of our new features. Well,
MonoRail doesn't make page localization any easier than Web Forms does.&amp;nbsp; As a
matter of fact, it actually breaks an important part of ASP.NET's localization (something
I should probably submit a patch for, heh).&amp;nbsp; Basically, the DefaultResourceFactory
in MonoRail creates IResources that wrap ResourceSets, which will not resolve resources
to their parent resource. In other words, if you have Res.ko-KR.resx which defines
String1 and Res.resx&amp;nbsp;which defines String1 and String2, then calling GetString
on a ResourceSet when your locale is ko-KR with String1 will work, but String2 will
fail.&amp;nbsp; Calling GetString with any other locale, will return the String2 from
Res.resx.&amp;nbsp;To get around this, we created an IResourceFactory that returns IResources
that wrap ResourceManagers instead of ResourceSets, which are capable of properly
traversing the resource tree.&amp;nbsp; I'll probably submit this code soon.&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
Anyways, in order to localize with MonoRail, you still need to create your resx file,
add an attribute to your controller to map that resx file to something in your view's
property bag, and create, name and initialize each string in your resx file.&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
What we did was create a new generator like the one mentioned in my previous post
that converts mybrail files to brail files.&amp;nbsp; All it does is convert this:&amp;nbsp;
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;${g.Test: Global Text} &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt; ${v.ViewTest:
View Text} &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt; ${c.ControllerTest:
Controller Text} &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="csharpcode"&gt;&lt;/pre&gt;
&lt;p&gt;
To this:&amp;nbsp;
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;${g.Test} &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt; ${c.Localization_ViewTest} &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt; ${c.ControllerTest} &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;p&gt;
Now a few things happened here:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
A file called Global.resx was created. 
&lt;/li&gt;
&lt;li&gt;
A file called Test.resx was created (Test is the name of the controller) 
&lt;/li&gt;
&lt;li&gt;
A resource called Test was added to Global.resx and initialized with the value "Global
Text" 
&lt;/li&gt;
&lt;li&gt;
A resource called ControllerTest was added to the Test.resx and initialized with the
value "Controller Text" 
&lt;/li&gt;
&lt;li&gt;
A resource called Localization_ViewTest (Localization is the name of the view) was
added to Test.resx and initialized with the value "View Text" 
&lt;/li&gt;
&lt;li&gt;
v.ViewTest was converted to c.Localization_ViewTest&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
Essentially, what you end up with, is one resx for your global strings, and one resx
per controller, with view specific strings being stored in the controller resx with
ViewName_ prefixed to them.&amp;nbsp; There's still one piece missing to the puzzle, which
is how do the views know what g and c are?&amp;nbsp;Do we attribute each controller with
a g resource and a c resource?&amp;nbsp;No... that would be too much work for us.&amp;nbsp;Instead
what we do is define a new IControllerDescriptorProvider that wraps a DefaultControllerDescriptorProvider
and adds appropriate ResourceDescriptors to the Resources collection of the descriptor
built by the DefaultControllerDescriptorProvider.&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
There is some room for improvement, like gracefully handling the case where you define
and give a value for a resource twice in the same file or two seperate files, e.g.
${g.Test: Hi} ${g.Test: Hello}.&amp;nbsp; In this case, g.Test will be Hello.&amp;nbsp; In
the case where they're in seperate files, it'll depend on which one was saved last
(ew).&amp;nbsp; A&amp;nbsp;decent way around this would be to detect this happening and pop
a message box if you try to do this.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.eleutian.com/aggbug.ashx?id=2888d63c-96c0-4545-b380-331fb94c16f2" /&gt;</description>
      <comments>http://blog.eleutian.com/CommentView,guid,2888d63c-96c0-4545-b380-331fb94c16f2.aspx</comments>
      <category>code generation</category>
      <category>development</category>
      <category>localization</category>
      <category>monorail</category>
      <category>productivity</category>
      <category>tools</category>
    </item>
    <item>
      <trackback:ping>http://blog.eleutian.com/Trackback.aspx?guid=e1f2cae9-7693-4935-9be9-927946cc6cd2</trackback:ping>
      <pingback:server>http://blog.eleutian.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.eleutian.com/PermaLink,guid,e1f2cae9-7693-4935-9be9-927946cc6cd2.aspx</pingback:target>
      <dc:creator>Aaron</dc:creator>
      <wfw:comment>http://blog.eleutian.com/CommentView,guid,e1f2cae9-7693-4935-9be9-927946cc6cd2.aspx</wfw:comment>
      <wfw:commentRss>http://blog.eleutian.com/SyndicationService.asmx/GetEntryCommentsRss?guid=e1f2cae9-7693-4935-9be9-927946cc6cd2</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">One of the things we love to do is remove
tedium from code. That subject will probably be the topic of this post, and many of
our posts in the future I'm sure, as we've done a lot of things in that department. 
ASP.NET is lacking in a number of areas, as I'm sure most of you know.  It's
"strong point" is supposed to be its declarative nature--but that often leads to very
difficult to test pages.  Not only that, but it's declarative syntax leaves much
to be desired.  My primary complaint is with its verbosity.  There's nothing
simple about ASP.NET syntax.  Here's an example:<br /><br /><p><span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;">&lt;asp:HyperLink
runat=<span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);">"server"</span> ID=<span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);">"_lnkForgot"</span> NavigateUrl='~/ForgotPassword.aspx'
Text='&lt;%$ Resources: PageStrings, Login_lnkForgot_Text %&gt;' /&gt;</span></p><p><span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;"></span></p>
Now, let's complain a little.  First, we've got that runat="server" tag. 
Who's idea was that?  I mean, I understand why it's there, but how often are
you going to want &lt;asp:Anything&gt; to be sent to the client in that form? 
Wouldn't it make more sense to just ASSUME that &lt;anything:Anything&gt; was runat="server"
and just allow us to specify runat="client" and strip that attribute when rendering
if we really want to send that to the client? 
<br /><br />
Next, we've got the ID tag.  I don't really have a problem with that, it's implemented
just fine.  Then there's the NavigateUrl.  Notice the ~.  I love that. 
It's something that ASP.NET did right. It makes it a breeze to make pages location
agnostic... unless of course you want to use a non-asp control.  Then you've
got to use this lovely syntax:<br /><br /><p><span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;">&lt;img
src='&lt;%= ResolveClientUrl(<span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);">"~/Images/img.gif"</span>)
%&gt;' /&gt;</span></p><p><span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;"></span></p>
Ah yes, that just screams beautiful.  Now would it have really been that difficult
to replace ~ with ApplicationPath and let ~~ by as ~ in attributes?  
<br /><br />
OK, let's move on to my favorite subject--Globalization/Localization.  ASP.NET
2.0 has come a long way on this front.  It's much easier to localize your pages
the way ASP.NET 2.0 wants you to than the way ASP.NET 1.0 wanted you to, especially
with the new meta:resourcekey attribute and automatic generation of resources. 
Unfortunately, it's still not as simple and elegant as it could be.  If you don't
want to use the meta:resource attribute (because you have a shared string) then you
have to use the lovely Resources: syntax seen up above, and you have to manually create
your resx file, and manually name and fill in your default locale value.  If
you want to localize a literal, you get to use wonderfully verbose &lt;asp:Localize&gt;
control.  
<br /><br />
Another complaint that isn't demonstrated in the example is with Databinding. 
The databinding syntax is pretty clean, I don't have any complaints about that, but
its implementation is a bit poor, mainly because of its use of uncached reflection. 
It's been a while since I benchmarked it, but if my memory serves me (and often it
doesn't) then it took about 30% longer to databind using the reflexive &lt;%# Field
%&gt; syntax than it did to use &lt;%# ((Class)Container.DataItem).Field %&gt;. 
Who wants to write all of the latter, especially with autocomplete in aspx pages being
flaky at best?<br /><br />
So how could ASP.NET be less verbose and more elegant? How could WE make it better
without being able to extend the many internal and sealed classes that make up the
webforms engine?<br /><br />
Preprocessing!<br /><br />
Here's an overview of what you do.<br /><ol><li>
Create a generator that extends Microsoft.CustomTool.BaseCodeGeneratorWithSite for
.aspx files and do your preprocessing here.<br /></li><li>
Create a wizard that extends Microsoft.VisualStudio.TemplateWizard.IWizard to set
up a file hiearchy like this: 
<ul><li>
Page.myaspx 
<ul><li>
Page.aspx 
<ul><li>
Page.aspx.cs 
</li><li>
Page.aspx.designer.cs</li></ul></li></ul></li></ul></li><li>
Create an ItemTemplate for your item that contains these files and sets your custom
tool to the generator you created in step one. 
</li><li>
Add a new myaspx to your project and make sure you don't ever modify the aspx directly
(this takes some getting used to)</li></ol>
So what are some things you could filter/generate/preprocess?<br /><ul><li>
Add runat="server" tags to all &lt;anything:anything&gt; nodes that don't have it. 
</li><li>
Replace "~/blah" with an appropriate call to ResolveClientUrl 
</li><li>
Do some localization magic</li></ul><p><span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;"></span></p><p><font face="Courier New"><span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;">&lt;asp:HyperLink
ID=<span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);">"_lnkForgot"</span> NavigateUrl='~/ForgotPassword.aspx'
Text=<span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);">"$:Forgot
your Username or Password?"</span> /&gt;</span></font></p><p><span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;"></span></p>
          This is actually the markup that we wrote
to generate the markup at the beginning of this post.  See the $:?  That
tells the generator to create a resource in PageStrings.resx with the format Page_ID_Property
that has the value that appears after the $:.  You never need to touch that resx
file.  You can just write your markup, define your strings, and not be interrupted,
or even have to name your strings.  If you want to name your strings, say something
global.  Just do "$Name: This is a string" and if you want to use it later just
use "$Name".<br /><ul><li>
Make databinding strongly typed.  This requires a bit of help, as you can't easily
infer the type being bound by just inspecting the source.  Our solution was to
add a DataType="Class" attribute to whatever the repeating control was.  For
example: 
<p><span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;"></span><br /><font face="Courier New"><span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;">&lt;asp:Repeater
ID=<span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);">"repeater"</span> DataType=<span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);">"BoundClass"</span>&gt;<br />
  &lt;ItemTemplate&gt;<br />
    &lt;asp:Label ID=<span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);">"textBox"</span> Text='&lt;%#@Name%&gt;'
/&gt;<br />
  &lt;/ItemTemplate&gt;<br />
&lt;/asp:Repeater&gt;</span></font></p></li></ul><blockquote><p>
Notice the @ in the &lt;%#%&gt; tag.  That gets replaced with ((BoundClass)Container.DataItem),
so you can do things like &lt;%# String.Format("{0} {1}", @FirstName, @LastName) %&gt;<br /><br />
So that's how we made ASP.NET more manageable.  Now, there are still several
issues with ASP.NET WebForms that caused us to eventually switch to MonoRail, which
also benefits from preprocessing, but I'll post on that later.
</p></blockquote><img width="0" height="0" src="http://blog.eleutian.com/aggbug.ashx?id=e1f2cae9-7693-4935-9be9-927946cc6cd2" /></body>
      <title>ASP.NET page preprocessing</title>
      <guid isPermaLink="false">http://blog.eleutian.com/PermaLink,guid,e1f2cae9-7693-4935-9be9-927946cc6cd2.aspx</guid>
      <link>http://blog.eleutian.com/2007/01/27/ASPNETPagePreprocessing.aspx</link>
      <pubDate>Sat, 27 Jan 2007 16:47:03 GMT</pubDate>
      <description>One of the things we love to do is remove tedium from code. That subject will probably be the topic of this post, and many of our posts in the future I'm sure, as we've done a lot of things in that department.&amp;nbsp; ASP.NET is lacking in a number of areas, as I'm sure most of you know.&amp;nbsp; It's "strong point" is supposed to be its declarative nature--but that often leads to very difficult to test pages.&amp;nbsp; Not only that, but it's declarative syntax leaves much to be desired.&amp;nbsp; My primary complaint is with its verbosity.&amp;nbsp; There's nothing simple about ASP.NET syntax.&amp;nbsp; Here's an example:&lt;br&gt;
&lt;br&gt;
&lt;p&gt;
&lt;span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;"&gt;&amp;lt;asp:HyperLink
runat=&lt;span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);"&gt;"server"&lt;/span&gt; ID=&lt;span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);"&gt;"_lnkForgot"&lt;/span&gt; NavigateUrl='~/ForgotPassword.aspx'
Text='&amp;lt;%$ Resources: PageStrings, Login_lnkForgot_Text %&amp;gt;' /&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;"&gt;&lt;/span&gt;
&lt;/p&gt;
Now, let's complain a little.&amp;nbsp; First, we've got that runat="server" tag.&amp;nbsp;
Who's idea was that?&amp;nbsp; I mean, I understand why it's there, but how often are
you going to want &amp;lt;asp:Anything&amp;gt; to be sent to the client in that form?&amp;nbsp;
Wouldn't it make more sense to just ASSUME that &amp;lt;anything:Anything&amp;gt; was runat="server"
and just allow us to specify runat="client" and strip that attribute when rendering
if we really want to send that to the client? 
&lt;br&gt;
&lt;br&gt;
Next, we've got the ID tag.&amp;nbsp; I don't really have a problem with that, it's implemented
just fine.&amp;nbsp; Then there's the NavigateUrl.&amp;nbsp; Notice the ~.&amp;nbsp; I love that.&amp;nbsp;
It's something that ASP.NET did right. It makes it a breeze to make pages location
agnostic... unless of course you want to use a non-asp control.&amp;nbsp; Then you've
got to use this lovely syntax:&lt;br&gt;
&lt;br&gt;
&lt;p&gt;
&lt;span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;"&gt;&amp;lt;img
src='&amp;lt;%= ResolveClientUrl(&lt;span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);"&gt;"~/Images/img.gif"&lt;/span&gt;)
%&amp;gt;' /&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;"&gt;&lt;/span&gt;
&lt;/p&gt;
Ah yes, that just screams beautiful.&amp;nbsp; Now would it have really been that difficult
to replace ~ with ApplicationPath and let ~~ by as ~ in attributes?&amp;nbsp; 
&lt;br&gt;
&lt;br&gt;
OK, let's move on to my favorite subject--Globalization/Localization.&amp;nbsp; ASP.NET
2.0 has come a long way on this front.&amp;nbsp; It's much easier to localize your pages
the way ASP.NET 2.0 wants you to than the way ASP.NET 1.0 wanted you to, especially
with the new meta:resourcekey attribute and automatic generation of resources.&amp;nbsp;
Unfortunately, it's still not as simple and elegant as it could be.&amp;nbsp; If you don't
want to use the meta:resource attribute (because you have a shared string) then you
have to use the lovely Resources: syntax seen up above, and you have to manually create
your resx file, and manually name and fill in your default locale value.&amp;nbsp; If
you want to localize a literal, you get to use wonderfully verbose &amp;lt;asp:Localize&amp;gt;
control.&amp;nbsp; 
&lt;br&gt;
&lt;br&gt;
Another complaint that isn't demonstrated in the example is with Databinding.&amp;nbsp;
The databinding syntax is pretty clean, I don't have any complaints about that, but
its implementation is a bit poor, mainly because of its use of uncached reflection.&amp;nbsp;
It's been a while since I benchmarked it, but if my memory serves me (and often it
doesn't) then it took about 30% longer to databind using the reflexive &amp;lt;%# Field
%&amp;gt; syntax than it did to use &amp;lt;%# ((Class)Container.DataItem).Field %&amp;gt;.&amp;nbsp;
Who wants to write all of the latter, especially with autocomplete in aspx pages being
flaky at best?&lt;br&gt;
&lt;br&gt;
So how could ASP.NET be less verbose and more elegant? How could WE make it better
without being able to extend the many internal and sealed classes that make up the
webforms engine?&lt;br&gt;
&lt;br&gt;
Preprocessing!&lt;br&gt;
&lt;br&gt;
Here's an overview of what you do.&lt;br&gt;
&lt;ol&gt;
&lt;li&gt;
Create a generator that extends Microsoft.CustomTool.BaseCodeGeneratorWithSite for
.aspx files and do your preprocessing here.&lt;br&gt;
&lt;/li&gt;
&lt;li&gt;
Create a wizard that extends Microsoft.VisualStudio.TemplateWizard.IWizard to set
up a file hiearchy like this: 
&lt;ul&gt;
&lt;li&gt;
Page.myaspx 
&lt;ul&gt;
&lt;li&gt;
Page.aspx 
&lt;ul&gt;
&lt;li&gt;
Page.aspx.cs 
&lt;/li&gt;
&lt;li&gt;
Page.aspx.designer.cs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Create an ItemTemplate for your item that contains these files and sets your custom
tool to the generator you created in step one. 
&lt;/li&gt;
&lt;li&gt;
Add a new myaspx to your project and make sure you don't ever modify the aspx directly
(this takes some getting used to)&lt;/li&gt;
&lt;/ol&gt;
So what are some things you could filter/generate/preprocess?&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;
Add runat="server" tags to all &amp;lt;anything:anything&amp;gt; nodes that don't have it. 
&lt;/li&gt;
&lt;li&gt;
Replace "~/blah" with an appropriate call to ResolveClientUrl 
&lt;/li&gt;
&lt;li&gt;
Do some localization magic&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;"&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;&lt;span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;"&gt;&amp;lt;asp:HyperLink
ID=&lt;span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);"&gt;"_lnkForgot"&lt;/span&gt; NavigateUrl='~/ForgotPassword.aspx'
Text=&lt;span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);"&gt;"$:Forgot
your Username or Password?"&lt;/span&gt; /&amp;gt;&lt;/span&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;"&gt;&lt;/span&gt;
&lt;/p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; This is actually the markup that we wrote
to generate the markup at the beginning of this post.&amp;nbsp; See the $:?&amp;nbsp; That
tells the generator to create a resource in PageStrings.resx with the format Page_ID_Property
that has the value that appears after the $:.&amp;nbsp; You never need to touch that resx
file.&amp;nbsp; You can just write your markup, define your strings, and not be interrupted,
or even have to name your strings.&amp;nbsp; If you want to name your strings, say something
global.&amp;nbsp; Just do "$Name: This is a string" and if you want to use it later just
use "$Name".&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;
Make databinding strongly typed.&amp;nbsp; This requires a bit of help, as you can't easily
infer the type being bound by just inspecting the source.&amp;nbsp; Our solution was to
add a DataType="Class" attribute to whatever the repeating control was.&amp;nbsp; For
example: 
&lt;p&gt;
&lt;span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;"&gt;&lt;/span&gt;
&lt;br&gt;
&lt;font face="Courier New"&gt;&lt;span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent;"&gt;&amp;lt;asp:Repeater
ID=&lt;span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);"&gt;"repeater"&lt;/span&gt; DataType=&lt;span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);"&gt;"BoundClass"&lt;/span&gt;&amp;gt;&lt;br&gt;
&amp;nbsp; &amp;lt;ItemTemplate&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;asp:Label ID=&lt;span style="font-size: 11px; color: rgb(102, 102, 102); font-family: courier new; background-color: rgb(228, 228, 228);"&gt;"textBox"&lt;/span&gt; Text='&amp;lt;%#@Name%&amp;gt;'
/&amp;gt;&lt;br&gt;
&amp;nbsp; &amp;lt;/ItemTemplate&amp;gt;&lt;br&gt;
&amp;lt;/asp:Repeater&amp;gt;&lt;/span&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt; 
&lt;p&gt;
Notice the @ in the &amp;lt;%#%&amp;gt; tag.&amp;nbsp; That gets replaced with ((BoundClass)Container.DataItem),
so you can do things like &amp;lt;%# String.Format("{0} {1}", @FirstName, @LastName) %&amp;gt;&lt;br&gt;
&lt;br&gt;
So that's how we made ASP.NET more manageable.&amp;nbsp; Now, there are still several
issues with ASP.NET WebForms that caused us to eventually switch to MonoRail, which
also benefits from preprocessing, but I'll post on that later.
&lt;/p&gt;
&lt;/blockquote&gt;&lt;img width="0" height="0" src="http://blog.eleutian.com/aggbug.ashx?id=e1f2cae9-7693-4935-9be9-927946cc6cd2" /&gt;</description>
      <comments>http://blog.eleutian.com/CommentView,guid,e1f2cae9-7693-4935-9be9-927946cc6cd2.aspx</comments>
      <category>code generation</category>
      <category>development</category>
      <category>localization</category>
      <category>productivity</category>
      <category>tools</category>
    </item>
  </channel>
</rss>