<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://weblogs.asp.net/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title type="html">Grant Barrington</title><subtitle type="html">Random findings about ASP.NET, c#, Microsoft Dynamics NAV and jQuery</subtitle><id>http://weblogs.asp.net/grantbarrington/atom.aspx</id><link rel="alternate" type="text/html" href="http://weblogs.asp.net/grantbarrington/default.aspx" /><link rel="self" type="application/atom+xml" href="http://weblogs.asp.net/grantbarrington/atom.aspx" /><generator uri="http://communityserver.org" version="3.0.20510.895">Community Server</generator><updated>2008-12-06T16:11:00Z</updated><entry><title>Adding, Changing &amp; Finding buttons in the ASP.NET Wizard Control</title><link rel="alternate" type="text/html" href="http://weblogs.asp.net/grantbarrington/archive/2009/11/04/adding-changing-amp-finding-buttons-in-the-asp-net-wizard-control.aspx" /><id>http://weblogs.asp.net/grantbarrington/archive/2009/11/04/adding-changing-amp-finding-buttons-in-the-asp-net-wizard-control.aspx</id><published>2009-11-04T01:55:43Z</published><updated>2009-11-04T01:55:43Z</updated><content type="html">&lt;p&gt;A comment was recently left on a &lt;a href="http://weblogs.asp.net/grantbarrington/archive/2009/08/11/styling-the-asp-net-wizard-control-to-have-the-steps-across-the-top.aspx"&gt;previous post&lt;/a&gt; of mine asking how to go about adding a button to a wizard and handling the click. I thought I'd answer the question with another post as there is usually more you'd like to do than just adding a button (we certainly do!!!!)&lt;/p&gt;  &lt;h3&gt;Adding a button to the Wizard and handling the onclick event&lt;/h3&gt;  &lt;p&gt;Adding a button to the ASP.NET wizard is pretty simple and pretty easy to manage. You just have to define the StartNavigationTemplate, StepNavigationTemplate and FinishNavigationTemplate. These are what define the rendering of the buttons at the bottom of the wizard.&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Wizard &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;wzd&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;Server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;Width&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;100%&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;DisplaySideBar&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;false&amp;quot;&amp;gt;
     &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;WizardSteps&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
         &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;WizardStep &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;step1&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;StepType&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;Start&amp;quot;&amp;gt;
             &lt;/span&gt;... omitted ...
         &lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;WizardStep&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
         &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;WizardStep &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;step2&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;StepType&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;Step&amp;quot;&amp;gt;
             &lt;/span&gt;... omitted ...
         &lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;WizardStep&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
         &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;WizardStep &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;step3&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;StepType&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;Finish&amp;quot;&amp;gt;
             &lt;/span&gt;... omitted ...
         &lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;WizardStep&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
     &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;WizardSteps&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
     &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;StartNavigationTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
         &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;table &lt;/span&gt;&lt;span style="color: red"&gt;cellpadding&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;3&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;cellspacing&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;3&amp;quot;&amp;gt;
             &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                 &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                     &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Button &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;btnCancel&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;Text&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;Cancel&amp;quot;
                         &lt;/span&gt;&lt;span style="color: red"&gt;CausesValidation&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;false&amp;quot; 
                         &lt;/span&gt;&lt;span style="color: red"&gt;OnClientClick&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;return confirm('Are you sure you want to cancel');&amp;quot; 
                         &lt;/span&gt;&lt;span style="color: red"&gt;OnClick&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;btnCancel_Click&amp;quot; 
                      /&amp;gt;
                 &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                 &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                     &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Button &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;btnNext&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;Text&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;Next &amp;gt;&amp;gt;&amp;quot;
                         &lt;/span&gt;&lt;span style="color: red"&gt;CausesValidation&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;true&amp;quot; 
                         &lt;/span&gt;&lt;span style="color: red"&gt;CommandName&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;MoveNext&amp;quot; 
                      /&amp;gt;
                 &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
             &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
         &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;table&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
     &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;StartNavigationTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
     &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;StepNavigationTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
         &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;table &lt;/span&gt;&lt;span style="color: red"&gt;cellpadding&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;3&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;cellspacing&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;3&amp;quot;&amp;gt;
             &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                 &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                     &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Button &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;btnCancel&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;Text&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;Cancel&amp;quot;
                         &lt;/span&gt;&lt;span style="color: red"&gt;CausesValidation&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;false&amp;quot; 
                         &lt;/span&gt;&lt;span style="color: red"&gt;OnClientClick&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;return confirm('Are you sure you want to cancel');&amp;quot; 
                         &lt;/span&gt;&lt;span style="color: red"&gt;OnClick&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;btnCancel_Click&amp;quot; 
                      /&amp;gt;
                 &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                 &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                     &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Button &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;btnPrevious&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;Text&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;&amp;lt;&amp;lt; Previous&amp;quot;
                         &lt;/span&gt;&lt;span style="color: red"&gt;CausesValidation&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;false&amp;quot; 
                         &lt;/span&gt;&lt;span style="color: red"&gt;CommandName&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;MovePrevious&amp;quot; 
                      /&amp;gt;
                      &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Button &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;btnNext&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;Text&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;Next &amp;gt;&amp;gt;&amp;quot;
                         &lt;/span&gt;&lt;span style="color: red"&gt;CausesValidation&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;true&amp;quot; 
                         &lt;/span&gt;&lt;span style="color: red"&gt;CommandName&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;MoveNext&amp;quot; 
                      /&amp;gt;
                 &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
             &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
         &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;table&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
     &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;StepNavigationTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
     &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;FinishNavigationTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
         &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;table &lt;/span&gt;&lt;span style="color: red"&gt;cellpadding&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;3&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;cellspacing&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;3&amp;quot;&amp;gt;
             &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                 &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                     &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Button &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;btnCancel&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;Text&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;Cancel&amp;quot;
                         &lt;/span&gt;&lt;span style="color: red"&gt;CausesValidation&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;false&amp;quot; 
                         &lt;/span&gt;&lt;span style="color: red"&gt;OnClientClick&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;return confirm('Are you sure you want to cancel');&amp;quot; 
                         &lt;/span&gt;&lt;span style="color: red"&gt;OnClick&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;btnCancel_Click&amp;quot; 
                      /&amp;gt;
                 &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                 &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                      &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Button &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;btnFinish&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;Text&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;Finish&amp;quot;
                         &lt;/span&gt;&lt;span style="color: red"&gt;CausesValidation&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;true&amp;quot; 
                         &lt;/span&gt;&lt;span style="color: red"&gt;CommandName&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;MoveComplete&amp;quot; 
                      /&amp;gt;
                 &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
             &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
         &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;table&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
     &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;FinishNavigationTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
 &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Wizard&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;In the ASP.NET code above, I've added 3 steps to my wizard, each with a different StepType. The StepType is what defines which NavigationTemplate the ASP.NET wizard uses. 

&lt;br /&gt;In the example above:

&lt;br /&gt;

&lt;ul&gt;
  &lt;li&gt;Step 1 will use the &amp;quot;StartNavigationTemplate&amp;quot;&lt;/li&gt;

  &lt;li&gt;Step 2 will use the &amp;quot;StepNavigationTemplate&amp;quot;&lt;/li&gt;

  &lt;li&gt;Step 3 will use the &amp;quot;FinishNavigationTemplate&amp;quot;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trick with making your own NavigationTemplates is to make sure you use the &amp;quot;CommandNames&amp;quot; that the ASP.NET wizard requires. You can see on the &amp;quot;Next&amp;quot;, &amp;quot;Previous&amp;quot; and &amp;quot;Complete&amp;quot; buttons that there are no &amp;quot;OnClick&amp;quot; handlers, rather we have used &amp;quot;MoveNext&amp;quot;, &amp;quot;MovePrevious&amp;quot; and &amp;quot;MoveComplete&amp;quot; as the CommandNames on the buttons. These CommandNames are what the wizard uses to fire the appropriate event.&lt;/p&gt;

&lt;p&gt;In all the cases above, I've added a button that allows the user to &amp;quot;Cancel&amp;quot;. When the user clicks on &amp;quot;Cancel&amp;quot;, it fires a quick javascript confirm. If the user presses &amp;quot;OK&amp;quot;, then the normal code-behind button event handler is raised.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/AddingRemovingFindingbu.NETWizardControl_A462/image_4.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px" border="0" alt="image" src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/AddingRemovingFindingbu.NETWizardControl_A462/image_thumb_1.png" width="434" height="336" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;protected void &lt;/span&gt;btnCancel_Click(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;EventArgs &lt;/span&gt;e)
{
    &lt;span style="color: green"&gt;// Do something with the click ...
    &lt;/span&gt;Response.Redirect(&lt;span style="color: #a31515"&gt;&amp;quot;home.aspx&amp;quot;&lt;/span&gt;);
}&lt;/pre&gt;

&lt;h3&gt;Finding a button in a NavigationTemplate&lt;/h3&gt;

&lt;p&gt;Sometimes we want (or need) to hide a button on one of the wizard steps for whatever reason. 
  &lt;br /&gt;For example, if you are using a wizard for an e-commerce checkout, you might disable the Next button on the first step if there are no items in your shopping basket.&lt;/p&gt;

&lt;p&gt;This code below is from someone else, so I can't take credit for it.... I'm not sure where we got it from, but it works. &lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span style="color: blue"&gt;public enum &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WizardNavigationTempContainer
&lt;/span&gt;{
    StartNavigationTemplateContainerID = 1,
    StepNavigationTemplateContainerID = 2,
    FinishNavigationTemplateContainerID = 3
}

&lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Control &lt;/span&gt;GetControlFromWizard(&lt;span style="color: #2b91af"&gt;Wizard &lt;/span&gt;wizard, &lt;span style="color: #2b91af"&gt;WizardNavigationTempContainer &lt;/span&gt;wzdTemplate, &lt;span style="color: blue"&gt;string &lt;/span&gt;controlName)
{
    System.Text.&lt;span style="color: #2b91af"&gt;StringBuilder &lt;/span&gt;strCtrl = &lt;span style="color: blue"&gt;new &lt;/span&gt;System.Text.&lt;span style="color: #2b91af"&gt;StringBuilder&lt;/span&gt;();
    strCtrl.Append(wzdTemplate);
    strCtrl.Append(&lt;span style="color: #a31515"&gt;&amp;quot;$&amp;quot;&lt;/span&gt;);
    strCtrl.Append(controlName);

    &lt;span style="color: blue"&gt;return &lt;/span&gt;wizard.FindControl(strCtrl.ToString());
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The ASP.NET wizard does some weird stuff with naming, and you can't use the standard FindControl() to find the control. If you're using .NET 3.5, you could probably implement the above &amp;quot;GetControlFromWizard&amp;quot; as an Extension Method.&lt;/p&gt;

&lt;h3&gt;Hiding the button&lt;/h3&gt;

&lt;p&gt;Now that we know how to find the button in the wizard step, we can hide/disable... do anything we want to the button.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;protected void &lt;/span&gt;Page_Load(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;EventArgs &lt;/span&gt;e)
{
    &lt;span style="color: blue"&gt;if &lt;/span&gt;(Page.User.Identity.IsAuthenticated == &lt;span style="color: blue"&gt;true&lt;/span&gt;)
    {
        &lt;span style="color: #2b91af"&gt;Button &lt;/span&gt;btnNext = GetControlFromWizard(wzd, &lt;span style="color: #2b91af"&gt;WizardNavigationTempContainer&lt;/span&gt;.StartNavigationTemplateContainerID, &lt;span style="color: #a31515"&gt;&amp;quot;btnNext&amp;quot;&lt;/span&gt;) &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Button&lt;/span&gt;;
        btnNext.Enabled = &lt;span style="color: blue"&gt;false&lt;/span&gt;;
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;In the code above, I'm checking if a user is Authenticated.. and if they are, then I hide the button. As I said before, you could implement what condition you wanted to do here.&lt;/p&gt;

&lt;h3&gt;Putting it all together&lt;/h3&gt;

&lt;p&gt;Using the techniques I've used here, and the techniques described in my previous post, you can actually make some pretty nice looking wizards using the ASP.NET Wizard control. We use the methods I've shown here, and the methods in my previous post together and we've produced some pretty user-friendly wizards.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7246381" width="1" height="1"&gt;</content><author><name>grant.barrington</name><uri>http://weblogs.asp.net/members/grant.barrington.aspx</uri></author><category term="asp.net" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/asp.net/default.aspx" /></entry><entry><title>Screen Scraping in C#</title><link rel="alternate" type="text/html" href="http://weblogs.asp.net/grantbarrington/archive/2009/10/15/screen-scraping-in-c.aspx" /><id>http://weblogs.asp.net/grantbarrington/archive/2009/10/15/screen-scraping-in-c.aspx</id><published>2009-10-14T20:54:45Z</published><updated>2009-10-14T20:54:45Z</updated><content type="html">&lt;p&gt;Recently I was asked by a friend of mine to screen scrape a website. What he wanted was the results of a form submission. There were a number of fields on the form (mostly dropdowns), and he wanted me to run every possible permutation of these dropdown lists. All up, this resulted in just over 8,000 pieces of data.&lt;/p&gt;  &lt;p&gt;It ended up being REALLY easy (a bit easier than I thought). So I thought I'd share how I went about doing it. Most of these methods were gleaned from other peoples posts, then tailored to my specific needs.&lt;/p&gt;  &lt;p&gt;My approach was to tackle this in 2 separate parts:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Make the requests to the remote server, and save all the possible permutations to disk &lt;/li&gt;    &lt;li&gt;Load up and then scrape the files to extract the data I needed. &lt;/li&gt; &lt;/ol&gt;  &lt;h2&gt;Where to Start&lt;/h2&gt;  &lt;p&gt;I start by firing up &lt;a href="http://www.fiddler2.com"&gt;Fiddler&lt;/a&gt; and make a request to the server just using the browser.&lt;/p&gt;  &lt;p&gt;From this I can get the following information:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The URL I need to send the request to &lt;/li&gt;    &lt;li&gt;All the form fields I need to send with the request &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/ScreenScrapinginC_B9B3/image_2.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="image" src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/ScreenScrapinginC_B9B3/image_thumb.png" width="881" height="465" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;In my case, the server wasn't an ASP.NET server, so I didn't have to worry about VIEWSTATE at all.&lt;/p&gt;  &lt;h2&gt;Making the request through code&lt;/h2&gt;  &lt;p&gt;This is one place where I was surprised how EASY it was to make the request. The last time I had to do this was back in the .NET 1.1 days, and it was a little bit harder.&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private void &lt;/span&gt;SendRequest()
{
    &lt;span style="color: blue"&gt;try
    &lt;/span&gt;{
        &lt;span style="color: #2b91af"&gt;WebClient &lt;/span&gt;webClient = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WebClient&lt;/span&gt;();

        &lt;span style="color: green"&gt;// Create a new NameValueCollection instance to hold some custom parameters to be posted to the URL.
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NameValueCollection &lt;/span&gt;vars = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NameValueCollection&lt;/span&gt;();

        &lt;span style="color: green"&gt;// Add necessary parameter/value pairs to the name/value container.
        &lt;/span&gt;vars.Add(&lt;span style="color: #a31515"&gt;&amp;quot;ddlGender&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;male&amp;quot;&lt;/span&gt;);
        vars.Add(&lt;span style="color: #a31515"&gt;&amp;quot;ddlAge&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;&amp;gt;30&amp;quot;&lt;/span&gt;);

        &lt;span style="color: green"&gt;// Upload the NameValueCollection.
        &lt;/span&gt;&lt;span style="color: blue"&gt;byte&lt;/span&gt;[] responseArray = webClient.UploadValues(URL, &lt;span style="color: #a31515"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;, vars);

        &lt;span style="color: green"&gt;// Save the response.
        &lt;/span&gt;&lt;span style="color: blue"&gt;string &lt;/span&gt;fileName = &lt;span style="color: #a31515"&gt;&amp;quot;webRequest.html&amp;quot;&lt;/span&gt;;

        System.IO.&lt;span style="color: #2b91af"&gt;File&lt;/span&gt;.WriteAllBytes(System.IO.&lt;span style="color: #2b91af"&gt;Path&lt;/span&gt;.Combine(filePath, fileName), responseArray);

    }
    &lt;span style="color: blue"&gt;catch &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Exception &lt;/span&gt;ee)
    {
        &lt;span style="color: green"&gt;// Log error (omitted for brevity)
    &lt;/span&gt;}

}&lt;/pre&gt;

&lt;p&gt;In my case above, the variables &amp;quot;URL&amp;quot; and &amp;quot;filePath&amp;quot; are set in the constructor of the class. &lt;/p&gt;

&lt;p&gt;You will note in the example above that in my case I am using POST to get the data from the server. This can easily be changed to GET (or whatever HTTP method you need).&lt;/p&gt;

&lt;p&gt;I save all the response data to a file (which I then parse to get the data I want)&lt;/p&gt;

&lt;h2&gt;Parsing the HTML files&lt;/h2&gt;

&lt;p&gt;To parse the files also ended up being extremely easy for me. In the past I've tried to use regular expressions to extract the data from files, but plain and simple... I DO NOT understand regular expressions. I've tried, and where I need to I can get them to work, but my poor little brain doesn't have enough room to remember regular expressions.&lt;/p&gt;

&lt;p&gt;This time I used the &lt;a href="http://www.codeplex.com/htmlagilitypack"&gt;HTML Agility Pack&lt;/a&gt; available through CodePlex. It rocks... Coming from a .NET world, I can understand and use this easily, and its pretty fast as well. For those who haven't heard of the HTML Agility Pack here is an excerpt from their CodePlex homepage.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;This is an agile HTML parser that builds a read/write DOM and supports plain XPATH or XSLT (you actually don't HAVE to understand XPATH nor XSLT to use it, don't worry...). It is a .NET code library that allows you to parse &amp;quot;out of the web&amp;quot; HTML files. The parser is very tolerant with &amp;quot;real world&amp;quot; malformed HTML. The object model is very similar to what proposes System.Xml, but for HTML documents (or streams).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private void &lt;/span&gt;ParseFile(&lt;span style="color: blue"&gt;string &lt;/span&gt;fileName)
{
    &lt;span style="color: blue"&gt;if &lt;/span&gt;(!System.IO.&lt;span style="color: #2b91af"&gt;File&lt;/span&gt;.Exists(System.IO.&lt;span style="color: #2b91af"&gt;Path&lt;/span&gt;.Combine(filePath, fileName)))
    {
        &lt;span style="color: blue"&gt;return&lt;/span&gt;;
    }

    &lt;span style="color: #2b91af"&gt;HtmlDocument &lt;/span&gt;doc = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlDocument&lt;/span&gt;();

    doc.Load(System.IO.&lt;span style="color: #2b91af"&gt;Path&lt;/span&gt;.Combine(filePath, fileName));

    &lt;span style="color: #2b91af"&gt;HtmlNode &lt;/span&gt;greenBlockContainer = doc.DocumentNode.SelectSingleNode(&lt;span style="color: #a31515"&gt;&amp;quot;//div[@class=\&amp;quot;green-block-container\&amp;quot;]&amp;quot;&lt;/span&gt;);

    &lt;span style="color: #2b91af"&gt;HtmlNodeCollection &lt;/span&gt;greenBlocks = greenBlockContainer.SelectNodes(&lt;span style="color: #a31515"&gt;&amp;quot;//div[@class=\&amp;quot;green-block\&amp;quot;]&amp;quot;&lt;/span&gt;);

    &lt;span style="color: blue"&gt;string &lt;/span&gt;s1 = greenBlocks[0].SelectNodes(&lt;span style="color: #a31515"&gt;&amp;quot;//div[@class=\&amp;quot;result-block-left\&amp;quot;]&amp;quot;&lt;/span&gt;)[0].InnerText;
    &lt;span style="color: blue"&gt;string &lt;/span&gt;s2 = greenBlocks[0].SelectNodes(&lt;span style="color: #a31515"&gt;&amp;quot;//div[@class=\&amp;quot;result-block-right\&amp;quot;]&amp;quot;&lt;/span&gt;)[0].InnerText;
    &lt;span style="color: green"&gt;// etc...
    
    // Do something with the data... omitted.
    
&lt;/span&gt;}&lt;/pre&gt;

&lt;p&gt;Here is what the code above does:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Checks whether the file exists... if not returns &lt;/li&gt;

  &lt;li&gt;Creates a HtmlDocument (from the HtmlAgilityPack)&lt;/li&gt;

  &lt;li&gt;Load the html file (fileName) into the HtmlDocument &lt;/li&gt;

  &lt;li&gt;Extract the nodes we are looking for. Here we can use XPath type queries to get elements &lt;/li&gt;

  &lt;li&gt;Use the &amp;quot;InnerText&amp;quot; property to get the value of the node and assign it to a string (I then used this string to populate a DataTable) &lt;/li&gt;
&lt;/ol&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7230019" width="1" height="1"&gt;</content><author><name>grant.barrington</name><uri>http://weblogs.asp.net/members/grant.barrington.aspx</uri></author><category term="asp.net" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/asp.net/default.aspx" /><category term="screen scraping" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/screen+scraping/default.aspx" /></entry><entry><title>Styling the ASP.NET Wizard Control to have the Steps Across the top</title><link rel="alternate" type="text/html" href="http://weblogs.asp.net/grantbarrington/archive/2009/08/11/styling-the-asp-net-wizard-control-to-have-the-steps-across-the-top.aspx" /><id>http://weblogs.asp.net/grantbarrington/archive/2009/08/11/styling-the-asp-net-wizard-control-to-have-the-steps-across-the-top.aspx</id><published>2009-08-10T22:45:21Z</published><updated>2009-08-10T22:45:21Z</updated><content type="html">&lt;p&gt;The default style of the ASP.NET Wizard control is not the best. For the sidebar to work, and display all the wizard steps in a wizard requires quite a bit of space. And in all the wizards we end up creating, we don't want the user to jump from one step to the next using the sidebar. We make the user click from step to step linearly.&lt;/p&gt;  &lt;p&gt;We've spent a little time lately changing the way the wizard looks and have come up with the following look and feel.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/Sty.NETWizardControltohavetheStepsAcross_CA30/wizardDetails_2.gif"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="wizardDetails" src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/Sty.NETWizardControltohavetheStepsAcross_CA30/wizardDetails_thumb.gif" width="958" height="396" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The top HeaderTemplate contains the current step the user is on (derived from the WizardStep Title) and an indication of the total number of step (we use three different classes in indicate the current step, completed step and incomplete step). The &amp;quot;steps&amp;quot; also have tooltips added to let the user know what steps are coming. (See image below)&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;a href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/Sty.NETWizardControltohavetheStepsAcross_CA30/image_2.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="Tooltip when Mouse hovers over the step number" src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/Sty.NETWizardControltohavetheStepsAcross_CA30/image_thumb.png" width="263" height="69" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The WizardStep in the image above is all the information regarding &amp;quot;Billing and Shipping&amp;quot; details (this is just standard Wizard Step stuff)&lt;/p&gt;  &lt;h2&gt;How its done&lt;/h2&gt;  &lt;p&gt;The markup for the wizard aspx code is as follows:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Wizard &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;wzd&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;Server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;Width&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;100%&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;DisplaySideBar&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;false&amp;quot;&amp;gt;
    &lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;HeaderTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;table &lt;/span&gt;&lt;span style="color: red"&gt;style&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;&lt;/span&gt;&lt;span style="color: red"&gt;width&lt;/span&gt;: &lt;span style="color: blue"&gt;100%&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;cellpadding&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;0&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;cellspacing&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;0&amp;quot;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;wizardTitle&amp;quot;&amp;gt;
                    &lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;= &lt;/span&gt;wzd.ActiveStep.Title&lt;span style="background: #ffee62"&gt;%&amp;gt;
&lt;/span&gt;                &lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;table &lt;/span&gt;&lt;span style="color: red"&gt;style&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;&lt;/span&gt;&lt;span style="color: red"&gt;width&lt;/span&gt;: &lt;span style="color: blue"&gt;100%&lt;/span&gt;; &lt;span style="color: red"&gt;border-collapse&lt;/span&gt;: &lt;span style="color: blue"&gt;collapse&lt;/span&gt;;&lt;span style="color: blue"&gt;&amp;quot;&amp;gt;
                        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td &lt;/span&gt;&lt;span style="color: red"&gt;style&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;&lt;/span&gt;&lt;span style="color: red"&gt;text-align&lt;/span&gt;: &lt;span style="color: blue"&gt;right&amp;quot;&amp;gt;
                                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;span &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;wizardProgress&amp;quot;&amp;gt;&lt;/span&gt;Steps:&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;span&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Repeater &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;SideBarList&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot;&amp;gt;
                                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                                    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;stepBreak&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color: red"&gt;&amp;amp;nbsp;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                                    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;&lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt;# GetClassForWizardStep(Container.DataItem) &lt;span style="background: #ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;title&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;&lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt;# DataBinder.Eval(Container, &amp;quot;DataItem.Name&amp;quot;)&lt;span style="background: #ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;quot;&amp;gt;
                                        &lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;# &lt;/span&gt;wzd.WizardSteps.IndexOf(Container.DataItem &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WizardStep&lt;/span&gt;) + 1 &lt;span style="background: #ffee62"&gt;%&amp;gt;
&lt;/span&gt;                                    &lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                                &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Repeater&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                        &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;                    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;table&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;table&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;HeaderTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;SideBarTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;SideBarTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;WizardSteps&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt; ... removed... &lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;WizardSteps&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Wizard&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;We add the following event handler to Page_Load in our code-behind&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;protected void &lt;/span&gt;Page_Load(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;EventArgs &lt;/span&gt;e)
{
    wzd.PreRender += &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;EventHandler&lt;/span&gt;(wzd_PreRender);
}&lt;/pre&gt;

&lt;p&gt;And have the following methods in the code-behind&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;protected void &lt;/span&gt;wzd_PreRender(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;EventArgs &lt;/span&gt;e)
{
    &lt;span style="color: #2b91af"&gt;Repeater &lt;/span&gt;SideBarList = wzd.FindControl(&lt;span style="color: #a31515"&gt;&amp;quot;HeaderContainer&amp;quot;&lt;/span&gt;).FindControl(&lt;span style="color: #a31515"&gt;&amp;quot;SideBarList&amp;quot;&lt;/span&gt;) &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Repeater&lt;/span&gt;;

    SideBarList.DataSource = wzd.WizardSteps;
    SideBarList.DataBind();

}

&lt;span style="color: blue"&gt;public string &lt;/span&gt;GetClassForWizardStep(&lt;span style="color: blue"&gt;object &lt;/span&gt;wizardStep)
{
    &lt;span style="color: #2b91af"&gt;WizardStep &lt;/span&gt;step = wizardStep &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WizardStep&lt;/span&gt;;

    &lt;span style="color: blue"&gt;if &lt;/span&gt;(step == &lt;span style="color: blue"&gt;null&lt;/span&gt;)
    {
        &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
    }

    &lt;span style="color: blue"&gt;int &lt;/span&gt;stepIndex = wzd.WizardSteps.IndexOf(step);

    &lt;span style="color: blue"&gt;if &lt;/span&gt;(stepIndex &amp;lt; wzd.ActiveStepIndex)
    {
        &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;stepCompleted&amp;quot;&lt;/span&gt;;
    }
    &lt;span style="color: blue"&gt;else if &lt;/span&gt;(stepIndex &amp;gt; wzd.ActiveStepIndex)
    {
        &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;stepNotCompleted&amp;quot;&lt;/span&gt;;
    }
    &lt;span style="color: blue"&gt;else
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;stepCurrent&amp;quot;&lt;/span&gt;;
    }
}&lt;/pre&gt;

&lt;h2&gt;Explanation of the code above&lt;/h2&gt;

&lt;p&gt;When the wizard goes into PreRender, we bind the collection of WizardSteps to the Repeater in our HeaderTemplate&lt;/p&gt;

&lt;p&gt;The &amp;quot;GetClassForWizardStep&amp;quot; is a helper method we have to determine what wizard step we're on, and render the appropriate class in the table cell.&lt;/p&gt;

&lt;h2&gt;Style Sheet Rules&lt;/h2&gt;

&lt;p&gt;The rules I'm using above to generate the page are as below...&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;/* WIZARD */
&lt;/span&gt;&lt;span style="color: #a31515"&gt;.stepNotCompleted
&lt;/span&gt;{
    &lt;span style="color: red"&gt;background-color&lt;/span&gt;: &lt;span style="color: blue"&gt;rgb(153,153,153)&lt;/span&gt;;
    &lt;span style="color: red"&gt;width&lt;/span&gt;: &lt;span style="color: blue"&gt;15px&lt;/span&gt;;
    &lt;span style="color: red"&gt;border&lt;/span&gt;: &lt;span style="color: blue"&gt;1px solid rgb(153,153,153)&lt;/span&gt;;
    &lt;span style="color: red"&gt;margin-right&lt;/span&gt;: &lt;span style="color: blue"&gt;5px&lt;/span&gt;;
    &lt;span style="color: red"&gt;color&lt;/span&gt;: &lt;span style="color: blue"&gt;White&lt;/span&gt;;
    &lt;span style="color: red"&gt;font-family&lt;/span&gt;: &lt;span style="color: blue"&gt;Arial&lt;/span&gt;;
    &lt;span style="color: red"&gt;font-size&lt;/span&gt;: &lt;span style="color: blue"&gt;12px&lt;/span&gt;;
    &lt;span style="color: red"&gt;text-align&lt;/span&gt;: &lt;span style="color: blue"&gt;center&lt;/span&gt;;
}

&lt;span style="color: #a31515"&gt;.stepCompleted
&lt;/span&gt;{
    &lt;span style="color: red"&gt;background-color&lt;/span&gt;: &lt;span style="color: blue"&gt;#4d4d4d&lt;/span&gt;;
    &lt;span style="color: red"&gt;width&lt;/span&gt;: &lt;span style="color: blue"&gt;15px&lt;/span&gt;;
    &lt;span style="color: red"&gt;border&lt;/span&gt;: &lt;span style="color: blue"&gt;1px solid #4d4d4d&lt;/span&gt;;
    &lt;span style="color: red"&gt;color&lt;/span&gt;: &lt;span style="color: blue"&gt;White&lt;/span&gt;;
    &lt;span style="color: red"&gt;font-family&lt;/span&gt;: &lt;span style="color: blue"&gt;Arial&lt;/span&gt;;
    &lt;span style="color: red"&gt;font-size&lt;/span&gt;: &lt;span style="color: blue"&gt;12px&lt;/span&gt;;
    &lt;span style="color: red"&gt;text-align&lt;/span&gt;: &lt;span style="color: blue"&gt;center&lt;/span&gt;;
}

&lt;span style="color: #a31515"&gt;.stepCurrent
&lt;/span&gt;{
    &lt;span style="color: red"&gt;background-color&lt;/span&gt;: &lt;span style="color: blue"&gt;#e01122&lt;/span&gt;;
    &lt;span style="color: red"&gt;width&lt;/span&gt;: &lt;span style="color: blue"&gt;15px&lt;/span&gt;;
    &lt;span style="color: red"&gt;border&lt;/span&gt;: &lt;span style="color: blue"&gt;1px solid #e01122&lt;/span&gt;;
    &lt;span style="color: red"&gt;color&lt;/span&gt;: &lt;span style="color: blue"&gt;White&lt;/span&gt;;
    &lt;span style="color: red"&gt;font-family&lt;/span&gt;: &lt;span style="color: blue"&gt;Arial&lt;/span&gt;;
    &lt;span style="color: red"&gt;font-size&lt;/span&gt;: &lt;span style="color: blue"&gt;12px&lt;/span&gt;;
    &lt;span style="color: red"&gt;font-weight&lt;/span&gt;: &lt;span style="color: blue"&gt;bold&lt;/span&gt;;
    &lt;span style="color: red"&gt;text-align&lt;/span&gt;: &lt;span style="color: blue"&gt;center&lt;/span&gt;;
}

&lt;span style="color: #a31515"&gt;.stepBreak
&lt;/span&gt;{
    &lt;span style="color: red"&gt;width&lt;/span&gt;: &lt;span style="color: blue"&gt;3px&lt;/span&gt;;
    &lt;span style="color: red"&gt;background-color&lt;/span&gt;: &lt;span style="color: blue"&gt;Transparent&lt;/span&gt;;
}

&lt;span style="color: #a31515"&gt;.wizardProgress
&lt;/span&gt;{
    &lt;span style="color: red"&gt;padding-right&lt;/span&gt;: &lt;span style="color: blue"&gt;10px&lt;/span&gt;;
    &lt;span style="color: red"&gt;font-family&lt;/span&gt;: &lt;span style="color: blue"&gt;Arial&lt;/span&gt;;
    &lt;span style="color: red"&gt;color&lt;/span&gt;: &lt;span style="color: blue"&gt;#333333&lt;/span&gt;;
    &lt;span style="color: red"&gt;font-size&lt;/span&gt;: &lt;span style="color: blue"&gt;12px&lt;/span&gt;;

}

&lt;span style="color: #a31515"&gt;.wizardTitle
&lt;/span&gt;{
    &lt;span style="color: red"&gt;font-family&lt;/span&gt;: &lt;span style="color: blue"&gt;Arial&lt;/span&gt;;
    &lt;span style="color: red"&gt;font-size&lt;/span&gt;: &lt;span style="color: blue"&gt;120%&lt;/span&gt;;
    &lt;span style="color: red"&gt;font-weight&lt;/span&gt;: &lt;span style="color: blue"&gt;bold&lt;/span&gt;;
    &lt;span style="color: red"&gt;color&lt;/span&gt;: &lt;span style="color: blue"&gt;#333333&lt;/span&gt;;
    &lt;span style="color: red"&gt;vertical-align&lt;/span&gt;: &lt;span style="color: blue"&gt;middle&lt;/span&gt;;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7166144" width="1" height="1"&gt;</content><author><name>grant.barrington</name><uri>http://weblogs.asp.net/members/grant.barrington.aspx</uri></author><category term="asp.net" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/asp.net/default.aspx" /></entry><entry><title>Table-less layouts with DotNetNuke</title><link rel="alternate" type="text/html" href="http://weblogs.asp.net/grantbarrington/archive/2009/07/30/table-less-layouts-with-dotnetnuke.aspx" /><id>http://weblogs.asp.net/grantbarrington/archive/2009/07/30/table-less-layouts-with-dotnetnuke.aspx</id><published>2009-07-30T05:17:48Z</published><updated>2009-07-30T05:17:48Z</updated><content type="html">&lt;p&gt;We use DotNetNuke as a base for most of our applications. We are primarily in the space of content management, mixed with custom code. DNN handles content management pretty well for all our situations. The ability for us to create modules in DNN to do whatever we want is pretty awesome.. And after you get used to some quirks (and jumping through some pretty funky hoops, its actually pretty easy to use).&lt;/p&gt;  &lt;p&gt;One thing we came across recently was doing some zebra striping with jQuery, and using a table-less layout skin (DIV's only). When you hovered over a table row, the whole page would jump up about 6-ish pixels. I'd noticed it, and hoped no-one else would, but alas it was discovered, and left up to me to fix.&lt;/p&gt;  &lt;p&gt;I won't go into the complete set of styles and the full skin file, but I'll post enough to give a few hints.&lt;/p&gt;  &lt;pre class="code"&gt;    &lt;span style="color: green"&gt;&amp;lt;!-- B. MAIN --&amp;gt;
    &lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;main&amp;quot;&amp;gt;
        &lt;/span&gt;&lt;span style="color: green"&gt;&amp;lt;!-- B.1 MAIN CONTENT --&amp;gt;
        &lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;main-content&amp;quot;&amp;gt;
            &lt;/span&gt;&lt;span style="color: green"&gt;&amp;lt;!-- Content unit - One column --&amp;gt;
            &lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;topPane&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;column1-unit&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;visible&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;false&amp;quot;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;hr &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;clear-contentunit&amp;quot; /&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;div&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;contentPane&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;column1-unit&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;visible&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;false&amp;quot;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;hr &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;clear-contentunit&amp;quot; /&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;div&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &lt;/span&gt;&lt;span style="color: green"&gt;&amp;lt;!-- Content unit - Two columns --&amp;gt;
            &lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;leftPane&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;column2-unit-left&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;visible&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;true&amp;quot; /&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;rightPane&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;column2-unit-right&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;visible&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;false&amp;quot; /&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;hr &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;clear-contentunit&amp;quot; /&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;bottomPane&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;column1-unit&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;visible&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;false&amp;quot;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;hr &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;clear-contentunit&amp;quot; /&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;div&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;div&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;hr &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;clear-contentunit&amp;quot; /&amp;gt;
        &lt;/span&gt;&lt;span style="color: green"&gt;&amp;lt;!-- C. FOOTER AREA --&amp;gt;
        &lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;footer&amp;quot;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;span &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;credits&amp;quot;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;dnn&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;TERMS &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;TERMS&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;Text&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;Terms &amp;amp; Conditions&amp;quot; /&amp;gt;
                &lt;/span&gt;|
                &lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;dnn&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;PRIVACY &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;PRIVACY&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;Text&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;Privacy Policy&amp;quot; /&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;span&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: red"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &lt;br /&gt;            &lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;span&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Copyright &lt;span style="color: red"&gt;&amp;amp;copy; &lt;/span&gt;Ellington Management &amp;amp;amps; Information Services,
                &lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;DateTime.Now.ToString(&lt;span style="color: #a31515"&gt;&amp;quot;yyyy&amp;quot;&lt;/span&gt;)&lt;span style="background: #ffee62"&gt;%&amp;gt;&lt;/span&gt;. All rights reserved. &lt;br /&gt;            &lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;span&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;div&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;div&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The key here is make sure you add &lt;strong&gt;&amp;quot;visible=false&amp;quot;&lt;/strong&gt; to all of your DIVs. When DotNetNuke adds a module to a pane, it also sets visible=true on the DIV. This way we make sure we don't get any empty DIV's rendered on the page. I don't 100% know why the empty div collapsed when you hover over a row with jQuery, but this solved the problem.&lt;/p&gt;

&lt;p&gt;In the skin above, the only DIV element I have &amp;quot;visible=true&amp;quot; on, is the leftPane. I want this DIV to render, regardless of whether there is a module added to it or not. The repercussion we get if its not &amp;quot;visible=true&amp;quot; is that the DIV doesn't render, and the rightPane ends up rendering on the left hand side of the page.&lt;/p&gt;

&lt;h2&gt;&lt;/h2&gt;

&lt;h2&gt;Make sure you ALWAYS have a contentPane (Mental note to self)&lt;/h2&gt;

&lt;p&gt;Make sure you ALWAYS have a pane in your skin called &amp;quot;contentPane&amp;quot;. I learnt this the hard way (very hard). We designed a skin for a customer and they effectively wanted 4 panels (top-left, top-right, bottom-left and bottom-right)... In all my wisdom I added panes with these names, and for the most part everything worked.... The big thing that didn't work was users logging out. &lt;/p&gt;

&lt;p&gt;The reason is this: when you click the logout link, it redirects to a URL with ctl=logoff. When DotNetNuke sees Request.QueryString[&amp;quot;ctl&amp;quot;], it loads this module and inserts it into the ContentPane... which in my case didn't exist. DNN does some error checking and if it can't find &amp;quot;ContentPane&amp;quot; it doesn't add the control. Kudos to DNN for good error checking. Bad form on my part for not realising that a &amp;quot;contentPane&amp;quot; is needed.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7157528" width="1" height="1"&gt;</content><author><name>grant.barrington</name><uri>http://weblogs.asp.net/members/grant.barrington.aspx</uri></author><category term="asp.net" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/asp.net/default.aspx" /><category term="DNN" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/DNN/default.aspx" /><category term="DotNetNuke" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/DotNetNuke/default.aspx" /></entry><entry><title>Detecting and Preventing a User From Submitting a Form Twice</title><link rel="alternate" type="text/html" href="http://weblogs.asp.net/grantbarrington/archive/2009/04/08/detecting-and-preventing-a-user-from-submitting-a-form-twice.aspx" /><id>http://weblogs.asp.net/grantbarrington/archive/2009/04/08/detecting-and-preventing-a-user-from-submitting-a-form-twice.aspx</id><published>2009-04-08T06:08:36Z</published><updated>2009-04-08T06:08:36Z</updated><content type="html">&lt;p&gt;Users get impatient when something is taking a long time to run server-side. This usually results in having a form submitted more than once. Ok, maybe its not impatience, maybe its that they didn't think they clicked the button.... I don't know why.... I just have to fix the problem of duplicate records in the database.&lt;/p&gt;  &lt;p&gt;We use a pretty simple method of tracking whether a user has submitted a form more than one. This is usually used in conjunction with other methods, such as BusyBoxes or javascript click prevention. Ultimately, this method is our absolute failsafe to ensure we only submit the form once.&lt;/p&gt;  &lt;p&gt;This has been used and tested (and approved) by a number of different payment gateways and banks we use in Australia.&lt;/p&gt;  &lt;h2&gt;How do we do it&lt;/h2&gt;  &lt;p&gt;All our pages inherit from a common base page (inherited from System.Web.UI.Page). We override the OnInit method and add a hidden field which is a Guid. We only set this field when the page first loads.&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&lt;br /&gt;protected override void &lt;/span&gt;OnInit(&lt;span style="color: #2b91af"&gt;EventArgs &lt;/span&gt;e)
{
    &lt;span style="color: #2b91af"&gt;Literal &lt;/span&gt;lit = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Literal&lt;/span&gt;();

    lit.ID = &lt;span style="color: #a31515"&gt;&amp;quot;__PAGEGUID&amp;quot;&lt;/span&gt;;
    lit.Visible = &lt;span style="color: blue"&gt;false&lt;/span&gt;;
    &lt;span style="color: blue"&gt;this&lt;/span&gt;.Controls.Add(lit);

    &lt;span style="color: blue"&gt;if &lt;/span&gt;(!IsPostBack)
    {
        lit.Text = &lt;span style="color: #2b91af"&gt;Guid&lt;/span&gt;.NewGuid().ToString();
    }

    &lt;span style="color: blue"&gt;base&lt;/span&gt;.OnInit(e);
}

&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Guid &lt;/span&gt;GetPageGuid()
{
    &lt;span style="color: #2b91af"&gt;Literal &lt;/span&gt;lit = &lt;span style="color: blue"&gt;this&lt;/span&gt;.FindControl(&lt;span style="color: #a31515"&gt;&amp;quot;__PAGEGUID&amp;quot;&lt;/span&gt;) &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Literal&lt;/span&gt;;

    &lt;span style="color: blue"&gt;if &lt;/span&gt;(lit == &lt;span style="color: blue"&gt;null&lt;/span&gt;)
    {
        &lt;span style="color: blue"&gt;throw new &lt;/span&gt;System.&lt;span style="color: #2b91af"&gt;Exception&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Could not find __PAGEGUID control&amp;quot;&lt;/span&gt;);
    }
    &lt;span style="color: blue"&gt;else
    &lt;/span&gt;{
        &lt;span style="color: #2b91af"&gt;Guid &lt;/span&gt;g = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Guid&lt;/span&gt;(lit.Text);
        &lt;span style="color: blue"&gt;return &lt;/span&gt;g;
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;This gives us a unique reference for every page we use. When its comes time to checking that a page is unique we do the following.&lt;/p&gt;

&lt;p&gt;NOTE: In the scenario below, we're tracking that users don't click the &amp;quot;Order&amp;quot; button more than once when we're firing an order through to Microsoft Dynamics NAV.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;/*
 * Ensure we only submit the order once.
 */
&lt;/span&gt;&lt;span style="color: blue"&gt;try
&lt;/span&gt;{
    &lt;span style="color: #2b91af"&gt;OrderHelper&lt;/span&gt;.EnsureOrderIsUnique(&lt;span style="color: blue"&gt;this&lt;/span&gt;.GetPageGuid());
}
&lt;span style="color: blue"&gt;catch &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;DuplicateOrderException &lt;/span&gt;dupExc)
{&lt;br /&gt;    // Do something with the error. (Code omitted)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;

&lt;p&gt;The method that does the &amp;quot;EnsureOrderIsUnique&amp;quot; is described below. I've used a static List to store the page Guids in this case. When we take credit card payments, we store the Guid in the database along with the payment information. Its up to you how to store the Guid... it just needs to be accessible by all processes.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&lt;br /&gt;private static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Guid&lt;/span&gt;&amp;gt; _submittedOrders = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Guid&lt;/span&gt;&amp;gt;();


&lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/span&gt;&lt;span style="color: green"&gt;Keeps track of all the Order Guid we've placed (similiar to Payment Gateway).
&lt;/span&gt;&lt;span style="color: gray"&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;If an order is not unique, then a DuplicateOrderException is thrown.
&lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name=&amp;quot;orderGuid&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;public static void &lt;/span&gt;EnsureOrderIsUnique(&lt;span style="color: #2b91af"&gt;Guid &lt;/span&gt;orderGuid)
{
    &lt;span style="color: blue"&gt;lock &lt;/span&gt;(((&lt;span style="color: #2b91af"&gt;ICollection&lt;/span&gt;)_submittedOrders).SyncRoot)
    {
        &lt;span style="color: blue"&gt;if &lt;/span&gt;(_submittedOrders.Contains(orderGuid))
        {
            &lt;span style="color: blue"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DuplicateOrderException&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Order has already been placed&amp;quot;&lt;/span&gt;);
        }

        _submittedOrders.Add(orderGuid);
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Thats it.... pretty simple really. And it works under a number of different scenarios:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;people double-clicking on a button at the end of a wizard&lt;/li&gt;

  &lt;li&gt;people finishing a wizard, pressing back on the browser, then pressing finish again&lt;/li&gt;

  &lt;li&gt;people opening up new browser windows and submitting both..&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&amp;#160;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7034916" width="1" height="1"&gt;</content><author><name>grant.barrington</name><uri>http://weblogs.asp.net/members/grant.barrington.aspx</uri></author><category term="asp.net" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/asp.net/default.aspx" /></entry><entry><title>Using Reflection to Determine whether an Type is Nullable And Get the underlying Type</title><link rel="alternate" type="text/html" href="http://weblogs.asp.net/grantbarrington/archive/2009/03/17/using-reflection-to-determine-whether-an-type-is-nullable-and-get-the-underlying-type.aspx" /><id>http://weblogs.asp.net/grantbarrington/archive/2009/03/17/using-reflection-to-determine-whether-an-type-is-nullable-and-get-the-underlying-type.aspx</id><published>2009-03-16T21:11:56Z</published><updated>2009-03-16T21:11:56Z</updated><content type="html">&lt;p&gt;I've mentioned in a &lt;a href="http://weblogs.asp.net/grantbarrington/archive/2009/01/08/libraries-in-my-toolkit-another-lesson-in-partial-trust.aspx"&gt;previous post&lt;/a&gt; that we use Aspose.Words combined with Aspose.Pdf to create PDF documents/reports in all our applications. &lt;/p&gt;  &lt;p&gt;To do this we use a method within the Aspose.Words.Reporting.MailMerge class called &lt;a href="http://www.aspose.com/documentation/file-format-components/aspose.words-for-.net-and-java/aspose.words.reporting.mailmerge.executewithregions_overload_3.html"&gt;ExecuteWithRegions&lt;/a&gt; using the overload that passes in a DataTable. Within Aspose.Words this effectively loops through the fields in DataTable and creates what you'd normally refer to as a sub-report.&lt;/p&gt;  &lt;p&gt;Within our applications we use classes to represent our business objects. As we produce quite a few reports that rely on a number of different objects, we've created a helper method that turns our business objects and/or a List of business objects into DataTables.&lt;/p&gt;  &lt;p&gt;We came into a problem recently when one of our fields was defined as &amp;quot;int?&amp;quot; (same as Nullable&amp;lt;int&amp;gt;). The problem we had was trying to add a column on type &amp;quot;int?&amp;quot; to a DataTable. Make sense when you think about it... databases have had the concept of nullable fields for as long as I've been creating databases.&lt;/p&gt;  &lt;p&gt;Anyway... rather than add a field of type &amp;quot;int?&amp;quot; to the DataTable, I needed to add a field of type &amp;quot;int&amp;quot; as a column. Sounded simple... sort of... A fair bit of Googling and pulling together ideas from a couple of different blog posts led me to the following code.&lt;/p&gt; &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;  &lt;p&gt;The code below takes a List of objects (simple... this doesn't handle complex types) and then returns a DataTable which is a representation of the object.&lt;/p&gt;  &lt;pre class="code" style="color: black"&gt;&lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;
 /// &lt;/span&gt;&lt;span style="color: green"&gt;Converts a Generic List into a DataTable
 &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;
 /// &amp;lt;param name=&amp;quot;list&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
 /// &amp;lt;param name=&amp;quot;typ&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
 /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
 &lt;/span&gt;&lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DataTable &lt;/span&gt;GetDataTable(&lt;span style="color: #2b91af"&gt;IList &lt;/span&gt;list, &lt;span style="color: #2b91af"&gt;Type &lt;/span&gt;typ)
 {
     &lt;span style="color: #2b91af"&gt;DataTable &lt;/span&gt;dt = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DataTable&lt;/span&gt;();

     &lt;span style="color: green"&gt;// Get a list of all the properties on the object
     &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PropertyInfo&lt;/span&gt;[] pi = typ.GetProperties();

     &lt;span style="color: green"&gt;// Loop through each property, and add it as a column to the datatable
     &lt;/span&gt;&lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;PropertyInfo &lt;/span&gt;p &lt;span style="color: blue"&gt;in &lt;/span&gt;pi)
     {
         &lt;span style="color: green"&gt;// The the type of the property
         &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Type &lt;/span&gt;columnType = p.PropertyType;

         &lt;span style="color: green"&gt;// We need to check whether the property is NULLABLE
         &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;(p.PropertyType.IsGenericType &amp;amp;&amp;amp; p.PropertyType.GetGenericTypeDefinition() == &lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Nullable&lt;/span&gt;&amp;lt;&amp;gt;))
         {
             &lt;span style="color: green"&gt;// If it is NULLABLE, then get the underlying type. eg if &amp;quot;Nullable&amp;lt;int&amp;gt;&amp;quot; then this will return just &amp;quot;int&amp;quot;
             &lt;/span&gt;columnType = p.PropertyType.GetGenericArguments()[0];
         }

         &lt;span style="color: green"&gt;// Add the column definition to the datatable.
         &lt;/span&gt;dt.Columns.Add(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DataColumn&lt;/span&gt;(p.Name, columnType));
     }

     &lt;span style="color: green"&gt;// For each object in the list, loop through and add the data to the datatable.
     &lt;/span&gt;&lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;object &lt;/span&gt;obj &lt;span style="color: blue"&gt;in &lt;/span&gt;list)
     {
         &lt;span style="color: blue"&gt;object&lt;/span&gt;[] row = &lt;span style="color: blue"&gt;new object&lt;/span&gt;[pi.Length];
         &lt;span style="color: blue"&gt;int &lt;/span&gt;i = 0;

         &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;PropertyInfo &lt;/span&gt;p &lt;span style="color: blue"&gt;in &lt;/span&gt;pi)
         {
             row[i++] = p.GetValue(obj, &lt;span style="color: blue"&gt;null&lt;/span&gt;);
         }

         dt.Rows.Add(row);
     }

     &lt;span style="color: blue"&gt;return &lt;/span&gt;dt;
 }&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The key points from the code above are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;using PropertyType.IsGenericType to determine whether the property is a generic type &lt;/li&gt;

  &lt;li&gt;using ProprtyType.GetGenericTypeDefinition() == typeof(Nullable&amp;lt;&amp;gt;) to test whether its a nullable type &lt;/li&gt;

  &lt;li&gt;getting the underlying type using PropertyType.GetGenericArguments() to get the base type. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To use the code above, you can do the following. The example below is a fairly contrived example, but it should highlight what I'm trying to do below.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Person
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public string &lt;/span&gt;Name { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }
    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DateTime &lt;/span&gt;DateOfBirth { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }
    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;? DateOfDeath { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }
}

&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Example
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DataTable &lt;/span&gt;RunExample()
    {
        &lt;span style="color: #2b91af"&gt;Person &lt;/span&gt;edward = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Person&lt;/span&gt;() { Name = &lt;span style="color: #a31515"&gt;&amp;quot;Edward&amp;quot;&lt;/span&gt;, DateOfBirth = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;(1900, 1, 1), DateOfDeath = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;(1990, 10, 15) };
        &lt;span style="color: #2b91af"&gt;Person &lt;/span&gt;margaret = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Person&lt;/span&gt;() { Name = &lt;span style="color: #a31515"&gt;&amp;quot;Margaret&amp;quot;&lt;/span&gt;, DateOfBirth = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;(1950, 2, 9), DateOfDeath = &lt;span style="color: blue"&gt;null &lt;/span&gt;};
        &lt;span style="color: #2b91af"&gt;Person &lt;/span&gt;grant = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Person&lt;/span&gt;() { Name = &lt;span style="color: #a31515"&gt;&amp;quot;Grant&amp;quot;&lt;/span&gt;, DateOfBirth = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;(1975, 6, 13), DateOfDeath = &lt;span style="color: blue"&gt;null &lt;/span&gt;};

        &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Person&lt;/span&gt;&amp;gt; people = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Person&lt;/span&gt;&amp;gt;();

        people.Add(edward);
        people.Add(margaret);
        people.Add(grant);

        &lt;span style="color: #2b91af"&gt;DataTable &lt;/span&gt;dt = GetDataTable(people, &lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Person&lt;/span&gt;));

        &lt;span style="color: blue"&gt;return &lt;/span&gt;dt;
    }
}&lt;/pre&gt;

&lt;p&gt;And this will return a DataTable that looks like the following (I'm an Aussie, so the date format is dd/MM/yyyy):&lt;/p&gt;

&lt;table cellspacing="0" cellpadding="2" width="713" border="0"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top" width="236"&gt;&lt;strong&gt;Name (string)&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="228"&gt;&lt;strong&gt;DateOfBirth (DateTime)&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="246"&gt;&lt;strong&gt;DateOfDeath (DateTime)&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="236"&gt;Edward&lt;/td&gt;

      &lt;td valign="top" width="228"&gt;1/1/1900&lt;/td&gt;

      &lt;td valign="top" width="246"&gt;15/10/1990&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="235"&gt;Margaret&lt;/td&gt;

      &lt;td valign="top" width="228"&gt;9/2/1950&lt;/td&gt;

      &lt;td valign="top" width="246"&gt;[NULL]&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="235"&gt;Grant&lt;/td&gt;

      &lt;td valign="top" width="228"&gt;13/6/1975&lt;/td&gt;

      &lt;td valign="top" width="246"&gt;[NULL]&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;NOTE: as a general rule we try to NOT use nullable fields in the database, as nullable fields do some REALLY weird things to queries. Pretty much the only field types we use as nulls are DateTime fields. In my opinion, nullable fields get used far too often within databases and there is usually an alternative.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6968518" width="1" height="1"&gt;</content><author><name>grant.barrington</name><uri>http://weblogs.asp.net/members/grant.barrington.aspx</uri></author><category term="asp.net" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/asp.net/default.aspx" /><category term="Aspose" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/Aspose/default.aspx" /><category term="reflection" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/reflection/default.aspx" /></entry><entry><title>Reflection Speed Test - How slow is it really?</title><link rel="alternate" type="text/html" href="http://weblogs.asp.net/grantbarrington/archive/2009/02/19/reflection-speed-test-how-slow-is-it-really.aspx" /><id>http://weblogs.asp.net/grantbarrington/archive/2009/02/19/reflection-speed-test-how-slow-is-it-really.aspx</id><published>2009-02-18T21:06:01Z</published><updated>2009-02-18T21:06:01Z</updated><content type="html">&lt;p&gt;Whenever anyone anywhere mentions Reflection on a blog post, straight away there is a reply saying &amp;quot;you shouldn't use Reflection as its slow&amp;quot;. I thought I'd take a look at how &amp;quot;slow&amp;quot; reflection really is in the real world.&lt;/p&gt;  &lt;p&gt;We use reflection in a couple of instances in our applications. One situation where we use Reflection is in a previous post about &lt;a href="http://weblogs.asp.net/grantbarrington/archive/2009/01/19/enumhelper-getting-a-friendly-description-from-an-enum.aspx"&gt;getting a friendly name from an enumeration.&lt;/a&gt; Another situation is where we convert a List of business objects into a DataTable (we need to do this produce PDF documents in our application using ASPOSE.Words - I'll post about this later). Another common situation you'll see is object hydration.&lt;/p&gt;  &lt;h2&gt;&lt;/h2&gt;  &lt;h2&gt;Getting a friendly name from an enumeration&lt;/h2&gt;  &lt;p&gt;There are a couple of other options I've seen/used in the past to get friendly names from Enums.&lt;/p&gt;  &lt;p&gt;These consist of:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;using Reflection to get the value of an attribute on the enum (code from my previous post) &lt;/li&gt;    &lt;li&gt;storing the enum in a table in the database and looking it up at runtime &lt;/li&gt;    &lt;li&gt;storing the enum in some other way (e.g. XML) and looking it up at runtime &lt;/li&gt;    &lt;li&gt;retrieving the friendly name from a resources file at runtime &lt;/li&gt;    &lt;li&gt;using a switch/case statement to get the values of the enum &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;I'm going to test all of the above options and see how we go for speed. &lt;/p&gt;  &lt;h2&gt;&lt;/h2&gt;  &lt;h2&gt;The Results&lt;/h2&gt;  &lt;p&gt;I'm sure some of you won't want to read through how I did it, and what methods I used... so for those people here are the results.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Startup Time&lt;/strong&gt;&lt;/p&gt;  &lt;table cellspacing="0" cellpadding="2" width="472" border="1"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="246"&gt;&lt;strong&gt;Method&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" align="right" width="110"&gt;&lt;strong&gt;Time Taken            &lt;br /&gt;(ticks*)&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" align="right" width="114"&gt;&lt;strong&gt;Time Taken            &lt;br /&gt;(ms)&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="243"&gt;Reflection &lt;/td&gt;        &lt;td valign="top" align="right" width="113"&gt;36,639&lt;/td&gt;        &lt;td valign="top" align="right" width="114"&gt;3.66&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="242"&gt;Database Warm-up &lt;/td&gt;        &lt;td valign="top" align="right" width="115"&gt;637,757&lt;/td&gt;        &lt;td valign="top" align="right" width="114"&gt;63.78&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="241"&gt;Database (Stored Procedure)&lt;/td&gt;        &lt;td valign="top" align="right" width="117"&gt;9,672&lt;/td&gt;        &lt;td valign="top" align="right" width="114"&gt;0.97&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="240"&gt;Switch / Case Statement&lt;/td&gt;        &lt;td valign="top" align="right" width="118"&gt;2,744&lt;/td&gt;        &lt;td valign="top" align="right" width="114"&gt;0.27&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="239"&gt;Resources &lt;/td&gt;        &lt;td valign="top" align="right" width="119"&gt;932,752&lt;/td&gt;        &lt;td valign="top" align="right" width="114"&gt;93.28&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="238"&gt;Xml Warm-up &lt;/td&gt;        &lt;td valign="top" align="right" width="120"&gt;14,712&lt;/td&gt;        &lt;td valign="top" align="right" width="114"&gt;1.47&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="238"&gt;Xml &lt;/td&gt;        &lt;td valign="top" align="right" width="121"&gt;8,225&lt;/td&gt;        &lt;td valign="top" align="right" width="114"&gt;0.82&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;* - A tick is 100 nanoseconds.&lt;/p&gt;  &lt;p&gt;The above data represents a average of 5 runs, only getting the value of the enum once. This represents the cold-start time for each different method (basically I'm trying to exclude any form of caching). What we can see from the above results, is that by far, a SWITCH / CASE statement is the fastest method we have available. I've split out Database warm-up and database stored proc runtime into 2 separate runs (likewise with XML). I'm a database guy, and everyone knows that establishing a connection to the database is pretty costly. What was a surprise to me, is that the longest method was getting the value from a resources file.&lt;/p&gt;  &lt;p&gt;But looking at the numbers above....and putting it into a bit of context, the longest method above took 93ms.... In terms of speed, this is still pretty fast, and certainly within tolerable levels for a Web UI.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;100 Iterations&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;I've also run the results for 100 iterations. Why 100? Maybe I'm rendering a list of data, and this is one of the columns I want to display. I know 100 is a fairly big list to render, but lets just pretend....&lt;/p&gt;  &lt;table cellspacing="0" cellpadding="2" width="472" border="1"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="246"&gt;&lt;strong&gt;Method&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" align="right" width="110"&gt;&lt;strong&gt;Time Taken            &lt;br /&gt;(ticks*)&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" align="right" width="114"&gt;&lt;strong&gt;Time Taken            &lt;br /&gt;(ms)&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="240"&gt;Switch / Case Statement&lt;/td&gt;        &lt;td valign="top" align="right" width="118"&gt;74&lt;/td&gt;        &lt;td valign="top" align="right" width="114"&gt;0.0074&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="239"&gt;Resources &lt;/td&gt;        &lt;td valign="top" align="right" width="119"&gt;37,809&lt;/td&gt;        &lt;td valign="top" align="right" width="114"&gt;3.7809&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="238"&gt;Reflection with cache&lt;/td&gt;        &lt;td valign="top" align="right" width="120"&gt;67,015&lt;/td&gt;        &lt;td valign="top" align="right" width="114"&gt;6.7015&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;Again, we see that using a switch/case statement outperforms everything else MASSIVELY. I'm actually pretty surprised how fast it is. For &lt;strong&gt;100 iterations &lt;/strong&gt;of resources and reflection, we get response times of 3.7ms and 6.7ms respectively. Again, putting this in context, we're not talking about a process that's going to put the brakes on any website I develop.&lt;/p&gt;  &lt;p&gt;What is interesting, is that using Resources is initially slow to startup, but then runs pretty past afterwards.&lt;/p&gt;  &lt;h2&gt;How I got the Values of the enum&lt;/h2&gt;  &lt;p&gt;I'll post the code I used to get the values of the enumerations.&lt;/p&gt;  &lt;h3&gt;&lt;/h3&gt;  &lt;h3&gt;EnumHelper - Reflection&lt;/h3&gt;  &lt;p&gt;This is the same method I used in a &lt;a href="http://weblogs.asp.net/grantbarrington/archive/2009/01/19/enumhelper-getting-a-friendly-description-from-an-enum.aspx"&gt;previous blog post.&lt;/a&gt; Its posted below as well in the Reflection with Cache code.&lt;/p&gt;  &lt;h3&gt;Database&lt;/h3&gt;  &lt;p&gt;This is pretty simple stuff. Basically open the connection to the database and run a stored procedure.&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public static string &lt;/span&gt;GetDescription(&lt;span style="color: #2b91af"&gt;Enum &lt;/span&gt;en)
       {
           &lt;span style="color: blue"&gt;using &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;SqlConnection &lt;/span&gt;conn = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SqlConnection&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;ConfigurationManager&lt;/span&gt;.ConnectionStrings[&lt;span style="color: #a31515"&gt;&amp;quot;SqlCommon&amp;quot;&lt;/span&gt;].ConnectionString))
           {
               &lt;span style="color: #2b91af"&gt;SqlCommand &lt;/span&gt;cmd = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SqlCommand&lt;/span&gt;();

               conn.Open();
               cmd.Connection = conn;

               cmd.CommandType = &lt;span style="color: #2b91af"&gt;CommandType&lt;/span&gt;.StoredProcedure;
               cmd.CommandText = &lt;span style="color: #a31515"&gt;&amp;quot;Enum_GetDescription&amp;quot;&lt;/span&gt;;

               cmd.Parameters.Add(&lt;span style="color: #a31515"&gt;&amp;quot;enumName&amp;quot;&lt;/span&gt;, &lt;span style="color: #2b91af"&gt;SqlDbType&lt;/span&gt;.VarChar).Value = en.ToString();

               &lt;span style="color: #2b91af"&gt;SqlDataReader &lt;/span&gt;dr = cmd.ExecuteReader();

               &lt;span style="color: blue"&gt;if &lt;/span&gt;(dr.Read())
               {
                   &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Convert&lt;/span&gt;.ToString(dr[&lt;span style="color: #a31515"&gt;&amp;quot;Description&amp;quot;&lt;/span&gt;]);
               }
           }

           &lt;span style="color: blue"&gt;return &lt;/span&gt;en.ToString();
       }&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;h3&gt;Switch / Case statement&lt;/h3&gt;

&lt;p&gt;Basically pass in the enum, and return a string. The only drawback I can think of about this one, is that you'd need to write one of these for each enumeration you use in your application.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public static string &lt;/span&gt;GetDescription(&lt;span style="color: #2b91af"&gt;UserColours &lt;/span&gt;en)
{
    &lt;span style="color: blue"&gt;switch &lt;/span&gt;(en)
    {
        &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #2b91af"&gt;UserColours&lt;/span&gt;.AliceBlue: &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;Alice Blue&amp;quot;&lt;/span&gt;;
        &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #2b91af"&gt;UserColours&lt;/span&gt;.BrightPink: &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;Bright Pink&amp;quot;&lt;/span&gt;;
        &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #2b91af"&gt;UserColours&lt;/span&gt;.BurntOrange: &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;Burnt Orange&amp;quot;&lt;/span&gt;;
        &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #2b91af"&gt;UserColours&lt;/span&gt;.DarkGreen: &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;Dark Green&amp;quot;&lt;/span&gt;;
        &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #2b91af"&gt;UserColours&lt;/span&gt;.SkyBlue: &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;Sky Blue&amp;quot;&lt;/span&gt;;
        &lt;span style="color: blue"&gt;default&lt;/span&gt;: &lt;span style="color: blue"&gt;return &lt;/span&gt;en.ToString();
    }
}&lt;/pre&gt;

&lt;h3&gt;Resources&lt;/h3&gt;

&lt;p&gt;Again, just read the value from a resources file, using the enumeration ToString() as the Name&amp;#160; &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public static string &lt;/span&gt;GetDescription(&lt;span style="color: #2b91af"&gt;Enum &lt;/span&gt;en)
{
    &lt;span style="color: blue"&gt;string &lt;/span&gt;s = Resources.&lt;span style="color: #2b91af"&gt;UserColoursResource&lt;/span&gt;.ResourceManager.GetString(en.ToString());

    &lt;span style="color: blue"&gt;if &lt;/span&gt;(!&lt;span style="color: blue"&gt;string&lt;/span&gt;.IsNullOrEmpty(s))
        &lt;span style="color: blue"&gt;return &lt;/span&gt;s;

    &lt;span style="color: blue"&gt;return &lt;/span&gt;en.ToString();

}&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/SpeedTestReflection_13284/image_2.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="174" alt="image" src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/SpeedTestReflection_13284/image_thumb.png" width="303" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;Xml File&lt;/h3&gt;

&lt;p&gt;Load up the Xml file, and use XPath to find the friendly name of the enum&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public static string &lt;/span&gt;GetDescription(&lt;span style="color: #2b91af"&gt;Enum &lt;/span&gt;en)
{
    &lt;span style="color: #2b91af"&gt;XmlDocument &lt;/span&gt;xmlDoc = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XmlDocument&lt;/span&gt;();

    xmlDoc.Load(&lt;span style="color: #2b91af"&gt;HttpContext&lt;/span&gt;.Current.Server.MapPath(&lt;span style="color: #a31515"&gt;&amp;quot;Enums.xml&amp;quot;&lt;/span&gt;));

    &lt;span style="color: #2b91af"&gt;XmlNode &lt;/span&gt;node = xmlDoc.SelectSingleNode(&lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(&lt;span style="color: #a31515"&gt;&amp;quot;enums/enum[@value = \&amp;quot;{0}\&amp;quot;]&amp;quot;&lt;/span&gt;, en.ToString()));

    &lt;span style="color: blue"&gt;if &lt;/span&gt;(node != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
    {
        &lt;span style="color: blue"&gt;return &lt;/span&gt;node.Attributes[&lt;span style="color: #a31515"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;].Value;
    }

    &lt;span style="color: blue"&gt;return &lt;/span&gt;en.ToString();
}&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color: #a31515"&gt;xml &lt;/span&gt;&lt;span style="color: red"&gt;version&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;1.0&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;encoding&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;utf-8&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;?&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;enums&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;enum &lt;/span&gt;&lt;span style="color: red"&gt;value&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;BurntOrange&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;description&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Burnt Orange&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;enum&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;enum &lt;/span&gt;&lt;span style="color: red"&gt;value&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;BrightPink&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;description&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Bright Pink&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;enum&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;enum &lt;/span&gt;&lt;span style="color: red"&gt;value&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;DarkGreen&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;description&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Dark Green&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;enum&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;enum &lt;/span&gt;&lt;span style="color: red"&gt;value&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;SkyBlue&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;description&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Sky Blue&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;enum&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;enum &lt;/span&gt;&lt;span style="color: red"&gt;value&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;AliceBlue&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;description&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Alice Blue&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;enum&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;enums&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;h3&gt;Resources with caching&lt;/h3&gt;

&lt;p&gt;This is effectively the same as my standard EnumHelper class library, except I've added a caching using the HttpContext Cache.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public static class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RelfectionEnumHelper
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;private static object &lt;/span&gt;padLock = &lt;span style="color: blue"&gt;new object&lt;/span&gt;();

    &lt;span style="color: blue"&gt;public static string &lt;/span&gt;GetDescription(&lt;span style="color: #2b91af"&gt;Enum &lt;/span&gt;en)
    {
        &lt;span style="color: #2b91af"&gt;Type &lt;/span&gt;type = en.GetType();

        &lt;span style="color: #2b91af"&gt;MemberInfo&lt;/span&gt;[] memInfo = type.GetMember(en.ToString());

        &lt;span style="color: blue"&gt;if &lt;/span&gt;(memInfo != &lt;span style="color: blue"&gt;null &lt;/span&gt;&amp;amp;&amp;amp; memInfo.Length &amp;gt; 0)
        {
            &lt;span style="color: blue"&gt;object&lt;/span&gt;[] attrs = memInfo[0].GetCustomAttributes(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;DescriptionAttribute&lt;/span&gt;), &lt;span style="color: blue"&gt;false&lt;/span&gt;);

            &lt;span style="color: blue"&gt;if &lt;/span&gt;(attrs != &lt;span style="color: blue"&gt;null &lt;/span&gt;&amp;amp;&amp;amp; attrs.Length &amp;gt; 0)
            {
                &lt;span style="color: blue"&gt;return &lt;/span&gt;((&lt;span style="color: #2b91af"&gt;DescriptionAttribute&lt;/span&gt;)attrs[0]).Description;
            }
        }

        &lt;span style="color: blue"&gt;return &lt;/span&gt;en.ToString();
    }


    &lt;span style="color: blue"&gt;public static string &lt;/span&gt;GetDescriptionUsingCache(&lt;span style="color: #2b91af"&gt;Enum &lt;/span&gt;en)
    {
        System.Web.Caching.&lt;span style="color: #2b91af"&gt;Cache &lt;/span&gt;cache = System.Web.&lt;span style="color: #2b91af"&gt;HttpContext&lt;/span&gt;.Current.Cache;

        &lt;span style="color: blue"&gt;if &lt;/span&gt;(cache[en.ToString()] == &lt;span style="color: blue"&gt;null&lt;/span&gt;)
        {
            &lt;span style="color: blue"&gt;lock &lt;/span&gt;(padLock)
            {
                &lt;span style="color: blue"&gt;if &lt;/span&gt;(cache[en.ToString()] == &lt;span style="color: blue"&gt;null&lt;/span&gt;)
                {
                    cache.Insert(en.ToString(), GetDescription(en));
                }
            }
        }

        &lt;span style="color: blue"&gt;return &lt;/span&gt;cache[en.ToString()].ToString();
    }
}&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Personally, I'm going to stick with using my EnumHelper library with caching. I'm really not that fussed about shaving 3ms of a page hit...&lt;/p&gt;

&lt;p&gt;The reasons I'll stick with this library are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;its nice and simple. The enum and its friendly name are located in the one spot. Developers are lazy.... if they have to maintain things in 2 or 3 different locations... plain and simple they won't! &lt;/li&gt;

  &lt;li&gt;its fast enough for me. None of my clients ever ask us to make it go faster. (There are usually other way we can make things run faster anyway) &lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6916046" width="1" height="1"&gt;</content><author><name>grant.barrington</name><uri>http://weblogs.asp.net/members/grant.barrington.aspx</uri></author><category term="asp.net" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/asp.net/default.aspx" /><category term="reflection" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/reflection/default.aspx" /></entry><entry><title>EnumHelper - Getting a Friendly Description from an Enum</title><link rel="alternate" type="text/html" href="http://weblogs.asp.net/grantbarrington/archive/2009/01/19/enumhelper-getting-a-friendly-description-from-an-enum.aspx" /><id>http://weblogs.asp.net/grantbarrington/archive/2009/01/19/enumhelper-getting-a-friendly-description-from-an-enum.aspx</id><published>2009-01-19T10:36:13Z</published><updated>2009-01-19T10:36:13Z</updated><content type="html">&lt;p&gt;Wherever possible we use enumerations in our applications. Often the name of the enumeration isn't what you want to print on the screen. It could be because the enumeration is 2 words that have been joined together, or you want the description to start with a number (not that we do this... but you could).&lt;/p&gt;  &lt;h2&gt;Example&lt;/h2&gt;  &lt;p&gt;You might have a enumeration for Colours that a user is allowed to select from. The values available for this enumeration may be (hypothetically):&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Burnt Orange &lt;/li&gt;    &lt;li&gt;Bright Pink &lt;/li&gt;    &lt;li&gt;Dark Green &lt;/li&gt;    &lt;li&gt;Sky Blue &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;To define this in code, you'd use an enumeration like this:&lt;/p&gt;  &lt;pre class="code" style="color: black"&gt;&lt;span style="color: blue"&gt;public enum &lt;/span&gt;&lt;span style="color: #2b91af"&gt;UserColours
&lt;/span&gt;{
    BurntOrange = 1,
    BrightPink = 2,
    DarkGreen = 3,
    SkyBlue = 4
}&lt;/pre&gt;

&lt;h2&gt;&lt;/h2&gt;

&lt;h2&gt;The Problem&lt;/h2&gt;

&lt;p&gt;Normally, in an ASP.NET application we'd render an enumeration as a Drop Down List. Problem is we don't want to show &amp;quot;BurntOrange&amp;quot; as a value in the drop down list, we want to show a nice friendly option like &amp;quot;Burnt Orange&amp;quot;.&lt;/p&gt;

&lt;h2&gt;The Solution&lt;/h2&gt;

&lt;p&gt;We've created a static helper class that uses reflection to get a Description for each member of the enumeration. I've also got this as an extension method for ASP.NET 3.5. This post is for the helper class, but it can very easily be converted to an extension method for ToString().&lt;/p&gt;

&lt;p&gt;To get a friendly name, we decorate each member of the enumeration with the &lt;strong&gt;DescriptionAttribute&lt;/strong&gt; from the namespace &lt;strong&gt;System.ComponentModel&lt;/strong&gt;. Our enums end up looking like this:&lt;/p&gt;

&lt;pre class="code" style="color: black"&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;System.ComponentModel;

&lt;span style="color: blue"&gt;namespace &lt;/span&gt;Ellington.EnumHelperExamples
{
    &lt;span style="color: blue"&gt;public enum &lt;/span&gt;&lt;span style="color: #2b91af"&gt;UserColours
    &lt;/span&gt;{
        [&lt;span style="color: #2b91af"&gt;Description&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Burnt Orange&amp;quot;&lt;/span&gt;)]
        BurntOrange = 1,

        [&lt;span style="color: #2b91af"&gt;Description&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Bright Pink&amp;quot;&lt;/span&gt;)]
        BrightPink = 2,

        [&lt;span style="color: #2b91af"&gt;Description&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Dark Green&amp;quot;&lt;/span&gt;)]
        DarkGreen = 3,

        [&lt;span style="color: #2b91af"&gt;Description&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Sky Blue&amp;quot;&lt;/span&gt;)]
        SkyBlue = 4
    }
}&lt;/pre&gt;

&lt;p&gt;When we need to then retrieve the friendly name from the enum, we have the following helper class:&lt;/p&gt;

&lt;pre class="code" style="color: black"&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;System;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.ComponentModel;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Reflection;

&lt;span style="color: blue"&gt;namespace &lt;/span&gt;Ellington.EnumHelperExamples 
{
    &lt;span style="color: blue"&gt;public static class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;EnumHelper
    &lt;/span&gt;{
        &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;
        /// &lt;/span&gt;&lt;span style="color: green"&gt;Retrieve the description on the enum, e.g.
        &lt;/span&gt;&lt;span style="color: gray"&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;[Description(&amp;quot;Bright Pink&amp;quot;)]
        &lt;/span&gt;&lt;span style="color: gray"&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;BrightPink = 2,
        &lt;/span&gt;&lt;span style="color: gray"&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;Then when you pass in the enum, it will retrieve the description
        &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&amp;quot;en&amp;quot;&amp;gt;The Enumeration&amp;lt;/param&amp;gt;
        /// &amp;lt;returns&amp;gt;A string representing the friendly name&amp;lt;/returns&amp;gt;
        &lt;/span&gt;&lt;span style="color: blue"&gt;public static string &lt;/span&gt;GetDescription(&lt;span style="color: #2b91af"&gt;Enum &lt;/span&gt;en)
        {
            &lt;span style="color: #2b91af"&gt;Type &lt;/span&gt;type = en.GetType();

            &lt;span style="color: #2b91af"&gt;MemberInfo&lt;/span&gt;[] memInfo = type.GetMember(en.ToString());

            &lt;span style="color: blue"&gt;if &lt;/span&gt;(memInfo != &lt;span style="color: blue"&gt;null &lt;/span&gt;&amp;amp;&amp;amp; memInfo.Length &amp;gt; 0)
            {
                &lt;span style="color: blue"&gt;object&lt;/span&gt;[] attrs = memInfo[0].GetCustomAttributes(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;DescriptionAttribute&lt;/span&gt;), &lt;span style="color: blue"&gt;false&lt;/span&gt;);

                &lt;span style="color: blue"&gt;if &lt;/span&gt;(attrs != &lt;span style="color: blue"&gt;null &lt;/span&gt;&amp;amp;&amp;amp; attrs.Length &amp;gt; 0)&lt;br /&gt;                {
                    &lt;span style="color: blue"&gt;return &lt;/span&gt;((&lt;span style="color: #2b91af"&gt;DescriptionAttribute&lt;/span&gt;)attrs[0]).Description;&lt;br /&gt;                }
            }

            &lt;span style="color: blue"&gt;return &lt;/span&gt;en.ToString();
        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Now, when we want to get the friendly name from the enum, all we do is call:&lt;/p&gt;

&lt;pre class="code" style="color: black"&gt;&lt;br /&gt;EnumHelper.GetDescription(UserColours.BrightPink);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The code above, basically takes in the enumeration, uses Reflection to find the &amp;quot;DescriptionAttribute&amp;quot; on the member, and then returns the Description. If the DescriptionAttribute is not present on the enum, then we just call a ToString() on the enum to get the name.&lt;/p&gt;

&lt;p&gt;As we're not hitting anything that is scary from a security point of view, the whole thing works in a partial trust environment.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6844557" width="1" height="1"&gt;</content><author><name>grant.barrington</name><uri>http://weblogs.asp.net/members/grant.barrington.aspx</uri></author><category term="asp.net" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/asp.net/default.aspx" /><category term="partial trust" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/partial+trust/default.aspx" /></entry><entry><title>Libraries in my toolkit - Another lesson in Partial Trust</title><link rel="alternate" type="text/html" href="http://weblogs.asp.net/grantbarrington/archive/2009/01/08/libraries-in-my-toolkit-another-lesson-in-partial-trust.aspx" /><id>http://weblogs.asp.net/grantbarrington/archive/2009/01/08/libraries-in-my-toolkit-another-lesson-in-partial-trust.aspx</id><published>2009-01-08T09:03:40Z</published><updated>2009-01-08T09:03:40Z</updated><content type="html">&lt;h1&gt;&lt;/h1&gt;  &lt;h1&gt;Introduction&lt;/h1&gt;  &lt;p&gt;I compiled a list of the libraries we use day-to-day in my company. There are a couple of home-grown libraries, but most are commercially available, or open source.&lt;/p&gt;  &lt;p&gt;&amp;quot;Yeah great... another person telling us which libraries they use...&amp;quot;. I hear you all say... The reason I've done this is because nearly all our sites operate under a partial trust environment. To get some of these libraries working under partial trust I've done the following:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;I've recompiled them myself &lt;/li&gt;    &lt;li&gt;I've had to provide detailed instructions on how to replicate issues &lt;/li&gt;    &lt;li&gt;I've been told &amp;quot;BAD LUCK&amp;quot;, we're not going to bother getting our dll working, so find a new one. (This was my personal favourite) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;All this and the only error you usually get is the dreaded &amp;quot;SecurityException&amp;quot; and an obfuscated stack trace.&lt;/p&gt;  &lt;p&gt;So, here they are... the libraries I use with great success.&lt;/p&gt;  &lt;h1&gt;&lt;/h1&gt;  &lt;h1&gt;Libraries I Use&lt;/h1&gt;  &lt;h2&gt;BusyBoxDotNet&lt;/h2&gt;  &lt;p&gt;This library is used to display a modal popup when a long-running process is occurring.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;a href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/Librariesinmytoolkit_13727/image_2.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="230" alt="image" src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/Librariesinmytoolkit_13727/image_thumb.png" width="456" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;We use it for a couple of reasons:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;to let the user know they really did press that &amp;quot;FINISH&amp;quot; button&amp;#160; &lt;/li&gt;    &lt;li&gt;to stop the user from pressing that &amp;quot;FINISH&amp;quot; button again &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;This library relies on the following:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;ICSharpCode.SharpZipLib.dll &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;To get this to work under partial trust, we needed to recompile both dll's.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sourceforge.net/projects/busybox"&gt;BusyBoxDotNet website&lt;/a&gt;&lt;/p&gt;  &lt;h2&gt;&lt;/h2&gt;  &lt;h2&gt;Aspose.Words, Aspose.Pdf&lt;/h2&gt;  &lt;p&gt;These 2 libraries combined make up an AWESOME PDF generator. The ability to have one of our clients create their own report in Word using mail merge fields, and for us to deploy just a .doc file to a server is FANTASTIC.&lt;/p&gt;  &lt;p&gt;It took a little while for us to get this working under a partial trust environment. A couple of issues were logged with ASPOSE to rectify some things, but it all worked out in the end. This library is now working extremely well. Getting it working fast (less than 0.5 seconds per document) with Unicode characters and using all fonts (not just the default PDF fonts of Times and Courier) was an interesting exercise. I'll try to publish an article in the near future about how we got this working...&lt;/p&gt;  &lt;p&gt;Basically we can go from a Word document like this below...&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/Librariesinmytoolkit_13727/image_4.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="116" alt="image" src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/Librariesinmytoolkit_13727/image_thumb_1.png" width="644" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;To a PDF document like this... &lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/Librariesinmytoolkit_13727/image_6.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="102" alt="image" src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/Librariesinmytoolkit_13727/image_thumb_2.png" width="644" border="0" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.aspose.com"&gt;Aspose Website&lt;/a&gt;&lt;/p&gt;  &lt;h2&gt;Aspose.Cells&lt;/h2&gt;  &lt;p&gt;This is a relatively new library for us and it does mostly what we need. There are a few things I've noticed about not running under partial trust. This is usually around setting and executing excel formulas in cells. Lucky for us, we use this mostly as a reporting tool and just dump tabular data into a spreadsheet.&lt;/p&gt;  &lt;h2&gt;iTextSharp&lt;/h2&gt;  &lt;p&gt;For more general PDF manipulation, we use iTextSharp. We use this library for the following (using a helper library we've created):&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;joining 2 or more PDF files into 1 to email to a user (rather than making a user download 4 PDF files, we roll them all up into 1 PDF and send that to them instead.... it make it easier for them to print that way) &lt;/li&gt;    &lt;li&gt;watermarking an existing PDF &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;You can use iTextSharp to do PDF generation, but its extremely low-level. Given the amount of times end-users change their mind when it comes to documents generated from our systems, it was well worth the money to ASPOSE to allow users to create their documents in Word.&lt;/p&gt;  &lt;p&gt;To get iTextSharp working under partial trust, we had to sign and recompile the whole library (and a related library from memory)&lt;/p&gt;  &lt;h2&gt;Microsoft Enterprise Library&lt;/h2&gt;  &lt;p&gt;We just use the Data Access Layer functionality from EntLib version 3.1 (and probably just a really small portion of that). We run all our data access through stored procedures and usually return either DataSets or DataReaders (depending on what we need).&lt;/p&gt;  &lt;p&gt;To get this working under partial trust was a MAMMOTH effort. The compiled libraries didn't come signed or partially trusted... thus they didn't work. We had to recompile the whole enterprise library.    &lt;br /&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I think the compiled libraries available for download are now signed.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.codeplex.com/entlib"&gt;Enterprise Library website&lt;/a&gt;&lt;/p&gt;  &lt;h2&gt;NLog&lt;/h2&gt;  &lt;p&gt;NLog is a really good logging library. We've use it in every project we start now.&lt;/p&gt;  &lt;p&gt;We believe that when designing and writing applications, supportability is key.    &lt;br /&gt;When logging information we keep the following information:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;every stored procedure we run (including all the aspnet membership SPs). We re-wrote them to include logging. Basically every stored proc run logs to a table before it exits &lt;/li&gt;    &lt;li&gt;every page execution (who, when and how long it took to run). I do this as a page handler (I'll try to write about this in the future) &lt;/li&gt;    &lt;li&gt;any exception (we have a global error page that handles errors which logs and display a friendly error to the user) &lt;/li&gt;    &lt;li&gt;anything else we way think necessary to help with diagnosis or supportability. eg run-times of reports &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;To get NLog working under partial trust required us to recompile the whole library from source. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.nlog-project.org/"&gt;Nlog Website&lt;/a&gt;&lt;/p&gt;  &lt;h2&gt;AJAX - AjaxControlToolKit, System.Web.Extensions&lt;/h2&gt;  &lt;p&gt;What web application could you start now without including AJAX somewhere in there???. For AJAX we use:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;System.Web.Extensions &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.codeplex.com/AjaxControlToolkit"&gt;AjaxControlToolkit&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.codeplex.com/mscui"&gt;NhsCui toolkit&lt;/a&gt; - We used this primarily for the &amp;quot;time picker&amp;quot; control. A very nice one... I like it. This was a pain to get working under partial trust though... In the file &amp;quot;CommonAssemblyInfo.cs&amp;quot; there is an attribute which requests full trust. In this web application this wasn't necessary, and works when you remove this attribute.       &lt;p&gt;[assembly: PermissionSet(SecurityAction.RequestMinimum, Name = &amp;quot;FullTrust&amp;quot;)]&lt;/p&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;NVelocity&lt;/h2&gt;  &lt;p&gt;We use NVelocity as our templating engine. Basically we use it as a mail-merge engine where we really just want either HTML or text as our output. We have wrapped a helper library around the standard NVelocity library as we don't use any of the functionality that reads templates from .vm files. We always pass in the template (usually stored in the DB) and our &amp;quot;merge fields&amp;quot; and retrieve the output from NVelocity.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.castleproject.org/others/nvelocity/index.html"&gt;NVelocity website&lt;/a&gt;&lt;/p&gt;  &lt;h1&gt;Home Grown Libraries we use for nearly every project&lt;/h1&gt;  &lt;p&gt;There are a couple of other home-grown libraries we use in almost every project.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;ForceSSL      &lt;br /&gt;&lt;/strong&gt;Running our applications on our hosting server, we can't get access to any IIS settings, specifically relating to SSL. Instead we have a HttpHandler that intercepts the page request, and redirects it to the same page, but using SSL.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Post Code Picker      &lt;br /&gt;&lt;/strong&gt;This control is similar to a Date Picker or Colour Picker. This control was written as a Extender using the AjaxControlToolkit and then turned into a composite user control. The user enters in the &amp;quot;Post Code&amp;quot; (Zip Code) and a list of available Suburbs (and States) appear retrieved from a web service.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/Librariesinmytoolkit_13727/image_8.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="198" alt="image" src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/Librariesinmytoolkit_13727/image_thumb_3.png" width="366" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/Librariesinmytoolkit_13727/image_10.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="51" alt="image" src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/Librariesinmytoolkit_13727/image_thumb_4.png" width="304" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Convert RTF to text      &lt;br /&gt;&lt;/strong&gt;One of our applications requires us to interface with an application that stores data in a BLOB field formatted as Rich Text (RTF). We've written a convertor that takes the raw RTF data and converts it to raw text (removes all formatting codes etc.). I'll try to publish how we do this later as well.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;ABN Lookup helper      &lt;br /&gt;&lt;/strong&gt;The Australian Government allows us to access company records using a publicly exposed &lt;a href="http://www.abr.business.gov.au/content.aspx?page=XMLWebService"&gt;web service&lt;/a&gt;. In Australia (as with most countries I guess) each company has an ABN (Australian Business Number). This web service is great, as is stops duplicate records from being entered in applications we've written and verifies that the ABN that a client has given us is really theirs.&lt;/p&gt;  &lt;p&gt;We've written a helper wrapper around the web service and drop this into our applications as a library, rather than reference the web service directly in every application we write.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Payment Provider (Commerce Starter Kit)      &lt;br /&gt;&lt;/strong&gt;In quite a few of our applications we have to interface with a payment gateway to process credit card transactions. We've taken the Payment Gateway provider that came with the original Commerce Starter Kit and re-rolled it. This allows us to:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;use the provider based model to connect to different gateways &lt;/li&gt;    &lt;li&gt;plug in a test gateway that approves all transactions (this is good for testing as most payment gateways use the cents value of the transaction to approve/decline a payment). eg 00 cents will pass, but 02 cents will return an error... Error number 02.. &lt;/li&gt; &lt;/ul&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6826275" width="1" height="1"&gt;</content><author><name>grant.barrington</name><uri>http://weblogs.asp.net/members/grant.barrington.aspx</uri></author><category term="asp.net" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/asp.net/default.aspx" /><category term="trust" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/trust/default.aspx" /><category term="partial trust" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/partial+trust/default.aspx" /><category term="Aspose" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/Aspose/default.aspx" /></entry><entry><title>How to Run a Website in Partial Trust</title><link rel="alternate" type="text/html" href="http://weblogs.asp.net/grantbarrington/archive/2008/12/29/how-to-run-a-website-in-partial-trust.aspx" /><id>http://weblogs.asp.net/grantbarrington/archive/2008/12/29/how-to-run-a-website-in-partial-trust.aspx</id><published>2008-12-29T05:12:54Z</published><updated>2008-12-29T05:12:54Z</updated><content type="html">&lt;p&gt;Nearly all our websites are hosted up on WebCentral. WebCentral operate all their websites under a partial (hosted) trust environment.&lt;/p&gt;  &lt;p&gt;Internally we develop all our sites using this partial trust setup as it just causes too many headaches to develop in full trust and then try to retrofit everything to work under partial trust.&lt;/p&gt;  &lt;p&gt;We originally received instructions on how to setup a machine to run in partial trust, but it involved editing config files located under the C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG directory. While this is fine, if I wanted to test something quick and simple (and didn't care about partial trust), I'd have to rename files, restart IIS, close Cassini... blah blah blah... too hard..&lt;/p&gt;  &lt;p&gt;A little while ago I discovered how to run just a site as partial trust. It involves putting the hostedtrust.config file in the same directory as the web.config file. This works well for us, as it means we can add all the files we require to a project, which are all then added to SourceSafe. When we get the latest version, we also get all required files to run in partial trust.&lt;/p&gt;  &lt;h2&gt;Instructions&lt;/h2&gt;  &lt;p&gt;We were given the hosted trust setup from WebCentral as they dictate.&lt;/p&gt;  &lt;p&gt;Copy this file into the root directory of your website.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/HOWTORUNAPROJECTINPARTIALTRUST_F2F1/image_2.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="154" alt="image" src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/HOWTORUNAPROJECTINPARTIALTRUST_F2F1/image_thumb.png" width="257" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;In your web.config file add the following into the &amp;quot;system.web&amp;quot; configuration section.&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;!-- &lt;/span&gt;&lt;span style="color: green"&gt;**************************************************** &lt;/span&gt;&lt;span style="color: blue"&gt;--&amp;gt;
&amp;lt;!-- &lt;/span&gt;&lt;span style="color: green"&gt;WEBCENTRAL HOSTED TRUST CONFIG &lt;/span&gt;&lt;span style="color: blue"&gt;--&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;securityPolicy&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;trustLevel &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Hosted2&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;policyFile&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;web_hostedtrust2.config&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;trustLevel&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;securityPolicy&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;!-- &lt;/span&gt;&lt;span style="color: green"&gt;Comment out line below to run in FULL TRUST &lt;/span&gt;&lt;span style="color: blue"&gt;--&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;trust &lt;/span&gt;&lt;span style="color: red"&gt;level&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Hosted2&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;originUrl&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;

&amp;lt;!-- &lt;/span&gt;&lt;span style="color: green"&gt;**************************************************** &lt;/span&gt;&lt;span style="color: blue"&gt;--&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Below is a screen shot of what my web.config file looks like. &lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/HOWTORUNAPROJECTINPARTIALTRUST_F2F1/image_4.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="423" alt="image" src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/HOWTORUNAPROJECTINPARTIALTRUST_F2F1/image_thumb_1.png" width="766" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;If you ever need to run the site in full trust to test something out, just comment out the &amp;quot;trust&amp;quot; element.&lt;/p&gt;

&lt;h2&gt;What libraries I use (and don't use)&lt;/h2&gt;

&lt;p&gt;In my next post I'll list out the libraries I use in Partial Trust... and the one's I don't use and why. &lt;/p&gt;

&lt;p&gt;I've had pretty good success getting sites working that need server-side image manipulation, ZIP creation and PDF creation / manipulation.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6808565" width="1" height="1"&gt;</content><author><name>grant.barrington</name><uri>http://weblogs.asp.net/members/grant.barrington.aspx</uri></author><category term="asp.net" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/asp.net/default.aspx" /><category term="trust" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/trust/default.aspx" /><category term="partial trust" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/partial+trust/default.aspx" /></entry><entry><title>Preventing a User From Submitting a Form Twice</title><link rel="alternate" type="text/html" href="http://weblogs.asp.net/grantbarrington/archive/2008/12/06/preventing-a-user-from-submitting-a-form-twice.aspx" /><link rel="enclosure" type="application/octet-stream" length="22576" href="http://weblogs.asp.net/grantbarrington/attachment/6768033.ashx" /><id>http://weblogs.asp.net/grantbarrington/archive/2008/12/06/preventing-a-user-from-submitting-a-form-twice.aspx</id><published>2008-12-06T06:11:00Z</published><updated>2008-12-06T06:11:00Z</updated><content type="html">&lt;P&gt;When building web applications, we've had a "defect" reported a number of times where a user presses a button twice in quick succession and causes a postback twice, typically causing whatever server-side code you've written to run twice.&lt;/P&gt;
&lt;P&gt;Fellow developers usually dismiss this "defect" and say "can't the user just press the button once and wait?". Short answer, NO.&lt;/P&gt;
&lt;P&gt;I've solved this in the past a few different ways. &lt;/P&gt;
&lt;P&gt;For long running tasks I use &lt;A href="http://sourceforge.net/projects/busybox" mce_href="http://sourceforge.net/projects/busybox"&gt;BusyBoxDotNet&lt;/A&gt;. This basically uses the same concept as the ModalPopup through the AJAX Control Toolkit, but it hooks into the browser's onbeforeunload event. As it places a modal popup over the page, it prevents the user from pressing the submit button again. &lt;/P&gt;
&lt;P&gt;This week, I needed a quick and easy way to prevent a user from submitting twice, and found it thanks to &lt;A href="http://jquery.com/" mce_href="http://jquery.com/"&gt;jQuery&lt;/A&gt;.&lt;/P&gt;
&lt;H2&gt;Screenshot&lt;/H2&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/PreventingaUserFromSubmittingaFormTwice_EFD6/image_2.png" mce_href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/PreventingaUserFromSubmittingaFormTwice_EFD6/image_2.png"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=376 alt=image src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/PreventingaUserFromSubmittingaFormTwice_EFD6/image_thumb.png" width=512 border=0 mce_src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/PreventingaUserFromSubmittingaFormTwice_EFD6/image_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;On the screenshot above, you can see that I've got a TextBox (which has a RequiredFieldValidator). In my button press event, I've got a Thread.Sleep(1000) to simulate a long running task.&lt;/P&gt;
&lt;P&gt;If the user tries clicking the textbox after the page has already submitted, you get the alert message above.&lt;/P&gt;
&lt;H3&gt;Show me the code....&lt;/H3&gt;
&lt;P&gt;The magic happens in the following piece of javascript code...&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/PreventingaUserFromSubmittingaFormTwice_EFD6/image_6.png" mce_href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/PreventingaUserFromSubmittingaFormTwice_EFD6/image_6.png"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=723 alt=image src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/PreventingaUserFromSubmittingaFormTwice_EFD6/image_thumb_2.png" width=686 border=0 mce_src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/PreventingaUserFromSubmittingaFormTwice_EFD6/image_thumb_2.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Breaking it down.&lt;/P&gt;
&lt;P&gt;Add a reference to the jQuery library, then call "noConflict()". (I like to call jQuery by its name, not using $)&lt;/P&gt;
&lt;P&gt;I keep a javascript variable called "submitted" which initially is set to false.&lt;/P&gt;
&lt;P&gt;Using jQuery, I hook up an event handler for the document ready event. This function finds (using jQuery selectors) the Page's Form.ClientID (so you can call the form what you want). When "submit" is called on the form, run the event handler. &lt;/P&gt;
&lt;P&gt;I have to wrap "Page_IsValid" in a try..catch as Page_IsValid may NOT be on the page. This happens when there are no validators on the page. &lt;/P&gt;
&lt;P&gt;If the form is valid, and it hasn't been submitted already, then all we do is update the "submitted" variable to TRUE. &lt;BR&gt;If the form is valid, but the page HAS been submitted, then we call "preventDefault()" which stops form submission, and alert() to the user.&lt;/P&gt;
&lt;H3&gt;Important Notes&lt;/H3&gt;
&lt;P&gt;The important part here is that when we subscribe to the "submit" event in jQuery, it APPENDS our code to whatever is already there, it DOES NOT replace the code. I've struggled in the past with trying to get this to work, as you need to check if the form is submitted AFTER all the ASP.NET validators have run.&lt;/P&gt;
&lt;H3&gt;In the past some of the things I've tried are:&lt;/H3&gt;
&lt;P&gt;&lt;B&gt;Using the Page.RegisterOnSubmitStatement()&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;This registers the javascript function before the WebForm_OnSubmit() function call.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/PreventingaUserFromSubmittingaFormTwice_EFD6/image_8.png" mce_href="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/PreventingaUserFromSubmittingaFormTwice_EFD6/image_8.png"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=71 alt=image src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/PreventingaUserFromSubmittingaFormTwice_EFD6/image_thumb_3.png" width=965 border=0 mce_src="http://weblogs.asp.net/blogs/grantbarrington/WindowsLiveWriter/PreventingaUserFromSubmittingaFormTwice_EFD6/image_thumb_3.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Creating my own FORM class by overriding HtmlForm&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;I quickly tried this and tried to override OnPreRender() and RenderAttributes() and could never get my javascript AFTER the WebForm_OnSubmit() code.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Disabling / hiding buttons after they've been pressed&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;This is probably the easiest method of stopping submission of a page twice, but you have to be careful you don't disable the button BEFORE you check for validation errors, otherwise your user will never be able to submit a page.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Use BusyBoxDotNet&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;For really long running postbacks (eg payment gateway transactions), we use BusyBoxDotNet. As all our sites are hosted at &lt;A href="http://www.webcentral.com.au/" mce_href="http://www.webcentral.com.au/"&gt;WebCentral&lt;/A&gt; we've had to roll our own version to ensure it runs under a partial trust environment.&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6768033" width="1" height="1"&gt;</content><author><name>grant.barrington</name><uri>http://weblogs.asp.net/members/grant.barrington.aspx</uri></author><category term="asp.net" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/asp.net/default.aspx" /><category term="jQuery" scheme="http://weblogs.asp.net/grantbarrington/archive/tags/jQuery/default.aspx" /></entry></feed>