<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" version="2.0">
  <channel>
    <title>Manuel Abadia's ASP.NET stuff</title>
    <link>http://www.manuelabadia.com/blog/</link>
    <description />
    <language>en-us</language>
    <copyright>Manuel Abadia</copyright>
    <lastBuildDate>Mon, 22 Dec 2008 23:35:20 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.3.12105.0</generator>
    <managingEditor>blogcomments@manuelabadia.com</managingEditor>
    <webMaster>blogcomments@manuelabadia.com</webMaster>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=0606d95f-56ae-4dd7-8458-69cd550fa356</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,0606d95f-56ae-4dd7-8458-69cd550fa356.aspx</pingback:target>
      <dc:creator>Manu</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,0606d95f-56ae-4dd7-8458-69cd550fa356.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=0606d95f-56ae-4dd7-8458-69cd550fa356</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
All controls that inherit from ListControl (BulletedList, CheckBoxList, DropDownList,
ListBox and RadioButtonList) have some annoying behavior in common: 
</p>
        <p>
You can only bind the control to a single property using the DataTextField property.
For example, if you have a Customer class with properties Id, Name, Surname, etc and
you want to show the full name of a customer in any of the ListControls, you have
several options:
</p>
        <ol>
          <li>
When you get the data from the database, return another column with the name and surname. 
</li>
          <li>
Create a property (f.e. FullName) that returns what you want to show. 
</li>
          <li>
Use a DataSet and add a computed column. 
</li>
          <li>
Manually add ListItems with the appropriate values performing the data bind manually. 
</li>
          <li>
Create a simple class that will be bound (instead of the original one) just to fix
the problem.</li>
        </ol>
        <p>
The truth is that I don’t like any of those options, all of them are hacks. 
</p>
        <p>
For nested properties you have the similar problems. You can bind to Id or Name, but
you can’t bind to Address.City or Address.Zip.
</p>
        <p>
Today I faced this problem again and I decided to investigate a more innovative solution.
The problem itself is in the controls that inherit from ListControl that are very
strict in the binding options. So I took a look of how the controls perform the binding
to see if I could do anything to overcome those limitations. At first sight I thought
I was loosing my time but after a deeper study I found that it was amazingly easy
to fix those problems in a very sleek way.
</p>
        <p>
The data binding of the controls is performed in the PerformDataBinding method. The
code at ListControl.PerformDataBinding uses DataBinder.GetPropertyValue to retrieve
the value to show in the control if you set the DataTextField property. However, DataBinder.GetPropertyValue
doesn’t handle nested properties. DataBinder.Eval is a better choice because it does
handle nested properties. So using it we solve one problem. The other problem can
be solved easily as well. As we have two properties that control how the Text of each
ListItem will be extracted and shown from the data source, with a bit more of effort
we can handle the new functionality. I have come up with a very intuitive solution:
</p>
        <ul>
          <li>
DataTextField allows one or more properties (that can be nested if needed) separated
by commas. 
</li>
          <li>
DataTextFormatString can be used to control the formatting of the items, using {0},
{1}, {2}, {3}… as the value of the properties specified with DataTextField.</li>
        </ul>
        <p>
The code that performs the data binding is:
</p>
        <div class="csharp" style="BORDER-RIGHT: #d0d0d0 1px solid; BORDER-TOP: #d0d0d0 1px solid; BORDER-LEFT: #d0d0d0 1px solid; COLOR: #006; BORDER-BOTTOM: #d0d0d0 1px solid; FONT-FAMILY: monospace; BACKGROUND-COLOR: #f0f0f0">
          <span style="COLOR: #008080; FONT-STYLE: italic">///
&lt;summary&gt;Binds the data to the control.&lt;/summary&gt;</span>
          <br />
          <span style="COLOR: #008080; FONT-STYLE: italic">/// &lt;param name="ctrl"&gt;control
to bind.&lt;/param&gt;</span>
          <br />
          <span style="COLOR: #008080; FONT-STYLE: italic">/// &lt;param name="dataSource"&gt;data
to bind to the control.&lt;/param&gt;</span>
          <br />
          <span style="COLOR: #0600ff">public</span>
          <span style="COLOR: #0600ff">static</span>
          <span style="COLOR: #0600ff">void</span> PerformDataBinding<span style="COLOR: #000000">(</span>ListControl
ctrl, IEnumerable dataSource<span style="COLOR: #000000">)</span><br /><span style="COLOR: #000000">{</span><br />
    <span style="COLOR: #008080; FONT-STYLE: italic">// resets the selected
item</span><br />
    ctrl.<span style="COLOR: #0000ff">SelectedIndex</span><span style="COLOR: #008000">=</span><span style="COLOR: #008000">-</span><span style="COLOR: #ff0000">1</span><span style="COLOR: #008000">;</span><br />
    ctrl.<span style="COLOR: #0000ff">SelectedValue</span><span style="COLOR: #008000">=</span> null<span style="COLOR: #008000">;</span><br /><br />
    <span style="COLOR: #0600ff">if</span><span style="COLOR: #000000">(</span>dataSource <span style="COLOR: #008000">!=</span><span style="COLOR: #0600ff">null</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />
        <span style="COLOR: #ff0000">bool</span> fieldInfoSet <span style="COLOR: #008000">=</span> false<span style="COLOR: #008000">;</span><br />
        <span style="COLOR: #ff0000">bool</span> dataTextFormatStringSet <span style="COLOR: #008000">=</span> false<span style="COLOR: #008000">;</span><br /><br />
        <span style="COLOR: #008080; FONT-STYLE: italic">// checks
if we have to clear the existing items</span><br />
        <span style="COLOR: #0600ff">if</span><span style="COLOR: #000000">(</span><span style="COLOR: #008000">!</span>ctrl.<span style="COLOR: #0000ff">AppendDataBoundItems</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />
            ctrl.<span style="COLOR: #0000ff">Items</span>.<span style="COLOR: #0000ff">Clear</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span><span style="COLOR: #008000">;</span><br />
        <span style="COLOR: #000000">}</span><br /><br />
        <span style="COLOR: #008080; FONT-STYLE: italic">// if
the data source is a collection, sets the capacity</span><br />
        ICollection soureceCollection <span style="COLOR: #008000">=</span> dataSource <span style="COLOR: #0600ff">as</span> ICollection<span style="COLOR: #008000">;</span><br />
        <span style="COLOR: #0600ff">if</span><span style="COLOR: #000000">(</span>soureceCollection <span style="COLOR: #008000">!=</span><span style="COLOR: #0600ff">null</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />
            ctrl.<span style="COLOR: #0000ff">Items</span>.<span style="COLOR: #0000ff">Capacity</span><span style="COLOR: #008000">=</span> soureceCollection.<span style="COLOR: #0000ff">Count</span><span style="COLOR: #008000">+</span> ctrl.<span style="COLOR: #0000ff">Items</span>.<span style="COLOR: #0000ff">Count</span><span style="COLOR: #008000">;</span><br />
        <span style="COLOR: #000000">}</span><br /><br />
        <span style="COLOR: #008080; FONT-STYLE: italic">// save
if the data text field of data value field has been set</span><br />
        <span style="COLOR: #0600ff">if</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">(</span>ctrl.<span style="COLOR: #0000ff">DataTextField</span>.<span style="COLOR: #0000ff">Length</span><span style="COLOR: #008000">!=</span><span style="COLOR: #ff0000">0</span><span style="COLOR: #000000">)</span><span style="COLOR: #008000">||</span><span style="COLOR: #000000">(</span>ctrl.<span style="COLOR: #0000ff">DataValueField</span>.<span style="COLOR: #0000ff">Length</span><span style="COLOR: #008000">!=</span><span style="COLOR: #ff0000">0</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />
            fieldInfoSet <span style="COLOR: #008000">=</span> true<span style="COLOR: #008000">;</span><br />
        <span style="COLOR: #000000">}</span><br /><br />
        <span style="COLOR: #008080; FONT-STYLE: italic">// save
if the data text format string has been set</span><br />
        <span style="COLOR: #0600ff">if</span><span style="COLOR: #000000">(</span>ctrl.<span style="COLOR: #0000ff">DataTextFormatString</span>.<span style="COLOR: #0000ff">Length</span><span style="COLOR: #008000">!=</span><span style="COLOR: #ff0000">0</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />
            dataTextFormatStringSet <span style="COLOR: #008000">=</span> true<span style="COLOR: #008000">;</span><br />
        <span style="COLOR: #000000">}</span><br /><br />
        <span style="COLOR: #008080; FONT-STYLE: italic">// iterates
through the data source creating the ListItems</span><br />
        <span style="COLOR: #0600ff">foreach</span><span style="COLOR: #000000">(</span><span style="COLOR: #ff0000">object</span> obj <span style="COLOR: #0600ff">in</span> dataSource<span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />
            ListItem item <span style="COLOR: #008000">=</span><a style="COLOR: #000060" href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="COLOR: #008000">new</span></a> ListItem<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span><span style="COLOR: #008000">;</span><br /><br />
            <span style="COLOR: #0600ff">if</span><span style="COLOR: #000000">(</span>fieldInfoSet<span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />
                <span style="COLOR: #0600ff">if</span><span style="COLOR: #000000">(</span>ctrl.<span style="COLOR: #0000ff">DataTextField</span>.<span style="COLOR: #0000ff">Length</span><span style="COLOR: #008000">&gt;</span><span style="COLOR: #ff0000">0</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />
                    <span style="COLOR: #0600ff">if</span><span style="COLOR: #000000">(</span>ctrl.<span style="COLOR: #0000ff">DataTextField</span>.<span style="COLOR: #0000ff">IndexOf</span><span style="COLOR: #000000">(</span><span style="COLOR: #666666">','</span><span style="COLOR: #000000">)</span><span style="COLOR: #008000">==</span><span style="COLOR: #008000">-</span><span style="COLOR: #ff0000">1</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />
                       
item.<span style="COLOR: #0000ff">Text</span><span style="COLOR: #008000">=</span> DataBinder.<span style="COLOR: #0000ff">Eval</span><span style="COLOR: #000000">(</span>obj,
ctrl.<span style="COLOR: #0000ff">DataTextField</span>, ctrl.<span style="COLOR: #0000ff">DataTextFormatString</span><span style="COLOR: #000000">)</span><span style="COLOR: #008000">;</span><br />
                    <span style="COLOR: #000000">}</span><span style="COLOR: #0600ff">else</span><span style="COLOR: #000000">{</span><br />
                        <span style="COLOR: #008080; FONT-STYLE: italic">//
if the DataTextField property has a list of fields, get them to create the text of
the item</span><br />
                        <span style="COLOR: #ff0000">string</span><span style="COLOR: #000000">[</span><span style="COLOR: #000000">]</span> fields <span style="COLOR: #008000">=</span> ctrl.<span style="COLOR: #0000ff">DataTextField</span>.<span style="COLOR: #0000ff">Split</span><span style="COLOR: #000000">(</span><a style="COLOR: #000060" href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="COLOR: #008000">new</span></a><span style="COLOR: #ff0000">string</span><span style="COLOR: #000000">[</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">{</span><span style="COLOR: #666666">","</span><span style="COLOR: #000000">}</span>,
StringSplitOptions.<span style="COLOR: #0000ff">RemoveEmptyEntries</span><span style="COLOR: #000000">)</span><span style="COLOR: #008000">;</span><br />
                        <span style="COLOR: #ff0000">object</span><span style="COLOR: #000000">[</span><span style="COLOR: #000000">]</span> values <span style="COLOR: #008000">=</span><a style="COLOR: #000060" href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="COLOR: #008000">new</span></a><span style="COLOR: #ff0000">object</span><span style="COLOR: #000000">[</span>fields.<span style="COLOR: #0000ff">Length</span><span style="COLOR: #000000">]</span><span style="COLOR: #008000">;</span><br /><br />
                        <span style="COLOR: #0600ff">for</span><span style="COLOR: #000000">(</span><span style="COLOR: #ff0000">int</span> i <span style="COLOR: #008000">=</span><span style="COLOR: #ff0000">0</span><span style="COLOR: #008000">;</span> i <span style="COLOR: #008000">&lt;</span> fields.<span style="COLOR: #0000ff">Length</span><span style="COLOR: #008000">;</span> i<span style="COLOR: #008000">++</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />
                       
    <span style="COLOR: #ff0000">string</span> field <span style="COLOR: #008000">=</span> fields<span style="COLOR: #000000">[</span>i<span style="COLOR: #000000">]</span><span style="COLOR: #008000">;</span><br />
                       
    values<span style="COLOR: #000000">[</span>i<span style="COLOR: #000000">]</span><span style="COLOR: #008000">=</span> DataBinder.<span style="COLOR: #0000ff">Eval</span><span style="COLOR: #000000">(</span>obj,
field<span style="COLOR: #000000">)</span><span style="COLOR: #008000">;</span><br />
                        <span style="COLOR: #000000">}</span><br /><br />
                       
item.<span style="COLOR: #0000ff">Text</span><span style="COLOR: #008000">=</span><span style="COLOR: #ff0000">String</span>.<span style="COLOR: #0000ff">Format</span><span style="COLOR: #000000">(</span>ctrl.<span style="COLOR: #0000ff">DataTextFormatString</span>,
values<span style="COLOR: #000000">)</span><span style="COLOR: #008000">;</span><br />
                    <span style="COLOR: #000000">}</span><br />
                <span style="COLOR: #000000">}</span><br />
                <span style="COLOR: #0600ff">if</span><span style="COLOR: #000000">(</span>ctrl.<span style="COLOR: #0000ff">DataValueField</span>.<span style="COLOR: #0000ff">Length</span><span style="COLOR: #008000">&gt;</span><span style="COLOR: #ff0000">0</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />
                    item.<span style="COLOR: #0000ff">Value</span><span style="COLOR: #008000">=</span> DataBinder.<span style="COLOR: #0000ff">Eval</span><span style="COLOR: #000000">(</span>obj,
ctrl.<span style="COLOR: #0000ff">DataValueField</span>, <span style="COLOR: #0600ff">null</span><span style="COLOR: #000000">)</span><span style="COLOR: #008000">;</span><br />
                <span style="COLOR: #000000">}</span><br />
            <span style="COLOR: #000000">}</span><span style="COLOR: #0600ff">else</span><span style="COLOR: #000000">{</span><br />
                <span style="COLOR: #0600ff">if</span><span style="COLOR: #000000">(</span>dataTextFormatStringSet<span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />
                    item.<span style="COLOR: #0000ff">Text</span><span style="COLOR: #008000">=</span><span style="COLOR: #ff0000">string</span>.<span style="COLOR: #0000ff">Format</span><span style="COLOR: #000000">(</span>CultureInfo.<span style="COLOR: #0000ff">CurrentCulture</span>,
ctrl.<span style="COLOR: #0000ff">DataTextFormatString</span>, <a style="COLOR: #000060" href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="COLOR: #008000">new</span></a><span style="COLOR: #ff0000">object</span><span style="COLOR: #000000">[</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">{</span> obj <span style="COLOR: #000000">}</span><span style="COLOR: #000000">)</span><span style="COLOR: #008000">;</span><br />
                <span style="COLOR: #000000">}</span><span style="COLOR: #0600ff">else</span><span style="COLOR: #000000">{</span><br />
                    item.<span style="COLOR: #0000ff">Text</span><span style="COLOR: #008000">=</span> obj.<span style="COLOR: #0000ff">ToString</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span><span style="COLOR: #008000">;</span><br />
                <span style="COLOR: #000000">}</span><br />
                item.<span style="COLOR: #0000ff">Value</span><span style="COLOR: #008000">=</span> obj.<span style="COLOR: #0000ff">ToString</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span><span style="COLOR: #008000">;</span><br />
            <span style="COLOR: #000000">}</span><br />
            
<br />
            ctrl.<span style="COLOR: #0000ff">Items</span>.<span style="COLOR: #0000ff">Add</span><span style="COLOR: #000000">(</span>item<span style="COLOR: #000000">)</span><span style="COLOR: #008000">;</span><br />
        <span style="COLOR: #000000">}</span><br />
    <span style="COLOR: #000000">}</span><br /><span style="COLOR: #000000">}</span></div>
        <p>
 
</p>
        <p>
As we need to call this data binding code instead of the one from ListControl I needed
to subclass all controls that inherit from ListControl in order to fix them. So now
I have BulletedListEx, CheckBoxListEx, DropDownListEx, ListBoxEx and RadioButtonListEx.
</p>
        <p>
I have created a simple example showing how to use them. Imagine that an Item can
be supplied by a set of suppliers, and each supplier sells the item with a different
price. The following image shows the properties of the 3 entities of the sample:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/listcontrolex_sample.png" border="0" />
        </p>
        <p>
I have created a web page with a DropDownList with some items, and when you select
an item in the DropDownList you will see a ListBox with the all suppliers of that
item with the associated price for the item. Notice how I show the Id and the Name
in the DropDownList and how I show the price, supplier Id and supplier name in the
ListBox:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/listcontrolex_sample2.png" border="0" />
        </p>
        <p>
The ASPX of the page follows:
</p>
        <div class="xml" style="BORDER-RIGHT: #d0d0d0 1px solid; BORDER-TOP: #d0d0d0 1px solid; BORDER-LEFT: #d0d0d0 1px solid; COLOR: #006; BORDER-BOTTOM: #d0d0d0 1px solid; FONT-FAMILY: monospace; BACKGROUND-COLOR: #f0f0f0">
          <span style="COLOR: #009900">
            <span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;body<span style="FONT-WEIGHT: bold; COLOR: #000000">&gt;</span></span>
          </span>
          <br />
    <span style="COLOR: #009900"><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;form</span><span style="COLOR: #000066">id</span>=<span style="COLOR: #ff0000">"form1"</span><span style="COLOR: #000066">runat</span>=<span style="COLOR: #ff0000">"server"</span><span style="FONT-WEIGHT: bold; COLOR: #000000">&gt;</span></span><br />
    <span style="COLOR: #009900"><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;div<span style="FONT-WEIGHT: bold; COLOR: #000000">&gt;</span></span></span><br />
    <span style="COLOR: #009900"><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;/div<span style="FONT-WEIGHT: bold; COLOR: #000000">&gt;</span></span></span><br />
        Choose an item to see the suppliers:<span style="COLOR: #009900"><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;br</span><span style="FONT-WEIGHT: bold; COLOR: #000000">/&gt;</span></span><br />
        Items:<span style="COLOR: #009900"><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;br</span><span style="FONT-WEIGHT: bold; COLOR: #000000">/&gt;</span></span><br />
        <span style="COLOR: #009900"><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;manu:DropDownListEx</span><span style="COLOR: #000066">ID</span>=<span style="COLOR: #ff0000">"DropDownListEx1"</span><span style="COLOR: #000066">runat</span>=<span style="COLOR: #ff0000">"server"</span><span style="COLOR: #000066">AutoPostBack</span>=<span style="COLOR: #ff0000">"True"</span><span style="COLOR: #000066">Width</span>=<span style="COLOR: #ff0000">"300px"</span></span><br /><span style="COLOR: #009900">            <span style="COLOR: #000066">DataTextField</span>=<span style="COLOR: #ff0000">"Id,
Name"</span></span><br /><span style="COLOR: #009900">            <span style="COLOR: #000066">DataTextFormatString</span>=<span style="COLOR: #ff0000">"[{0}]
- {1}"</span></span><br /><span style="COLOR: #009900">            <span style="COLOR: #000066">DataValueField</span>=<span style="COLOR: #ff0000">"Id"</span></span><br /><span style="COLOR: #009900">            <span style="COLOR: #000066">OnSelectedIndexChanged</span>=<span style="COLOR: #ff0000">"DropDownListEx1_SelectedIndexChanged"</span><span style="COLOR: #000066">AppendDataBoundItems</span>=<span style="COLOR: #ff0000">"True"</span><span style="FONT-WEIGHT: bold; COLOR: #000000">&gt;</span></span><br />
            <span style="COLOR: #009900"><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;asp:ListItem</span><span style="COLOR: #000066">Selected</span>=<span style="COLOR: #ff0000">"True"</span><span style="COLOR: #000066">Value</span>=<span style="COLOR: #ff0000">"0"</span><span style="FONT-WEIGHT: bold; COLOR: #000000">&gt;</span></span>Select
an Item<span style="COLOR: #009900"><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;/asp:ListItem<span style="FONT-WEIGHT: bold; COLOR: #000000">&gt;</span></span></span><br />
        <span style="COLOR: #009900"><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;/manu:DropDownListEx<span style="FONT-WEIGHT: bold; COLOR: #000000">&gt;</span></span><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;br</span><span style="FONT-WEIGHT: bold; COLOR: #000000">/&gt;</span></span><br />
        
<br />
        Price and suppliers:<span style="COLOR: #009900"><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;br</span><span style="FONT-WEIGHT: bold; COLOR: #000000">/&gt;</span></span><br />
        
<br />
        <span style="COLOR: #009900"><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;manu:ListBoxEx</span><span style="COLOR: #000066">ID</span>=<span style="COLOR: #ff0000">"ListBoxEx1"</span><span style="COLOR: #000066">runat</span>=<span style="COLOR: #ff0000">"server"</span><span style="COLOR: #000066">Width</span>=<span style="COLOR: #ff0000">"300px"</span></span><br /><span style="COLOR: #009900">            <span style="COLOR: #000066">DataTextField</span>=<span style="COLOR: #ff0000">"Price,
Supplier.Id, Supplier.Name"</span></span><br /><span style="COLOR: #009900">            <span style="COLOR: #000066">DataTextFormatString</span>=<span style="COLOR: #ff0000">"{0}
- [{1}] {2}"</span></span><br /><span style="COLOR: #009900">            <span style="COLOR: #000066">DataValueField</span>=<span style="COLOR: #ff0000">"Supplier.Id"</span><span style="FONT-WEIGHT: bold; COLOR: #000000">&gt;</span></span><br />
        <span style="COLOR: #009900"><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;/manu:ListBoxEx<span style="FONT-WEIGHT: bold; COLOR: #000000">&gt;</span></span></span><br />
    <span style="COLOR: #009900"><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;/form<span style="FONT-WEIGHT: bold; COLOR: #000000">&gt;</span></span></span><br /><span style="COLOR: #009900"><span style="FONT-WEIGHT: bold; COLOR: #000000">&lt;/body<span style="FONT-WEIGHT: bold; COLOR: #000000">&gt;</span></span></span></div>
        <p>
 
</p>
        <p>
As you can see, the solution is really clean and elegant, and backward compatible
with the current controls that inherit from ListControl.
</p>
        <p>
That’s all for now,<br />
Merry christmas!
</p>
        <p>
          <a href="http://www.manuelabadia.com/blog/content/binary/ListControlsEx_bin.zip">ListControlsEx_bin.zip
(6.53 KB)</a>
        </p>
        <a href="http://www.manuelabadia.com/blog/content/binary/ListControlsEx_sample.zip">ListControlsEx_sample.zip
(33.75 KB)</a>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=0606d95f-56ae-4dd7-8458-69cd550fa356" />
      </body>
      <title>Binding a DropDownList to multiple properties and to nested properties</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,0606d95f-56ae-4dd7-8458-69cd550fa356.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,0606d95f-56ae-4dd7-8458-69cd550fa356.aspx</link>
      <pubDate>Mon, 22 Dec 2008 23:35:20 GMT</pubDate>
      <description>&lt;p&gt;
All controls that inherit from ListControl (BulletedList, CheckBoxList, DropDownList,
ListBox and RadioButtonList) have some annoying behavior in common: 
&lt;/p&gt;
&lt;p&gt;
You can only bind the control to a single property using the DataTextField property.
For example, if you have a Customer class with properties Id, Name, Surname, etc and
you want to show the full name of a customer in any of the ListControls, you have
several options:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
When you get the data from the database, return another column with the name and surname. 
&lt;li&gt;
Create a property (f.e. FullName) that returns what you want to show. 
&lt;li&gt;
Use a DataSet and add a computed column. 
&lt;li&gt;
Manually add ListItems with the appropriate values performing the data bind manually. 
&lt;li&gt;
Create a simple class that will be bound (instead of the original one) just to fix
the problem.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
The truth is that I don’t like any of those options, all of them are hacks. 
&lt;/p&gt;
&lt;p&gt;
For nested properties you have the similar problems. You can bind to Id or Name, but
you can’t bind to Address.City or Address.Zip.
&lt;/p&gt;
&lt;p&gt;
Today I faced this problem again and I decided to investigate a more innovative solution.
The problem itself is in the controls that inherit from ListControl that are very
strict in the binding options. So I took a look of how the controls perform the binding
to see if I could do anything to overcome those limitations. At first sight I thought
I was loosing my time but after a deeper study I found that it was amazingly easy
to fix those problems in a very sleek way.
&lt;/p&gt;
&lt;p&gt;
The data binding of the controls is performed in the PerformDataBinding method. The
code at ListControl.PerformDataBinding uses DataBinder.GetPropertyValue to retrieve
the value to show in the control if you set the DataTextField property. However, DataBinder.GetPropertyValue
doesn’t handle nested properties. DataBinder.Eval is a better choice because it does
handle nested properties. So using it we solve one problem. The other problem can
be solved easily as well. As we have two properties that control how the Text of each
ListItem will be extracted and shown from the data source, with a bit more of effort
we can handle the new functionality. I have come up with a very intuitive solution:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
DataTextField allows one or more properties (that can be nested if needed) separated
by commas. 
&lt;li&gt;
DataTextFormatString can be used to control the formatting of the items, using {0},
{1}, {2}, {3}… as the value of the properties specified with DataTextField.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
The code that performs the data binding is:
&lt;/p&gt;
&lt;div class=csharp style="BORDER-RIGHT: #d0d0d0 1px solid; BORDER-TOP: #d0d0d0 1px solid; BORDER-LEFT: #d0d0d0 1px solid; COLOR: #006; BORDER-BOTTOM: #d0d0d0 1px solid; FONT-FAMILY: monospace; BACKGROUND-COLOR: #f0f0f0"&gt;&lt;span style="COLOR: #008080; FONT-STYLE: italic"&gt;///
&amp;lt;summary&amp;gt;Binds the data to the control.&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #008080; FONT-STYLE: italic"&gt;/// &amp;lt;param name="ctrl"&amp;gt;control
to bind.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #008080; FONT-STYLE: italic"&gt;/// &amp;lt;param name="dataSource"&amp;gt;data
to bind to the control.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #0600ff"&gt;public&lt;/span&gt; &lt;span style="COLOR: #0600ff"&gt;static&lt;/span&gt; &lt;span style="COLOR: #0600ff"&gt;void&lt;/span&gt; PerformDataBinding&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;ListControl
ctrl, IEnumerable dataSource&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #008080; FONT-STYLE: italic"&gt;// resets the selected
item&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; ctrl.&lt;span style="COLOR: #0000ff"&gt;SelectedIndex&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;-&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;1&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; ctrl.&lt;span style="COLOR: #0000ff"&gt;SelectedValue&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; null&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;if&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;dataSource &lt;span style="COLOR: #008000"&gt;!=&lt;/span&gt; &lt;span style="COLOR: #0600ff"&gt;null&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #ff0000"&gt;bool&lt;/span&gt; fieldInfoSet &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; false&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #ff0000"&gt;bool&lt;/span&gt; dataTextFormatStringSet &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; false&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #008080; FONT-STYLE: italic"&gt;// checks
if we have to clear the existing items&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;if&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;!&lt;/span&gt;ctrl.&lt;span style="COLOR: #0000ff"&gt;AppendDataBoundItems&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ctrl.&lt;span style="COLOR: #0000ff"&gt;Items&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;Clear&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #008080; FONT-STYLE: italic"&gt;// if
the data source is a collection, sets the capacity&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ICollection soureceCollection &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; dataSource &lt;span style="COLOR: #0600ff"&gt;as&lt;/span&gt; ICollection&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;if&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;soureceCollection &lt;span style="COLOR: #008000"&gt;!=&lt;/span&gt; &lt;span style="COLOR: #0600ff"&gt;null&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ctrl.&lt;span style="COLOR: #0000ff"&gt;Items&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;Capacity&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; soureceCollection.&lt;span style="COLOR: #0000ff"&gt;Count&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;+&lt;/span&gt; ctrl.&lt;span style="COLOR: #0000ff"&gt;Items&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;Count&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #008080; FONT-STYLE: italic"&gt;// save
if the data text field of data value field has been set&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;if&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;ctrl.&lt;span style="COLOR: #0000ff"&gt;DataTextField&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;Length&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;!=&lt;/span&gt; &lt;span style="COLOR: #ff0000"&gt;0&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;||&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;ctrl.&lt;span style="COLOR: #0000ff"&gt;DataValueField&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;Length&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;!=&lt;/span&gt; &lt;span style="COLOR: #ff0000"&gt;0&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; fieldInfoSet &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; true&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #008080; FONT-STYLE: italic"&gt;// save
if the data text format string has been set&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;if&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;ctrl.&lt;span style="COLOR: #0000ff"&gt;DataTextFormatString&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;Length&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;!=&lt;/span&gt; &lt;span style="COLOR: #ff0000"&gt;0&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; dataTextFormatStringSet &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; true&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #008080; FONT-STYLE: italic"&gt;// iterates
through the data source creating the ListItems&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;foreach&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;object&lt;/span&gt; obj &lt;span style="COLOR: #0600ff"&gt;in&lt;/span&gt; dataSource&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ListItem item &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; &lt;a style="COLOR: #000060" href="http://www.google.com/search?q=new+msdn.microsoft.com"&gt;&lt;span style="COLOR: #008000"&gt;new&lt;/span&gt;&lt;/a&gt; ListItem&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;if&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;fieldInfoSet&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;if&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;ctrl.&lt;span style="COLOR: #0000ff"&gt;DataTextField&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;Length&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;&amp;gt;&lt;/span&gt; &lt;span style="COLOR: #ff0000"&gt;0&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;if&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;ctrl.&lt;span style="COLOR: #0000ff"&gt;DataTextField&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;IndexOf&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;span style="COLOR: #666666"&gt;','&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;==&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;-&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;1&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;
item.&lt;span style="COLOR: #0000ff"&gt;Text&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; DataBinder.&lt;span style="COLOR: #0000ff"&gt;Eval&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;obj,
ctrl.&lt;span style="COLOR: #0000ff"&gt;DataTextField&lt;/span&gt;, ctrl.&lt;span style="COLOR: #0000ff"&gt;DataTextFormatString&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt; &lt;span style="COLOR: #0600ff"&gt;else&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #008080; FONT-STYLE: italic"&gt;//
if the DataTextField property has a list of fields, get them to create the text of
the item&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #ff0000"&gt;string&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;[&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;]&lt;/span&gt; fields &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; ctrl.&lt;span style="COLOR: #0000ff"&gt;DataTextField&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;Split&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;a style="COLOR: #000060" href="http://www.google.com/search?q=new+msdn.microsoft.com"&gt;&lt;span style="COLOR: #008000"&gt;new&lt;/span&gt;&lt;/a&gt; &lt;span style="COLOR: #ff0000"&gt;string&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;[&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;]&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt; &lt;span style="COLOR: #666666"&gt;","&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;,
StringSplitOptions.&lt;span style="COLOR: #0000ff"&gt;RemoveEmptyEntries&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #ff0000"&gt;object&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;[&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;]&lt;/span&gt; values &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; &lt;a style="COLOR: #000060" href="http://www.google.com/search?q=new+msdn.microsoft.com"&gt;&lt;span style="COLOR: #008000"&gt;new&lt;/span&gt;&lt;/a&gt; &lt;span style="COLOR: #ff0000"&gt;object&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;[&lt;/span&gt;fields.&lt;span style="COLOR: #0000ff"&gt;Length&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;]&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;for&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;int&lt;/span&gt; i &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; &lt;span style="COLOR: #ff0000"&gt;0&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt; i &lt;span style="COLOR: #008000"&gt;&amp;lt;&lt;/span&gt; fields.&lt;span style="COLOR: #0000ff"&gt;Length&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt; i&lt;span style="COLOR: #008000"&gt;++&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #ff0000"&gt;string&lt;/span&gt; field &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; fields&lt;span style="COLOR: #000000"&gt;[&lt;/span&gt;i&lt;span style="COLOR: #000000"&gt;]&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;
&amp;nbsp; &amp;nbsp; values&lt;span style="COLOR: #000000"&gt;[&lt;/span&gt;i&lt;span style="COLOR: #000000"&gt;]&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; DataBinder.&lt;span style="COLOR: #0000ff"&gt;Eval&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;obj,
field&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;
item.&lt;span style="COLOR: #0000ff"&gt;Text&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; &lt;span style="COLOR: #ff0000"&gt;String&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;Format&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;ctrl.&lt;span style="COLOR: #0000ff"&gt;DataTextFormatString&lt;/span&gt;,
values&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;if&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;ctrl.&lt;span style="COLOR: #0000ff"&gt;DataValueField&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;Length&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;&amp;gt;&lt;/span&gt; &lt;span style="COLOR: #ff0000"&gt;0&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; item.&lt;span style="COLOR: #0000ff"&gt;Value&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; DataBinder.&lt;span style="COLOR: #0000ff"&gt;Eval&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;obj,
ctrl.&lt;span style="COLOR: #0000ff"&gt;DataValueField&lt;/span&gt;, &lt;span style="COLOR: #0600ff"&gt;null&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt; &lt;span style="COLOR: #0600ff"&gt;else&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;if&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;dataTextFormatStringSet&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; item.&lt;span style="COLOR: #0000ff"&gt;Text&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; &lt;span style="COLOR: #ff0000"&gt;string&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;Format&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;CultureInfo.&lt;span style="COLOR: #0000ff"&gt;CurrentCulture&lt;/span&gt;,
ctrl.&lt;span style="COLOR: #0000ff"&gt;DataTextFormatString&lt;/span&gt;, &lt;a style="COLOR: #000060" href="http://www.google.com/search?q=new+msdn.microsoft.com"&gt;&lt;span style="COLOR: #008000"&gt;new&lt;/span&gt;&lt;/a&gt; &lt;span style="COLOR: #ff0000"&gt;object&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;[&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;]&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt; obj &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt; &lt;span style="COLOR: #0600ff"&gt;else&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; item.&lt;span style="COLOR: #0000ff"&gt;Text&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; obj.&lt;span style="COLOR: #0000ff"&gt;ToString&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; item.&lt;span style="COLOR: #0000ff"&gt;Value&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; obj.&lt;span style="COLOR: #0000ff"&gt;ToString&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ctrl.&lt;span style="COLOR: #0000ff"&gt;Items&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;Add&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;item&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
As we need to call this data binding code instead of the one from ListControl I needed
to subclass all controls that inherit from ListControl in order to fix them. So now
I have BulletedListEx, CheckBoxListEx, DropDownListEx, ListBoxEx and RadioButtonListEx.
&lt;/p&gt;
&lt;p&gt;
I have created a simple example showing how to use them. Imagine that an Item can
be supplied by a set of suppliers, and each supplier sells the item with a different
price. The following image shows the properties of the 3 entities of the sample:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/listcontrolex_sample.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
I have created a web page with a DropDownList with some items, and when you select
an item in the DropDownList you will see a ListBox with the all suppliers of that
item with the associated price for the item. Notice how I show the Id and the Name
in the DropDownList and how I show the price, supplier Id and supplier name in the
ListBox:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/listcontrolex_sample2.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
The ASPX of the page follows:
&lt;/p&gt;
&lt;div class=xml style="BORDER-RIGHT: #d0d0d0 1px solid; BORDER-TOP: #d0d0d0 1px solid; BORDER-LEFT: #d0d0d0 1px solid; COLOR: #006; BORDER-BOTTOM: #d0d0d0 1px solid; FONT-FAMILY: monospace; BACKGROUND-COLOR: #f0f0f0"&gt;&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;body&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;form&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"form1"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;runat&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"server"&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Choose an item to see the suppliers:&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Items:&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;manu:DropDownListEx&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;ID&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"DropDownListEx1"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;runat&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"server"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;AutoPostBack&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"True"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;Width&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"300px"&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000066"&gt;DataTextField&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"Id,
Name"&lt;/span&gt; &lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000066"&gt;DataTextFormatString&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"[{0}]
- {1}"&lt;/span&gt; &lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000066"&gt;DataValueField&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"Id"&lt;/span&gt; &lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000066"&gt;OnSelectedIndexChanged&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"DropDownListEx1_SelectedIndexChanged"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;AppendDataBoundItems&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"True"&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;asp:ListItem&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;Selected&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"True"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;Value&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"0"&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Select
an Item&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/asp:ListItem&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/manu:DropDownListEx&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Price and suppliers:&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;manu:ListBoxEx&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;ID&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"ListBoxEx1"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;runat&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"server"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;Width&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"300px"&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000066"&gt;DataTextField&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"Price,
Supplier.Id, Supplier.Name"&lt;/span&gt; &lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000066"&gt;DataTextFormatString&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"{0}
- [{1}] {2}"&lt;/span&gt; &lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000066"&gt;DataValueField&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"Supplier.Id"&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/manu:ListBoxEx&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/form&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/body&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
As you can see, the solution is really clean and elegant, and backward compatible
with the current controls that inherit from ListControl.
&lt;/p&gt;
&lt;p&gt;
That’s all for now,&lt;br&gt;
Merry christmas!
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.manuelabadia.com/blog/content/binary/ListControlsEx_bin.zip"&gt;ListControlsEx_bin.zip
(6.53 KB)&lt;/a&gt;
&lt;/p&gt;
&lt;a href="http://www.manuelabadia.com/blog/content/binary/ListControlsEx_sample.zip"&gt;ListControlsEx_sample.zip
(33.75 KB)&lt;/a&gt;&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=0606d95f-56ae-4dd7-8458-69cd550fa356" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,0606d95f-56ae-4dd7-8458-69cd550fa356.aspx</comments>
      <category>ASP.NET</category>
      <category>Microsoft .NET Framework</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=7924eaf8-b406-43af-9444-b816f6dfa246</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,7924eaf8-b406-43af-9444-b816f6dfa246.aspx</pingback:target>
      <dc:creator>Manu</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,7924eaf8-b406-43af-9444-b816f6dfa246.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=7924eaf8-b406-43af-9444-b816f6dfa246</wfw:commentRss>
      <slash:comments>11</slash:comments>
      <title>Search Engine Optimization - Moving View State to the bottom of the page</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,7924eaf8-b406-43af-9444-b816f6dfa246.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,7924eaf8-b406-43af-9444-b816f6dfa246.aspx</link>
      <pubDate>Thu, 04 Dec 2008 19:26:16 GMT</pubDate>
      <description>&lt;p&gt;
One of the greatest problems when trying to optimize an ASP.NET page to be more search
engine friendly is the view state hidden field. Most search engines give more score
to the content of the firsts thousands of bytes of the document so if your first 2
KB are view state junk your pages are penalized. So the goal here is to move the view
state data as down as possible. 
&lt;/p&gt;
&lt;p&gt;
I have seen some approaches to solve this problem rewriting the final HTML code of
the response. While this approach works I think that it wastes some precious processor
cycles that can be used to do other things. So I needed a way to do the same thing
without wasting that CPU time. After some large reflector sessions I found a way to
do it. My method uses the ASP.NET Control Adapter Architecture. 
&lt;/p&gt;
&lt;p&gt;
A control adapter is a class that can be used to control the HTML generated by the
control it adapts. Since the Page class is the responsible of rendering the view state
hidden field (Page.BeginFormRender calls Page.RenderViewStateFields), an adapter for
the Page is needed. However, the view state hidden field plays a key role in the ASP.NET
infrastructure (for example, the Page.IsPostBack property checks if the view state
hidden field has been posted) and it is difficult to modify the associated HTML. 
&lt;/p&gt;
&lt;p&gt;
A PageAdapter has a method called GetStatePersister() that returns an object that
inherits from PageStatePersister. The PageStatePersister is called when it is time
to load and save the view state. There are 2 classes that inherit from PageStatePersister:
HiddenFieldPageStatePersister and SessionPageStatePersister. The first one is the
default, which stores the view state in the hidden field called __VIEWSTATE. The second
one stores the view state in the session. So, we can easily create a custom PageStatePersister
to control the view state load and save process. The big problem is how to create
the hidden view state field before the closing form tag while being a fully transparent
solution. After some tries I came up with a solution that I was happy with. 
&lt;/p&gt;
&lt;p&gt;
I realized that it was impossible to completely remove the view state hidden field
from the top of the page, because it plays a key role in the ASP.NET infrastructure.
However, with any custom page state persister the ASP.NET infrastructure renders at
least an empty view state hidden field of only 70 bytes: 
&lt;/p&gt;
&lt;div class=html4strict style="BORDER-RIGHT: #d0d0d0 1px solid; BORDER-TOP: #d0d0d0 1px solid; BORDER-LEFT: #d0d0d0 1px solid; COLOR: #006; BORDER-BOTTOM: #d0d0d0 1px solid; FONT-FAMILY: monospace; BACKGROUND-COLOR: #f0f0f0"&gt;&lt;span style="COLOR: #009900"&gt;&amp;lt;&lt;a style="COLOR: #000060" href="http://december.com/html/4/element/input.html"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;input&lt;/span&gt;&lt;/a&gt; &lt;span style="COLOR: #000066"&gt;type&lt;/span&gt;&lt;span style="COLOR: #66cc66"&gt;=&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;"hidden"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;name&lt;/span&gt;&lt;span style="COLOR: #66cc66"&gt;=&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;"__VIEWSTATE"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;&lt;span style="COLOR: #66cc66"&gt;=&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;"__VIEWSTATE"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;value&lt;/span&gt;&lt;span style="COLOR: #66cc66"&gt;=&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;""&lt;/span&gt; &lt;span style="COLOR: #66cc66"&gt;/&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
My page adapter adds a hidden field to the bottom of the form called __SEOVIEWSTATE
with the actual view state data, and the only limitation that it has it is that you
can not use &lt;% %&gt;expressions directly inside the asp.net form. However, this restriction
can be easily avoided putting the &lt;% %&gt;expression in a PlaceHolder control or inside
another control. For an in-depth explanation of this limitation take a look &lt;a href="http://www.west-wind.com/WebLog/posts/6148.aspx"&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Let’s see an example of the adapter in action. The following ASP.NET page: 
&lt;/p&gt;
&lt;div class=xml style="BORDER-RIGHT: #d0d0d0 1px solid; BORDER-TOP: #d0d0d0 1px solid; BORDER-LEFT: #d0d0d0 1px solid; COLOR: #006; BORDER-BOTTOM: #d0d0d0 1px solid; FONT-FAMILY: monospace; BACKGROUND-COLOR: #f0f0f0"&gt;&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;&lt;/span&gt;%@
Page &lt;span style="COLOR: #000066"&gt;Language&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"C#"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;AutoEventWireup&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"true"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;CodeBehind&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"Default.aspx.cs"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;Inherits&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"SEOViewStateAdapterTest._Default"&lt;/span&gt; %&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #00bbdd"&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;html&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;xmlns&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"http://www.w3.org/1999/xhtml"&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;head&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;runat&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"server"&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;title&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/title&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/head&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;body&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;form&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"form1"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;runat&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"server"&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Enter a message: &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;asp:TextBox&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;ID&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"txtMessage"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;runat&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"server"&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/asp:TextBox&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;asp:Button&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;ID&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"bSaveMessage"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;runat&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"server"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;Text&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"Save
Message"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;onclick&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"bSaveMessage_Click"&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;asp:Label&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;ID&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"lMessage"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;runat&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"server"&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/asp:Label&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;p&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Page
generated at &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;asp:PlaceHolder&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;ID&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"PlaceHolder1"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;runat&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"server"&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;&lt;/span&gt;%=
DateTime.Now.ToString&lt;span style="COLOR: #66cc66"&gt;(&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;"hh:mm
dd/MM/yyy"&lt;/span&gt;&lt;span style="COLOR: #66cc66"&gt;)&lt;/span&gt; %&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/asp:PlaceHolder&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/p&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/form&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/body&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/html&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;
&lt;/div&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
With the associated code: 
&lt;/p&gt;
&lt;div class=csharp style="BORDER-RIGHT: #d0d0d0 1px solid; BORDER-TOP: #d0d0d0 1px solid; BORDER-LEFT: #d0d0d0 1px solid; COLOR: #006; BORDER-BOTTOM: #d0d0d0 1px solid; FONT-FAMILY: monospace; BACKGROUND-COLOR: #f0f0f0"&gt;&lt;span style="COLOR: #0600ff"&gt;using&lt;/span&gt; &lt;span style="COLOR: #008080"&gt;System&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #0600ff"&gt;using&lt;/span&gt; &lt;span style="COLOR: #008080"&gt;System.Collections.Generic&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #0600ff"&gt;using&lt;/span&gt; &lt;span style="COLOR: #008080"&gt;System.Web&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #0600ff"&gt;using&lt;/span&gt; &lt;span style="COLOR: #008080"&gt;System.Web.UI&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #0600ff"&gt;using&lt;/span&gt; &lt;span style="COLOR: #008080"&gt;System.Web.UI.WebControls&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&lt;span style="COLOR: #0600ff"&gt;namespace&lt;/span&gt; SEOViewStateAdapterTest&lt;br&gt;
&lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;public&lt;/span&gt; &lt;span style="COLOR: #0600ff"&gt;partial&lt;/span&gt; &lt;span style="COLOR: #ff0000"&gt;class&lt;/span&gt; _Default &lt;span style="COLOR: #008000"&gt;:&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;System.&lt;span style="COLOR: #0000ff"&gt;Web&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;UI&lt;/span&gt;&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;Page&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;protected&lt;/span&gt; &lt;span style="COLOR: #0600ff"&gt;void&lt;/span&gt; Page_Load&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;object&lt;/span&gt; sender,
EventArgs e&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;if&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;!&lt;/span&gt;Page.&lt;span style="COLOR: #0000ff"&gt;IsPostBack&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ViewState&lt;span style="COLOR: #000000"&gt;[&lt;/span&gt;&lt;span style="COLOR: #666666"&gt;"previousMessage"&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;]&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; txtMessage.&lt;span style="COLOR: #0000ff"&gt;Text&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #0600ff"&gt;protected&lt;/span&gt; &lt;span style="COLOR: #0600ff"&gt;void&lt;/span&gt; bSaveMessage_Click&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;object&lt;/span&gt; sender,
EventArgs e&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;{&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; lMessage.&lt;span style="COLOR: #0000ff"&gt;Text&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; &lt;span style="COLOR: #ff0000"&gt;String&lt;/span&gt;.&lt;span style="COLOR: #0000ff"&gt;Format&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;span style="COLOR: #666666"&gt;"The
current message is '{0}'. The previous message was '{1}'"&lt;/span&gt;, txtMessage.&lt;span style="COLOR: #0000ff"&gt;Text&lt;/span&gt;, &lt;span style="COLOR: #000000"&gt;(&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;string&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;ViewState&lt;span style="COLOR: #000000"&gt;[&lt;/span&gt;&lt;span style="COLOR: #666666"&gt;"previousMessage"&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;]&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;)&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ViewState&lt;span style="COLOR: #000000"&gt;[&lt;/span&gt;&lt;span style="COLOR: #666666"&gt;"previousMessage"&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;]&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;=&lt;/span&gt; txtMessage.&lt;span style="COLOR: #0000ff"&gt;Text&lt;/span&gt;&lt;span style="COLOR: #008000"&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #000000"&gt;}&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;
&lt;/div&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
after a couple of postbacks, without using the adapter, the HTML looks like this: 
&lt;/p&gt;
&lt;div class=xml style="BORDER-RIGHT: #d0d0d0 1px solid; BORDER-TOP: #d0d0d0 1px solid; BORDER-LEFT: #d0d0d0 1px solid; COLOR: #006; BORDER-BOTTOM: #d0d0d0 1px solid; FONT-FAMILY: monospace; BACKGROUND-COLOR: #f0f0f0"&gt;&lt;span style="COLOR: #00bbdd"&gt;&amp;lt;!DOCTYPE
html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;html&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;xmlns&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"http://www.w3.org/1999/xhtml"&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;head&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;title&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/title&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/head&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;body&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;form&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;name&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"form1"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;method&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"post"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;action&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"Default.aspx"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"form1"&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;input&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;type&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"hidden"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;name&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"__VIEWSTATE"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"__VIEWSTATE"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;value&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"/wEPDwUJc01l[...]VwP+cfdSWI6Q=="&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;input&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;type&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"hidden"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;name&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"__EVENTVALIDATION"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"__EVENTVALIDATION"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;value&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"/wEWAwKb4uenCgK/1s7/DwKf8MMPfiUvZtKPSXk//XdxkLooz8QDI0Y="&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Enter a message: &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;input&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;name&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"txtMessage"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;type&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"text"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;value&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"Message
2"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"txtMessage"&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;input&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;type&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"submit"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;name&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"bSaveMessage"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;value&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"Save
Message"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"bSaveMessage"&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;span&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"lMessage"&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;The
current message is 'Message 2'. The previous message was 'Message 1'&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/span&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;p&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Page
generated at 08:13 04/12/2008&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/p&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/form&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/body&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/html&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
and after a couple of postbacks, using the adapter, the HTML looks like this: 
&lt;/p&gt;
&lt;div class=xml style="BORDER-RIGHT: #d0d0d0 1px solid; BORDER-TOP: #d0d0d0 1px solid; BORDER-LEFT: #d0d0d0 1px solid; COLOR: #006; BORDER-BOTTOM: #d0d0d0 1px solid; FONT-FAMILY: monospace; BACKGROUND-COLOR: #f0f0f0"&gt;&lt;span style="COLOR: #00bbdd"&gt;&amp;lt;!DOCTYPE
html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;html&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;xmlns&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"http://www.w3.org/1999/xhtml"&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;head&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;title&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/title&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/head&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;body&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;form&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;name&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"form1"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;method&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"post"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;action&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"Default.aspx"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"form1"&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;input&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;type&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"hidden"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;name&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"__VIEWSTATE"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"__VIEWSTATE"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;value&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;""&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;input&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;type&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"hidden"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;name&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"__EVENTVALIDATION"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"__EVENTVALIDATION"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;value&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"/wEWAwL+raDpAgK/1s7/DwKf8MMPyF7nqN1AbwNwFBq8OAjEAQorsyo="&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Enter a message: &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;input&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;name&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"txtMessage"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;type&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"text"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;value&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"Message
2"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"txtMessage"&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;input&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;type&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"submit"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;name&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"bSaveMessage"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;value&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"Save
Message"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"bSaveMessage"&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;span&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"lMessage"&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;The
current message is 'Message 2'. The previous message was 'Message 1'&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/span&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;br&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;p&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Page
generated at 08:11 04/12/2008&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/p&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/div&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;input&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;type&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"hidden"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;name&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"__SEOVIEWSTATE"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;id&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"__SEOVIEWSTATE"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;value&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"/wEPc01lc3[...]CdNY6AtgigHvU="&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/form&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/body&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/html&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
In order to use the adapter, you have to add a reference to the assembly and add a
file called SEOViewStateAdapter.browser (the name of the file does not matter. The
extension needs to be the same. Or also you could merge the contents to another file
if you already have one) to the App_Browsers folder. The content of the file should
be: 
&lt;/p&gt;
&lt;div class=xml style="BORDER-RIGHT: #d0d0d0 1px solid; BORDER-TOP: #d0d0d0 1px solid; BORDER-LEFT: #d0d0d0 1px solid; COLOR: #006; BORDER-BOTTOM: #d0d0d0 1px solid; FONT-FAMILY: monospace; BACKGROUND-COLOR: #f0f0f0"&gt;&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;browsers&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #808080; FONT-STYLE: italic"&gt;&amp;lt;!-- use the adapters
for all browsers --&amp;gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;browser&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;refID&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"Default"&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;controlAdapters&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #808080; FONT-STYLE: italic"&gt;&amp;lt;!--
ths adapter is used to save the view and control state at the bottom of the form so
the page is more friendly to search engines --&amp;gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;adapter&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;controlType&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"System.Web.UI.Page"&lt;/span&gt; &lt;span style="COLOR: #000066"&gt;adapterType&lt;/span&gt;=&lt;span style="COLOR: #ff0000"&gt;"Manu.Web.Adapters.SEOFriendlyViewStatePageAdapter,
SEOViewStateAdapter"&lt;/span&gt; &lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/controlAdapters&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp; &lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/browser&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="COLOR: #009900"&gt;&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;lt;/browsers&lt;span style="FONT-WEIGHT: bold; COLOR: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;
&lt;/div&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
That’s all. Enjoy!
&lt;/p&gt;
&lt;a href="http://www.manuelabadia.com/blog/content/binary/SEOViewState.zip"&gt;SEOViewState.zip
(29.67 KB)&lt;/a&gt;&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=7924eaf8-b406-43af-9444-b816f6dfa246" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,7924eaf8-b406-43af-9444-b816f6dfa246.aspx</comments>
      <category>ASP.NET</category>
      <category>Microsoft .NET Framework</category>
      <category>SEO</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=04e66909-e2ab-4869-8a1f-ae2348bf7e47</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,04e66909-e2ab-4869-8a1f-ae2348bf7e47.aspx</pingback:target>
      <dc:creator>Manu</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,04e66909-e2ab-4869-8a1f-ae2348bf7e47.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=04e66909-e2ab-4869-8a1f-ae2348bf7e47</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I have been using <a href="http://www.thejoyofcode.com/Validator_Module.aspx">Josh
Twist’s XHTML validation module</a> for a while and I have added a couple of small
enhancements I have found useful:
</p>
        <ul>
          <li>
It works without internet access as I included the required DTDs as embedded resources.
I usually have internet access when I’m using it, but it is a big problem if I don’t. 
</li>
          <li>
It doesn’t validate ASP.NET trace output if it is present in the page. This is checked
using the trace configuration section. I have not found a way to know if trace output
is enabled in the current request. 
</li>
          <li>
I have added an attribute called showErrorsOnly to the validatorModule element to
avoid calling the Renderer.Render method if there isn’t any error. That way, if the
page validates successfully no message is shown. 
</li>
        </ul>
        <p>
 
</p>
        <p>
          <a href="http://www.manuelabadia.com/blog/content/binary/validator_bin.zip">Download
validator_binaries (42,78 KB)</a>
        </p>
        <p>
          <a href="http://www.manuelabadia.com/blog/content/binary/validator_src.zip">Downlaod
Validator_source code (44,04 KB)</a>
        </p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=04e66909-e2ab-4869-8a1f-ae2348bf7e47" />
      </body>
      <title>XHTML Validation Module Enhancement</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,04e66909-e2ab-4869-8a1f-ae2348bf7e47.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,04e66909-e2ab-4869-8a1f-ae2348bf7e47.aspx</link>
      <pubDate>Wed, 13 Aug 2008 23:12:04 GMT</pubDate>
      <description>&lt;p&gt;
I have been using&amp;nbsp;&lt;a href="http://www.thejoyofcode.com/Validator_Module.aspx"&gt;Josh
Twist’s XHTML validation module&lt;/a&gt; for a while and I have added a couple of small
enhancements I have found useful:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
It works without internet access as I included the required DTDs as embedded resources.
I usually have internet access when I’m using it, but it is a big problem if I don’t. 
&lt;li&gt;
It doesn’t validate ASP.NET trace output if it is present in the page. This is checked
using the trace configuration section. I have not found a way to know if trace output
is enabled in the current request. 
&lt;li&gt;
I have added an attribute called showErrorsOnly to the validatorModule element to
avoid calling the Renderer.Render method if there isn’t any error. That way, if the
page validates successfully no message is shown. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.manuelabadia.com/blog/content/binary/validator_bin.zip"&gt;Download
validator_binaries (42,78 KB)&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.manuelabadia.com/blog/content/binary/validator_src.zip"&gt;Downlaod
Validator_source code (44,04 KB)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=04e66909-e2ab-4869-8a1f-ae2348bf7e47" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,04e66909-e2ab-4869-8a1f-ae2348bf7e47.aspx</comments>
      <category>ASP.NET</category>
      <category>XHTML</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=a93878c1-bd98-40d1-81cb-8bbfb6f0bb63</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,a93878c1-bd98-40d1-81cb-8bbfb6f0bb63.aspx</pingback:target>
      <dc:creator>Manu</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,a93878c1-bd98-40d1-81cb-8bbfb6f0bb63.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=a93878c1-bd98-40d1-81cb-8bbfb6f0bb63</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
The changes from v1.2 to the current one (v2.0) are:
</p>
        <ul>
          <li>
Now using NHibernate 2.0.0 CR1.</li>
          <li>
Fixed a bug that caused the provider to look for the configuration settings only in
the nhibernate config section. If you configured NHibernate using the hibernate-configuration
section, it didn't work.</li>
          <li>
Fixed a bug that prevented hashed passwords to work without supplying a password answer.</li>
          <li>
Some code refactoring/clean up.</li>
          <li>
Removed all FXCop warnings.</li>
          <li>
Changed the mapping generation for the NHCustomMembershipProvider. In NHiberante 2.0.0
CR1, it is not possible to create mappings programatically as before, so now a xml
document with the mapping is created.</li>
          <li>
Fixed a bug in ChangePassword and ResetPassword methods that made the stored password
answer useless if the provider was using hashed format with password salt.</li>
        </ul>
        <p>
From some questions/emails I've got, it seems that some people aren't using
the provider the way it was designed. There is no need to modify the code in the provider
to support custom fields for your Users or Roles. I have created a sample that uses
all the fields in the membership provider and adds some custom fields to
show how the provider should be used. The sample also uses the CreateUserExWizard
control in order to create an user.
</p>
        <p>
As always, feedback is welcome. It has been tested only in SQL Server 2005. Let me
know if you try it in other databases. 
</p>
        <p>
The binaries and source code can be downloaded <a href="http://www.manuelabadia.com/blog/PermaLink,guid,3b6ccb3f-2f2a-4dcb-a414-605371a00618.aspx">here</a></p>
        <p>
 
</p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=a93878c1-bd98-40d1-81cb-8bbfb6f0bb63" />
      </body>
      <title>Update to my NHibernate Custom Membership and Role Providers</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,a93878c1-bd98-40d1-81cb-8bbfb6f0bb63.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,a93878c1-bd98-40d1-81cb-8bbfb6f0bb63.aspx</link>
      <pubDate>Fri, 01 Aug 2008 10:10:15 GMT</pubDate>
      <description>&lt;p&gt;
The changes from v1.2 to the current one (v2.0) are:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Now using NHibernate 2.0.0 CR1.&lt;/li&gt;
&lt;li&gt;
Fixed a bug that caused the provider to look for the configuration settings only in
the nhibernate config section. If you configured NHibernate using the hibernate-configuration
section, it didn't work.&lt;/li&gt;
&lt;li&gt;
Fixed a bug that prevented hashed passwords to work without supplying a password answer.&lt;/li&gt;
&lt;li&gt;
Some code refactoring/clean up.&lt;/li&gt;
&lt;li&gt;
Removed all FXCop warnings.&lt;/li&gt;
&lt;li&gt;
Changed the mapping generation for the NHCustomMembershipProvider. In NHiberante 2.0.0
CR1, it is not possible to create mappings programatically as before, so now a xml
document with the mapping is created.&lt;/li&gt;
&lt;li&gt;
Fixed a bug in ChangePassword and ResetPassword methods that made the stored password
answer&amp;nbsp;useless if the provider was using hashed format with password salt.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
From some&amp;nbsp;questions/emails I've got,&amp;nbsp;it seems that some people aren't using
the provider the way it was designed. There is no need to modify the code in the provider
to support custom fields for your Users or Roles. I have created a sample that uses
all the fields in the&amp;nbsp;membership&amp;nbsp;provider and adds some custom fields to
show how the provider should be used. The sample also uses the CreateUserExWizard
control in order to create an user.
&lt;/p&gt;
&lt;p&gt;
As always, feedback is welcome. It has been tested only in SQL Server 2005. Let me
know if you try it in other databases. 
&lt;/p&gt;
&lt;p&gt;
The binaries and source code can be downloaded &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,3b6ccb3f-2f2a-4dcb-a414-605371a00618.aspx"&gt;here&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=a93878c1-bd98-40d1-81cb-8bbfb6f0bb63" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,a93878c1-bd98-40d1-81cb-8bbfb6f0bb63.aspx</comments>
      <category>ASP.NET</category>
      <category>NHibernate</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=51ac1b35-5246-4e8c-9ee6-41334480a54e</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx</pingback:target>
      <dc:creator>Manu</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=51ac1b35-5246-4e8c-9ee6-41334480a54e</wfw:commentRss>
      <slash:comments>32</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This post is first in English and then in Spanish<br />
Esta noticia está primero en inglés y luego en español
</p>
        <p>
 
</p>
        <p>
World Rally emulation is complete. I implemented priorities (that were trickier than
I thought), shadows/highlights and a few missing bits in the video hardware. Here
are some screenshots of the finished driver:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic1.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic5.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic3.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic2.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic4.png" border="0" />
        </p>
        <p>
 
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic7.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic6.png" border="0" />
        </p>
        <p>
The game is fully playable from beginning to end without any problem as far as I can
tell. I thought there was a bug in the video hardware emulation somewhere when I saw
this:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem1.png" border="0" />
        </p>
        <p>
So I plugged my PCB and compared it to the driver:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic1.jpg" border="0" />
        </p>
        <p>
The problem is also in the original arcade game. Because of the way an arcade monitor
works, the problem is nearly unnoticeable in the original game. I also checked if
the original PCB had the same “shadow effect” for the tiles:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem2.png" border="0" />
        </p>
        <p>
As you can see, the hardware works that way:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic2.jpg" border="0" />
          <br />
 <br />
Something curious about the protection... Javier told ElSemi that the protection of
this game took 8 months of work, so imagine how complicated it was… even the dallas
has some code that performs some pseudorandom dummy accesses to the shared RAM to
make black box attacks even more difficult.
</p>
        <p>
To clarify a question about the other protected games, having the World Rally dallas
code does not help to emulate the protection of them.  As MAME now has a DS5002FP
core and the other games are almost fully emulated, if we get the dallas code for
a game, it will be playable quickly.
</p>
        <p>
Finally, I want to thank to all the people that made this possible. It was cool to
be part of this. It has brought me some good memories and healed my wounds with Gaelco.
</p>
        <p>
          <strong>Update</strong>: <a href="http://www.gaelco.com">Gaelco</a> made public
the ROMs for World Rally. You can get them from <a href="http://www.gaelco.com">their
web page</a></p>
        <p>
For reference here are all the posts about World Rally emulation:
</p>
        <p>
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx">Part
1</a>
          <br />
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx">Part
2</a>
          <br />
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx">Part
3</a>
          <br />
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx">Part
4</a>
        </p>
        <p>
        </p>
        <p>
          <hr />
          <br />
La emulación del World Rally está completada. He implementado las prioridades (que
han sido más difíciles de lo que pensaba), los focos y sombras, y algún detalle que
faltaba del hardware gráfico. A continuación se muestran unas pantallas del driver: 
</p>
        <p>
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic1.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic5.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic3.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic2.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic4.png" border="0" />
        </p>
        <p>
 
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic7.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic6.png" border="0" />
        </p>
        <p>
        </p>
        <p>
Es completamente  jugable sin que haya podido observar ningún problema. Pensé
que había algún fallo en la emulación del hardware gráfico cuando vi esto:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem1.png" border="0" />
        </p>
        <p>
Así que enchufé mi placa y la comparé al driver:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic1.jpg" border="0" />
        </p>
        <p>
Como se observa, el problema también está presente en el juego original. Debido a
la forma en la que funciona un monitor de recreativa, el pequeño fallo gráfico es
prácticamente inapreciable en el juego original. También comprobé si el juego original
hacía el mismo “efecto de sombra” de los puentes:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem2.png" border="0" />
        </p>
        <p>
Como se puede apreciar, el hardware funciona de esa manera:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic2.jpg" border="0" />
        </p>
        <p>
Algo curioso sobre la protección… Javier le dijo a ElSemi que la desarrollar protección
del juego llevó 8 meses de trabajo. Inmaginad cómo de complicada es la protección…
Incluso el dallas tiene código para realizar accesos pseudoaleatorios a la memoria
compartido con el único motivo de hacer que los ataques de tipo caja negra sean incluso
más difíciles.
</p>
        <p>
Sobre la pregunta de si tener el código del dallas para el World Rally sirve para
emular la protección de los otros juegos, la respuesta es que no. Se necesita el código
de cada uno para hacerlo funcionar. Como ahora el MAME ya dispone de un emulador de
DS5002FP y los juegos de Gaelco protegidos están ya emulados completamente, una vez
que obtengamos el código del dallas para un juego, será jugable rápidamente.
</p>
        <p>
Por último, me gustaría darle las gracias a toda la gente que ha hecho esto posible.
Ha sido muy interesante poder formar parte de esto. Me ha traído muy gratos recuerdos
y ha cerrado viejas heridas con Gaelco.
</p>
        <p>
          <strong>Actualización</strong>: <a href="http://www.gaelco.com">Gaelco</a> ha
hecho públicas las ROMs del World Rally. Puedes obtenerlas desde <a href="http://www.gaelco.com">su
página web</a></p>
        <p>
A modo de referencia, aquí están todas las noticias sobre la emulación del World Rally:
</p>
        <p>
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx">Parte
1</a>
          <br />
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx">Parte
2</a>
          <br />
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx">Parte
3</a>
          <br />
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx">Parte
4</a>
        </p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=51ac1b35-5246-4e8c-9ee6-41334480a54e" />
      </body>
      <title>World Rally emulation completed</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx</link>
      <pubDate>Mon, 12 May 2008 09:13:01 GMT</pubDate>
      <description>&lt;p&gt;
This post is first in English and then in Spanish&lt;br&gt;
Esta noticia está primero en inglés y luego en español
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
World Rally emulation is complete. I implemented priorities (that were trickier than
I thought), shadows/highlights and a few missing bits in the video hardware. Here
are some screenshots of the finished driver:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic1.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic5.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic3.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic2.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic4.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic7.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic6.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
The game is fully playable from beginning to end without any problem as far as I can
tell. I thought there was a bug in the video hardware emulation somewhere when I saw
this:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem1.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
So I plugged my PCB and compared it to the driver:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic1.jpg" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
The problem is also in the original arcade game. Because of the way an arcade monitor
works, the problem is nearly unnoticeable in the original game. I also checked if
the original PCB had the same “shadow effect” for the tiles:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem2.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
As you can see, the hardware works that way:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic2.jpg" border=0&gt;
&lt;br&gt;
&amp;nbsp;&lt;br&gt;
Something curious about the protection... Javier told ElSemi that the protection of
this game took 8 months of work, so imagine how complicated it was… even the dallas
has some code that performs some pseudorandom dummy accesses to the shared RAM to
make black box attacks even more difficult.
&lt;/p&gt;
&lt;p&gt;
To clarify a question about the other protected games, having the World Rally dallas
code does not help to emulate the protection of them.&amp;nbsp; As MAME now has a DS5002FP
core and the other games are almost fully emulated, if we get the dallas code for
a game, it will be playable quickly.
&lt;/p&gt;
&lt;p&gt;
Finally, I want to thank to all the people that made this possible. It was cool to
be part of this. It has brought me some good memories and healed my wounds with Gaelco.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Update&lt;/strong&gt;: &lt;a href="http://www.gaelco.com"&gt;Gaelco&lt;/a&gt;&amp;nbsp;made public
the ROMs for World Rally. You can get them from &lt;a href="http://www.gaelco.com"&gt;their
web page&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
For reference here are all the posts about World Rally emulation:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx"&gt;Part
1&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx"&gt;Part
2&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx"&gt;Part
3&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx"&gt;Part
4&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;p&gt;
&lt;hr&gt;
&lt;br&gt;
La emulación del World Rally está completada. He implementado las prioridades (que
han sido más difíciles de lo que pensaba), los focos y sombras, y algún detalle que
faltaba del hardware gráfico. A continuación se muestran unas pantallas del driver: 
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic1.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic5.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic3.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic2.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic4.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic7.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic6.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Es completamente&amp;nbsp; jugable sin que haya podido observar ningún problema. Pensé
que había algún fallo en la emulación del hardware gráfico cuando vi esto:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem1.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Así que enchufé mi placa y la comparé al driver:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic1.jpg" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Como se observa, el problema también está presente en el juego original. Debido a
la forma en la que funciona un monitor de recreativa, el pequeño fallo gráfico es
prácticamente inapreciable en el juego original. También comprobé si el juego original
hacía el mismo “efecto de sombra” de los puentes:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem2.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Como se puede apreciar, el hardware funciona de esa manera:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic2.jpg" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Algo curioso sobre la protección… Javier le dijo a ElSemi que la desarrollar protección
del juego llevó 8 meses de trabajo. Inmaginad cómo de complicada es la protección…
Incluso el dallas tiene código para realizar accesos pseudoaleatorios a la memoria
compartido con el único motivo de hacer que los ataques de tipo caja negra sean incluso
más difíciles.
&lt;/p&gt;
&lt;p&gt;
Sobre la pregunta de si tener el código del dallas para el World Rally sirve para
emular la protección de los otros juegos, la respuesta es que no. Se necesita el código
de cada uno para hacerlo funcionar. Como ahora el MAME ya dispone de un emulador de
DS5002FP y los juegos de Gaelco protegidos están ya emulados completamente, una vez
que obtengamos el código del dallas para un juego, será jugable rápidamente.
&lt;/p&gt;
&lt;p&gt;
Por último, me gustaría darle las gracias a toda la gente que ha hecho esto posible.
Ha sido muy interesante poder formar parte de esto. Me ha traído muy gratos recuerdos
y ha cerrado viejas heridas con Gaelco.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Actualización&lt;/strong&gt;: &lt;a href="http://www.gaelco.com"&gt;Gaelco&lt;/a&gt;&amp;nbsp;ha
hecho públicas las ROMs del World Rally. Puedes obtenerlas desde &lt;a href="http://www.gaelco.com"&gt;su
página web&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
A modo de referencia, aquí están todas las noticias sobre la emulación del World Rally:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx"&gt;Parte
1&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx"&gt;Parte
2&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx"&gt;Parte
3&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx"&gt;Parte
4&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=51ac1b35-5246-4e8c-9ee6-41334480a54e" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx</comments>
      <category>Games</category>
      <category>MAME</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=c7e7ab2e-fea4-4642-a9b7-e43a063662f1</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx</pingback:target>
      <dc:creator>Manu</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c7e7ab2e-fea4-4642-a9b7-e43a063662f1</wfw:commentRss>
      <slash:comments>9</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This post is first in english and then in spanish.<br />
Esta noticia está primero en inglés y luego en castellano.
</p>
        <p>
Javier sent us (via ElSemi) detailed information about how the encryption process
worked. However, he told us that the sheets of paper that contained the encryption
info were a bit difficult to read in some places (remember that this protection was
designed 15 years ago) so probably there was some mistakes in the excel file he sent
us. ElSemi and I tried to add it with the information he gave us but we didn’t have
success. <a href="http://mamelife.blogspot.com/">Nicola Salmoria</a> did an excellent
work (as always) consolidating the information and obtaining the missing information.
He generated a working decryption function that not only works for World Rally, but
also for Squash and Thunder Hoop.
</p>
        <p>
Mike Coates also completed the interface to get the data from a World Rally PCB, so
he was able to supply the encrypted/decrypted data that was needed to get the specific
details to decrypt World Rally properly.
</p>
        <p>
Special mention to <a href="http://andreasnaive.blogspot.com/">Andreas Naive</a> too.
The high level information Javier told us a few days ago was already discovered by
Andreas and posted in his page a couple of months ago. Before Javier sent us detailed
information about how the encryption worked I contacted Andreas Naive about the encryption
and he told me that he didn’t have free time at the moment to look at it. However
he told me an intuition he had about the algorithm:
</p>
        <p>
"I remember that my last feeling was that to decipher each 16 bits block, it was done
in 3 chunks: a first 6 bits chunk and then two 5 bits chunks, each of them based in
a/some bits of the first chunk. I don't remember exactly which ones, but the first
chunk was the one with a simple structure (based on the tables I published), while
the other two were the ones that shown a more complex structure (and carry effects)".<br />
He was completely right as that was how it worked the encryption that Javier sent
us.<br />
 <br />
It is good to have geniouses around ;-)
</p>
        <p>
After adding the decryption to the driver the game looks like this:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0000.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0001.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0002.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0003.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0005.png" border="0" />
        </p>
        <p>
It has a few graphic glitches that will be fixed soon but it seems to be PLAYABLE ;-)
</p>
        <p>
          <strong>Update:</strong> more progress has been made. You can read about it <a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx"><font color="#003399">here</font></a></p>
        <p>
          <hr />
        </p>
        <p>
        </p>
        <p>
Javier nos ha mandado (via ElSemi) información detallada sobre cómo funciona el proceso
de encriptación. Sin embargo, las hojas donde tenía detallado el funcionamiento del
algoritmo eran difíciles de leer en algunos sitios (ya que la protección fue diseñada
hace 15 años) por lo que probablemente habría alguna errata en el fichero Excel que
nos mandó.  ElSemi y yo intentamos en vano añadir la información de Javier. <a href="http://mamelife.blogspot.com/">Nicola
Salmoria</a> ha realizado un trabajo excelente (como siempre) terminando de pulir
esa información y descubrir los detalles que faltaban. El ha implementado una función
de desencriptación que funciona no solo para el World Rally, sino también para el
Squash y el Thunder Hoop.
</p>
        <p>
Mike Coates terminó el interfaz para obtener datos de la placa del World Rally, suministrando
valores encriptados y sus correspondientes valores desencriptados, que permitieron
obtener los datos específicos necesarios para la correcta desencriptación del World
Rally.
</p>
        <p>
Mención especial a <a href="http://andreasnaive.blogspot.com/">Andreas Naive</a>.
La información de alto nivel que Javier nos dio hace unos días ya había sido descubierta
por Andreas, que la publicó en su página hace unos meses. Antes de que Javier nos
diera la información detallada sobre cómo funcionaba la encriptación, contacté con
Andreas Naive sobre el tema. Me dijo que ahora mismo no tenía tiempo disponible para
mirarlo. Sin embargo, me dijo que tenía un pálpito:
</p>
        <p>
“Al descifrar cada bloque de 16 bits, se hacía en tres trozos: un primer bloque de
6 bits y luego dos bloques de 5 bits, cada uno de ellos basados en un/unos bits del
primer bloque. No recuerdo cuáles eran cuáles, pero el primer bloque era el que tenía
una estructura más sencilla (según las tablas que publiqué), mientras que los otros
dos son los que mostraban estructura más compleja (y efectos de acarreo debidos a
alguna suma).”
</p>
        <p>
El algoritmo que nos había mandado Javier funciona exactamente de esa forma.
</p>
        <p>
Está bien estar rodeado de genios ;-)
</p>
        <p>
Después de añadir el algoritmo para desencriptar los datos, el juego mostraba este
aspecto:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0000.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0001.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0002.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0003.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0005.png" border="0" />
        </p>
        <p>
El juego tiene algunos fallos gráficos que se corregirán pronto pero es JUGABLE (lo
poco que he probado) ;-)
</p>
        <p>
          <strong>Update:</strong> se ha completado la emulación del World Rally. Puedes
leer sobre ello <a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx"><font color="#003399">aquí</font></a></p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=c7e7ab2e-fea4-4642-a9b7-e43a063662f1" />
      </body>
      <title>Playable status reached</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx</link>
      <pubDate>Sat, 10 May 2008 18:52:23 GMT</pubDate>
      <description>&lt;p&gt;
This post is first in english and then in spanish.&lt;br&gt;
Esta noticia está primero en inglés&amp;nbsp;y luego en castellano.
&lt;/p&gt;
&lt;p&gt;
Javier sent us (via ElSemi) detailed information about how the encryption process
worked. However, he told us that the sheets of paper that contained the encryption
info were a bit difficult to read in some places (remember that this protection was
designed 15 years ago) so probably there was some mistakes in the excel file he sent
us. ElSemi and I tried to add it with the information he gave us but we didn’t have
success. &lt;a href="http://mamelife.blogspot.com/"&gt;Nicola Salmoria&lt;/a&gt; did an excellent
work (as always) consolidating the information&amp;nbsp;and obtaining the missing information.
He generated a working decryption function that not only works for World Rally, but
also for Squash and Thunder Hoop.
&lt;/p&gt;
&lt;p&gt;
Mike Coates also completed the interface to get the data from a World Rally PCB, so
he was able to supply the encrypted/decrypted data that was needed to get the specific
details to decrypt World Rally properly.
&lt;/p&gt;
&lt;p&gt;
Special mention to&amp;nbsp;&lt;a href="http://andreasnaive.blogspot.com/"&gt;Andreas Naive&lt;/a&gt;&amp;nbsp;too.
The high level information Javier told us a few days ago was already discovered by
Andreas and posted in his page a couple of months ago. Before Javier sent us detailed
information about how the encryption worked I contacted Andreas Naive about the encryption
and he told me that he didn’t have free time at the moment to look at it. However
he told me an intuition he had about the algorithm:
&lt;/p&gt;
&lt;p&gt;
"I remember that my last feeling was that to decipher each 16 bits block, it was done
in 3 chunks: a first 6 bits chunk and then two 5 bits chunks, each of them based in
a/some bits of the first chunk. I don't remember exactly which ones, but the first
chunk was the one with a simple structure (based on the tables I published), while
the other two were the ones that shown a more complex structure (and carry effects)".&lt;br&gt;
He was completely right as that was how it worked the encryption that Javier sent
us.&lt;br&gt;
&amp;nbsp;&lt;br&gt;
It is good to have geniouses around ;-)
&lt;/p&gt;
&lt;p&gt;
After adding the decryption to the driver the game looks like this:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0000.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0001.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0002.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0003.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0005.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
It has a few graphic glitches that will be fixed soon but it seems to be PLAYABLE&amp;nbsp;;-)
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Update:&lt;/strong&gt; more progress has been made. You can read about it &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx"&gt;&lt;font color=#003399&gt;here&lt;/font&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;hr&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Javier nos ha mandado (via ElSemi) información detallada sobre cómo funciona el proceso
de encriptación. Sin embargo, las hojas donde tenía detallado el funcionamiento del
algoritmo eran difíciles de leer en algunos sitios (ya que la protección fue diseñada
hace 15 años) por lo que probablemente habría alguna errata en el fichero Excel que
nos mandó.&amp;nbsp; ElSemi y yo intentamos en vano añadir la información de Javier. &lt;a href="http://mamelife.blogspot.com/"&gt;Nicola
Salmoria&lt;/a&gt; ha realizado un trabajo excelente (como siempre) terminando de pulir
esa información y descubrir los detalles que faltaban. El ha implementado una función
de desencriptación que funciona no solo para el World Rally, sino también para el
Squash y el Thunder Hoop.
&lt;/p&gt;
&lt;p&gt;
Mike Coates terminó el interfaz para obtener datos de la placa del World Rally, suministrando
valores encriptados y sus correspondientes valores desencriptados, que permitieron
obtener los datos específicos necesarios para la correcta desencriptación del World
Rally.
&lt;/p&gt;
&lt;p&gt;
Mención especial a&amp;nbsp;&lt;a href="http://andreasnaive.blogspot.com/"&gt;Andreas Naive&lt;/a&gt;.
La información de alto nivel que Javier nos dio hace unos días ya había sido descubierta
por Andreas, que la publicó en su página hace unos meses. Antes de que Javier nos
diera la información detallada sobre cómo funcionaba la encriptación, contacté con
Andreas Naive sobre el tema. Me dijo que ahora mismo no tenía tiempo disponible para
mirarlo. Sin embargo, me dijo que tenía un pálpito:
&lt;/p&gt;
&lt;p&gt;
“Al descifrar cada bloque de 16 bits, se hacía en tres trozos: un primer bloque de
6 bits y luego dos bloques de 5 bits, cada uno de ellos basados en un/unos bits del
primer bloque. No recuerdo cuáles eran cuáles, pero el primer bloque era el que tenía
una estructura más sencilla (según las tablas que publiqué), mientras que los otros
dos son los que mostraban estructura más compleja (y efectos de acarreo debidos a
alguna suma).”
&lt;/p&gt;
&lt;p&gt;
El algoritmo que nos había mandado Javier funciona exactamente de esa forma.
&lt;/p&gt;
&lt;p&gt;
Está bien estar rodeado de genios ;-)
&lt;/p&gt;
&lt;p&gt;
Después de añadir el algoritmo para desencriptar los datos, el juego mostraba este
aspecto:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0000.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0001.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0002.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0003.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0005.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
El juego tiene algunos fallos gráficos que se corregirán pronto pero es JUGABLE (lo
poco que he probado) ;-)
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Update:&lt;/strong&gt; se ha completado la emulación del World Rally.&amp;nbsp;Puedes
leer sobre ello&amp;nbsp;&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx"&gt;&lt;font color=#003399&gt;aquí&lt;/font&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=c7e7ab2e-fea4-4642-a9b7-e43a063662f1" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx</comments>
      <category>Games</category>
      <category>MAME</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=6aff4d5b-3e22-4a5d-af35-22dc8293e2f9</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx</pingback:target>
      <dc:creator>Manu</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=6aff4d5b-3e22-4a5d-af35-22dc8293e2f9</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This post is first in English and then in Spanish<br />
Esta noticia está primero en inglés y luego en español
</p>
        <p>
The Dallas DS5002FP core is complete. The additions to the 8051 core are:
</p>
        <p>
- Extra Special Function Registers<br />
- Byte-wide Bus Support<br />
- Memory Partition and Memory Range<br />
- Bootstrap Configuration<br />
- Power Fail Interrupt<br />
- Timed Access<br />
- Stop Mode<br />
- Idle Mode
</p>
        <p>
I didn’t bother to add support for Peripherals, the Reprogrammable Peripheral Controller
or CRC-16 support because it isn’t used by the game.
</p>
        <p>
The communication between the Dallas and the main CPU seems to be working, however,
the game writes some bytes to the encrypted Video RAM, it reads them back and then
makes some calls based on the decrypted data. As the current decryption is wrong,
the game doesn’t work yet and never uses the dallas for anything interesting right
now.
</p>
        <p>
The decryption of the Video RAM is in the same state as it was. However, ElSemi asked
Javier for information about the decryption and he is trying to help us. He didn’t
remember how it was performed but we send him the information we got about it in 2002
(when Mike connected the PCB to the fluke) to refresh a bit his memory. Thanks to
that, he gave us another point of view about how the encryption may work. Even if
he is right, we still need to get data from the original PCB. Hopefully, somewhere
in the process we end up with a clean decrypt function that uses no tables.
</p>
        <p>
Understanding some code I was able to guess some decrypted values and get this:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrallypres.png" border="0" />
        </p>
        <p>
 
</p>
        <p>
It looks really ugly as the colors for the tiles aren’t decrypted properly but this
finally confirms that World Rally uses the same Video Hardware as Target Hits. The
only change seems to be the additional palette entries for the night races. I have
seen how the palette was configured in a night race and I have an idea of how the
palette works for the night races (not very different from World Rally 2), but we’ll
have to wait until the game works to implement it.
</p>
        <p>
So, the current status is that if the Video RAM is decrypted properly and we are lucky,
the game should work without the light effects (and maybe some priority problems)
and be playable. If we are not that lucky, hopefully the problems are not difficult
to find and fix.
</p>
        <p>
          <strong>Update:</strong> more progress has been made. You can read about it <a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx">here</a></p>
        <p>
          <hr />
        </p>
        <p>
        </p>
        <p>
El emulador del Dallas DS5002FP está completado. Lo que se ha añadido al emulador
del 8051es:
</p>
        <p>
- Registros de funciones especiales (SFRs) extra<br />
- Soporte del Byte-wide bus<br />
- Partición y Rango de memoria<br />
- Configuration de arranque<br />
- Interrupción por falta de energía<br />
- Acceso temporizado<br />
- Modo Stop<br />
- Modo Idle
</p>
        <p>
No he añadido soporte de periféricos ni el Controlador Reprogramable de Periféricos,
porque no son usados por el juego.
</p>
        <p>
La comunicación entre el Dallas y la CPU principal parece estar funcionando correctamente.
Sin embargo, el juego escribe algunos bytes a la memoria de Video encriptada, luego
los lee desencriptados y hace unos saltos dependiendo del valor desencriptado. Como
la desencriptación actual es incorrecta, el juego sigue sin funcionar todavía y no
utiliza el dallas para nada interesante todavía.
</p>
        <p>
La desencriptación de la memoria de Video sigue igual. Sin embargo, ElSemi le ha pedido
a Javier información sobre la encriptación y nos está tratando de ayudar. Javier no
recordaba cómo funcionaba la encriptación por lo que le hemos mandado la información
que obtuvimos en 2002 (cuando Mike conectó la placa al fluke) para refrescar su memoria.
Gracias a ello, Javier nos ha dado otro punto de vista de cómo podría funcionar la
encriptación. Aún si está en lo cierto, con lo que nos ha dicho aún necesitamos obtener
datos de la placa original. Con un poco de suerte, en algún momento terminaremos con
una función de desencriptación clara que no usa tablas.
</p>
        <p>
Entendiendo un poco de código he podido intuir unos cuantos valores desencriptados
y obtener esto:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrallypres.png" border="0" />
        </p>
        <p>
 
</p>
        <p>
Se ve realmente feo porque los colores de los bloques no están desencriptados correctamente
pero esto confirma finalmente que el World Rally utiliza el mismo hardware gráfico
que el Target Hits. El único cambio son unas entradas adicionales de la paleta para
las carreras nocturnas. He podido ver como se configuraba la paleta en una carrera
nocturna y tengo una idea de cómo va (parecido al World Rally 2), pero habrá
que esperar a que el juego funcione para poder implementarlo.
</p>
        <p>
Por lo tanto, el estado actual es que si la RAM de Video se desencripta correctamente
y tenemos un poco de suerte, el juego debería funcionar sin los efectos de luz (y
quizás con algún problema de prioridades), pero sería jugable. Si no somos tan afortunados,
con un poco más de trabajo encontraremos y arreglaremos los problemas que surjan.
</p>
        <p>
          <strong>Actualización:</strong> se ha avanzado un poco más. Puedes leer sobre
ello <a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx">aquí</a></p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=6aff4d5b-3e22-4a5d-af35-22dc8293e2f9" />
      </body>
      <title>More World Rally news</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx</link>
      <pubDate>Wed, 07 May 2008 06:18:05 GMT</pubDate>
      <description>&lt;p&gt;
This post is first in English and then in Spanish&lt;br&gt;
Esta noticia está primero en inglés y luego en español
&lt;/p&gt;
&lt;p&gt;
The Dallas DS5002FP core is complete. The additions to the 8051 core are:
&lt;/p&gt;
&lt;p&gt;
- Extra Special Function Registers&lt;br&gt;
- Byte-wide Bus Support&lt;br&gt;
- Memory Partition and Memory Range&lt;br&gt;
- Bootstrap Configuration&lt;br&gt;
- Power Fail Interrupt&lt;br&gt;
- Timed Access&lt;br&gt;
- Stop Mode&lt;br&gt;
- Idle Mode
&lt;/p&gt;
&lt;p&gt;
I didn’t bother to add support for Peripherals, the Reprogrammable Peripheral Controller
or CRC-16 support because it isn’t used by the game.
&lt;/p&gt;
&lt;p&gt;
The communication between the Dallas and the main CPU seems to be working, however,
the game writes some bytes to the encrypted Video RAM, it reads them back and then
makes some calls based on the decrypted data. As the current decryption is wrong,
the game doesn’t work yet and never uses the dallas for anything interesting right
now.
&lt;/p&gt;
&lt;p&gt;
The decryption of the Video RAM is in the same state as it was. However, ElSemi asked
Javier for information about the decryption and he is trying to help us. He didn’t
remember how it was performed but we send him the information we got about it in 2002
(when Mike connected the PCB to the fluke) to refresh a bit his memory. Thanks to
that, he gave us another point of view about how the encryption may work. Even if
he is right, we still need to get data from the original PCB. Hopefully, somewhere
in the process we end up with a clean decrypt function that uses no tables.
&lt;/p&gt;
&lt;p&gt;
Understanding some code I was able to guess some decrypted values and get this:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrallypres.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
It looks really ugly as the colors for the tiles aren’t decrypted properly but this
finally confirms that World Rally uses the same Video Hardware as Target Hits. The
only change seems to be the additional palette entries for the night races. I have
seen how the palette was configured in a night race and I have an idea of how the
palette works for the night races (not very different from World Rally 2), but we’ll
have to wait until the game works to implement it.
&lt;/p&gt;
&lt;p&gt;
So, the current status is that if the Video RAM is decrypted properly and we are lucky,
the game should work without the light effects (and maybe some priority problems)
and be playable. If we are not that lucky, hopefully the problems are not difficult
to find and fix.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Update:&lt;/strong&gt; more progress has been made. You can read about it &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx"&gt;here&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;hr&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
El emulador del Dallas DS5002FP está completado. Lo que se ha añadido al emulador
del 8051es:
&lt;/p&gt;
&lt;p&gt;
- Registros de funciones especiales (SFRs) extra&lt;br&gt;
- Soporte del Byte-wide bus&lt;br&gt;
- Partición y Rango de memoria&lt;br&gt;
- Configuration de arranque&lt;br&gt;
- Interrupción por falta de energía&lt;br&gt;
- Acceso temporizado&lt;br&gt;
- Modo Stop&lt;br&gt;
- Modo Idle
&lt;/p&gt;
&lt;p&gt;
No he añadido soporte de periféricos ni el Controlador Reprogramable de Periféricos,
porque no son usados por el juego.
&lt;/p&gt;
&lt;p&gt;
La comunicación entre el Dallas y la CPU principal parece estar funcionando correctamente.
Sin embargo, el juego escribe algunos bytes a la memoria de Video encriptada, luego
los lee desencriptados y hace unos saltos dependiendo del valor desencriptado. Como
la desencriptación actual es incorrecta, el juego sigue sin funcionar todavía y no
utiliza el dallas para nada interesante todavía.
&lt;/p&gt;
&lt;p&gt;
La desencriptación de la memoria de Video sigue igual. Sin embargo, ElSemi le ha pedido
a Javier información sobre la encriptación y nos está tratando de ayudar. Javier no
recordaba cómo funcionaba la encriptación por lo que le hemos mandado la información
que obtuvimos en 2002 (cuando Mike conectó la placa al fluke) para refrescar su memoria.
Gracias a ello, Javier nos ha dado otro punto de vista de cómo podría funcionar la
encriptación. Aún si está en lo cierto, con lo que nos ha dicho aún necesitamos obtener
datos de la placa original. Con un poco de suerte, en algún momento terminaremos con
una función de desencriptación clara que no usa tablas.
&lt;/p&gt;
&lt;p&gt;
Entendiendo un poco de código he podido intuir unos cuantos valores desencriptados
y obtener esto:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrallypres.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
Se ve realmente feo porque los colores de los bloques no están desencriptados correctamente
pero esto confirma finalmente que el World Rally utiliza el mismo hardware gráfico
que el Target Hits. El único cambio son unas entradas adicionales de la paleta para
las carreras nocturnas. He podido ver como se configuraba la paleta en una carrera
nocturna y tengo una idea de cómo&amp;nbsp;va (parecido al World Rally 2), pero habrá
que esperar a que el juego funcione para poder implementarlo.
&lt;/p&gt;
&lt;p&gt;
Por lo tanto, el estado actual es que si la RAM de Video se desencripta correctamente
y tenemos un poco de suerte, el juego debería funcionar sin los efectos de luz (y
quizás con algún problema de prioridades), pero sería jugable. Si no somos tan afortunados,
con un poco más de trabajo&amp;nbsp;encontraremos y arreglaremos los problemas que surjan.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Actualización:&lt;/strong&gt; se ha avanzado un poco más.&amp;nbsp;Puedes leer sobre
ello &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx"&gt;aquí&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=6aff4d5b-3e22-4a5d-af35-22dc8293e2f9" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx</comments>
      <category>Games</category>
      <category>MAME</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=c20ef5fd-9018-4b83-bba6-63ce3edb5ba5</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx</pingback:target>
      <dc:creator>Manu</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c20ef5fd-9018-4b83-bba6-63ce3edb5ba5</wfw:commentRss>
      <slash:comments>18</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This post is first in English and then in Spanish<br />
Esta noticia está primero en inglés y luego en español
</p>
        <p>
If you have tried to execute World Rally since it was added to MAME you have seen
the precarious state of the driver. The protection of World Rally is double:
</p>
        <p>
          <strong>Encrypted Video RAM:</strong>
        </p>
        <p>
The encrypted Video RAM transforms a 32 bits value written to it to another value
that is really complex to derive from the original value. This protection was also
used in Thunder Hoop and Squash. Mike Coates connected a fluke to his PCBs and got
a 4 GB file will all possible combinations (2^32) for Thunder Hoop and Squash. 
Using that file, the encryption process was replicated.  However, it was not
very practical to require a 16 GB file to run the game. Nicola Salmoria studied
the file and generated some code (about 400 lines) that replicated the original encryption.
That’s why you can play Thunder Hoop and Squash.
</p>
        <p>
Why World Rally encryption is incomplete? All of us wanted to see World Rally running
before any other game, so we started studying World Rally before Squash and Thunder
Hoop. In that time, we thought that the encryption was only performed in 16 bits,
not 32. Unfortunately, when Mike got all decrypted values (2^16), the code was clearly
showing that the decrypted values were not correct in most cases (for example, one
of the methods that draws the tiles uses a decrypted value for the number of tiles
to draw. That’s why the power on self test results and other screens look horrible
right now).  After we find that out, the decryption efforts were centered in
the other games. As World Rally was not going to be playable unless the dallas code
was dumped (something that seemed unlikely), it has remained that way.
</p>
        <p>
          <strong>Dallas DS5002FP secure MCU:</strong>
        </p>
        <p>
The Dallas MCU in the Gaelco games has some critical code that handles inputs, objects
manipulation and other complex calculations that prevent the game from working properly
(Take a look at World Rally 2 if you don’t know what I mean). The DS5002FP MCU has
been one of the best chips for protecting information on its era making emulation
of these games impossible for now. There are some specialized labs that claim to be
able to get the code from a DS5002FP but it is an incredibly expensive process we
can’t afford.
</p>
        <p>
I have to admit that I thought that I’d never see World Rally emulated, as I approached
some people at Gaelco and Zigurat for the Dallas code without luck. However, the other
day I received an email that changed my mind. Miguel Angel Horna (ElSemi) did a talk
at Lleida Lan Party about emulation. At the party he met one of the Gaelco founders
(Javier Valero) that was there to speak about the arcade game industry. ElSemi and
Javier talked about the protection in some Gaelco games and Javier was kind enough
to provide the dallas code for World Rally. With the internal code of the DS5002FP
it is just a matter of time to finally have a working driver in MAME.
</p>
        <p>
I have been completely inactive from <a href="http://mamedev.org/">MAME</a> development
for a while but as I worked on the drivers of all the Gaelco 2D games (except Master
Boy) and I spent a lot of time and money on them, I thought it was a good time to
resume my work on MAME. 
</p>
        <p>
Mike Coates is trying to get all the possible values from World Rally Video RAM so
we can advance in that area too.
</p>
        <p>
Currently I am writing a DS5002FP core to run the dallas code. The DS5002FP is just
a 8051 MCU with some additions and as MAME already has a 8051 core things are going
fast. For example, the initial coprocessor test works (although it is a trivial test
to pass without the dallas code):
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrally1.png" border="0" />
        </p>
        <p>
Also, adding the Power Fail Interrupt of the dallas I managed to see this screen that
is supposed to be seen when the dallas is dying:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrally2.png" border="0" />
        </p>
        <p>
After the both protections are emulated the driver will need more work as probably
the video hardware emulation isn’t complete and needs some tweaks here and there but
I’m confident that World Rally will be playable in a not so distant future. I don’t
know if Javier will give us more dallas code or not, but hats off to him for this
one. Also, thanks a lot to ElSemi for being able to get the dallas code from him.
</p>
        <p>
          <strong>Update:</strong> more progress has been made. You can read about it <a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx">here</a></p>
        <p>
          <hr />
        </p>
        <p>
        </p>
        <p>
Si has tratado de ejecutar el World Rally desde que fue añadido al MAME habrás visto
el estado tan precario del driver. La protección del World Rally es doble:
</p>
        <p>
          <strong>Memoria de Video Encriptada:</strong>
        </p>
        <p>
La memoria de video encriptada transforma los valores de 32 bits que se escriben en
ella, de forma que el valor resultante es extremadamente difícil de obtenerlo dado
el valor original. Esta protección también se utilizó en el Thunder Hoop y en el Squash.
Mike Coates conecto un fluke a su placa y obtuvo un archivo de 4 GB con todas las
combinaciones posibles (2^32). Usando ese archivo, se pudo replicar la encriptación.
Sin embargo, no era muy práctico necesitar un archivo de 16 GB para ejecutar
el juego. Nicola Salmoria estudió el archivo y obtuvo un código (cerca de 400 líneas)
que obtenía los mismos valores de la encriptación. Por ello se puede jugar al Thunder
Hoop y al Squash actualmente.
</p>
        <p>
¿Por qué la encriptación del World Rally está incompleta? Todos queríamos ver el World
Rally funcionando antes que cualquier otro juego, por lo que empezamos a estudiar
el World Rally antes que el Squash y el Thunder Hoop. En esa época, pensábamos que
la encriptación solo era de 16 bits, no de 32. Cuando Mike obtuvo los valores desencriptados
(2^16) pudimos comprobar la cruda realidad. El código mostraba claramente que los
valores desencriptados no eran correctos en la mayoría de los casos (por ejemplo,
uno de los métodos que dibuja los fondos de las pantallas usa un valor desencriptado
como el número de bloques a dibujar. Por eso la carta de ajuste inicial que muestra
los resultados de los tests iniciales se ve tan mal actualmente). Después de percatarnos
de nuestro error, los esfuerzos se centraron en el resto de juegos. Como el World
Rally no iba a ser jugable a no ser que el código del dallas se obtuviera  (cosa
que parecía altamente improbable), se ha mantenido como estaba.
</p>
        <p>
          <strong>Microcontrollador Dallas DS5002FP:</strong>
        </p>
        <p>
El Microcontrolador Dallas en los juegos de Gaelco contiene código crítico que maneja
la entradas de los jugadores, la manipulación de objetos u otros cálculos complejos
que hacen que los juegos no funcionen correctamente (prueba el World Rally 2 si no
sabes a lo que me refiero). El DS5002FP ha sido uno de los chips con más éxito a la
hora de proteger información en su época, haciendo que la emulación de estos juegos
fuera imposible. Hay laboratorios especializados que presumen de poder obtener el
código de un DS5002FP pero es un proceso increíblemente caro que no nos podemos permitir.
</p>
        <p>
Debo admitir que pensé que nunca vería el Word Rally emulado, ya que contacté con
varias personas de Gaelco y Zigurat preguntando por el código del Dallas pero no hubo
suerte en ese momento. Sin embargo, el otro día recibí un email que me hizo cambiar
de opinión. Miguel Angel Horna (ElSemi) dio una charla en la Lleida Lan Party sobre
emulación. En la party conoció a uno de los fundadores de Gaelco (Javier Valero) que
estaba allí para hablar acerca de la industria de los juegos recreativos. ElSemi y
Javier hablaron sobre la protección en algunos juegos de Gaelco y Javier tuvo el detalle
de dar el código del dallas que usa el World Rally. Con el código interno del DS5002FP
es sólo una cuestión de tiempo de que finalmente el juego pueda funcionar correctamente
en el MAME.
</p>
        <p>
He estado completamente inactivo en el desarrollo de cosas para el <a href="http://mamedev.org/">MAME</a> bastante
tiempo, pero como trabajé en los drivers de todos los juegos 2D de Gaelco (excepto
el Master Boy) y me he dejado un montón de tiempo y dinero en ellos, he pensado que
sería un buen momento para trabajar un poco más en el MAME.
</p>
        <p>
Mike Coates está tratando de obtener los posibles valores de la memoria encriptada
del World Rally para ir avanzando en ese aspecto.
</p>
        <p>
Por mi parte, estoy escribiendo un core para el procesador DS5002FP de forma que se
pueda ejecutar el código del dallas en MAME. El DS5002FP es un microcontrolador 8051
con ligeros cambios, y como ya hay un core del 8051 en MAME, la cosa avanza rápido.
Por ejemplo, las comprobaciones iniciales del coprocesador funcionan (aunque es un
test tan sencillo, que se puede parchear sin tener el código del dallas, pero bueno):
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrally1.png" border="0" />
        </p>
        <p>
Emulando la interrupción de fallo de tension del dallas, he conseguido ver esta pantalla
que se muestra cuando se le acaba la pila al dallas y su contenido deja de funcionar:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrally2.png" border="0" />
        </p>
        <p>
Después de que ámbas protecciones hayan sido emuladas el driver necesitara un poco
más de trabajo porque probablemente la emulación de video requiera unas mejoras pero
estoy convencido de que el World Rally será jugable en un futuro no muy lejano. No
se si Javier nos pasará más códigos del dallas para otros juegos o no, pero me quito
el sombrero por lo que ya nos ha dado. Muchísimas gracias a ElSemi por conseguir el
código del Dallas.
</p>
        <p>
          <strong>Actualización:</strong> se ha avanzado un poco más. Puedes leer sobre
ello <a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx">aquí</a></p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=c20ef5fd-9018-4b83-bba6-63ce3edb5ba5" />
      </body>
      <title>World Rally, finally</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx</link>
      <pubDate>Mon, 05 May 2008 19:19:39 GMT</pubDate>
      <description>&lt;p&gt;
This post is first in English and then in Spanish&lt;br&gt;
Esta noticia está primero en inglés y luego en español
&lt;/p&gt;
&lt;p&gt;
If you have tried to execute World Rally since it was added to MAME you have seen
the precarious state of the driver. The protection of World Rally is double:
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Encrypted Video RAM:&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
The encrypted Video RAM transforms a 32 bits value written to it to another value
that is really complex to derive from the original value. This protection was also
used in Thunder Hoop and Squash. Mike Coates connected a fluke to his PCBs and got
a 4 GB file will all possible combinations (2^32) for Thunder Hoop and Squash.&amp;nbsp;
Using that file, the encryption process was replicated.&amp;nbsp; However, it was not
very practical to require a&amp;nbsp;16 GB file to run the game. Nicola Salmoria studied
the file and generated some code (about 400 lines) that replicated the original encryption.
That’s why you can play Thunder Hoop and Squash.
&lt;/p&gt;
&lt;p&gt;
Why World Rally encryption is incomplete? All of us wanted to see World Rally running
before any other game, so we started studying World Rally before Squash and Thunder
Hoop. In that time, we thought that the encryption was only performed in 16 bits,
not 32. Unfortunately, when Mike got all decrypted values (2^16), the code was clearly
showing that the decrypted values were not correct in most cases (for example, one
of the methods that draws the tiles uses a decrypted value for the number of tiles
to draw. That’s why the power on self test results and other screens look horrible
right now).&amp;nbsp; After we find that out, the decryption efforts were centered in
the other games. As World Rally was not going to be playable unless the dallas code
was dumped (something that seemed unlikely), it has remained that way.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Dallas DS5002FP secure MCU:&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
The Dallas MCU in the Gaelco games has some critical code that handles inputs, objects
manipulation and other complex calculations that prevent the game from working properly
(Take a look at World Rally 2 if you don’t know what I mean). The DS5002FP MCU has
been one of the best chips for protecting information on its era making emulation
of these games impossible for now. There are some specialized labs that claim to be
able to get the code from a DS5002FP but it is an incredibly expensive process we
can’t afford.
&lt;/p&gt;
&lt;p&gt;
I have to admit that I thought that I’d never see World Rally emulated, as I approached
some people at Gaelco and Zigurat for the Dallas code without luck. However, the other
day I received an email that changed my mind. Miguel Angel Horna (ElSemi) did a talk
at Lleida Lan Party about emulation. At the party he met one of the Gaelco founders
(Javier Valero) that was there to speak about the arcade game industry. ElSemi and
Javier talked about the protection in some Gaelco games and Javier was kind enough
to provide the dallas code for World Rally. With the internal code of the DS5002FP
it is just a matter of time to finally have a working driver in MAME.
&lt;/p&gt;
&lt;p&gt;
I have been completely inactive from &lt;a href="http://mamedev.org/"&gt;MAME&lt;/a&gt; development
for a while but as I worked on the drivers of all the Gaelco 2D games (except Master
Boy) and I spent a lot of time and money on them, I thought it was a good time to
resume my work on MAME. 
&lt;/p&gt;
&lt;p&gt;
Mike Coates is trying to get all the possible values from World Rally Video RAM so
we can advance in that area too.
&lt;/p&gt;
&lt;p&gt;
Currently I am writing a DS5002FP core to run the dallas code. The DS5002FP is just
a 8051 MCU with some additions and as MAME already has a 8051 core things are going
fast. For example, the initial coprocessor test works (although it is a trivial test
to pass without the dallas code):
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrally1.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Also, adding the Power Fail Interrupt of the dallas I managed to see this screen that
is supposed to be seen when the dallas is dying:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrally2.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
After the both protections are emulated the driver will need more work as probably
the video hardware emulation isn’t complete and needs some tweaks here and there but
I’m confident that World Rally will be playable in a not so distant future. I don’t
know if Javier will give us more dallas code or not, but hats off to him for this
one. Also, thanks a lot to ElSemi for being able to get the dallas code from him.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Update:&lt;/strong&gt; more progress has been made. You can read about it &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx"&gt;here&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;hr&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Si has tratado de ejecutar el World Rally desde que fue añadido al MAME habrás visto
el estado tan precario del driver. La protección del World Rally es doble:
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Memoria de Video Encriptada:&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
La memoria de video encriptada transforma los valores de 32 bits que se escriben en
ella, de forma que el valor resultante es extremadamente difícil de obtenerlo dado
el valor original. Esta protección también se utilizó en el Thunder Hoop y en el Squash.
Mike Coates conecto un fluke a su placa y obtuvo un archivo de 4 GB con todas las
combinaciones posibles (2^32). Usando ese archivo, se pudo replicar la encriptación.
Sin embargo, no era muy práctico necesitar un archivo de&amp;nbsp;16 GB para ejecutar
el juego. Nicola Salmoria estudió el archivo y obtuvo un código (cerca de 400 líneas)
que obtenía los mismos valores de la encriptación. Por ello se puede jugar al Thunder
Hoop y al Squash actualmente.
&lt;/p&gt;
&lt;p&gt;
¿Por qué la encriptación del World Rally está incompleta? Todos queríamos ver el World
Rally funcionando antes que cualquier otro juego, por lo que empezamos a estudiar
el World Rally antes que el Squash y el Thunder Hoop. En esa época, pensábamos que
la encriptación solo era de 16 bits, no de 32. Cuando Mike obtuvo los valores desencriptados
(2^16) pudimos comprobar la cruda realidad. El código mostraba claramente que los
valores desencriptados no eran correctos en la mayoría de los casos (por ejemplo,
uno de los métodos que dibuja los fondos de las pantallas usa un valor desencriptado
como el número de bloques a dibujar. Por eso la carta de ajuste inicial que muestra
los resultados de los tests iniciales se ve tan mal actualmente). Después de percatarnos
de nuestro error, los esfuerzos se centraron en el resto de juegos. Como el World
Rally no iba a ser jugable a no ser que el código del dallas se obtuviera&amp;nbsp; (cosa
que parecía altamente improbable), se ha mantenido como estaba.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Microcontrollador Dallas DS5002FP:&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
El Microcontrolador Dallas en los juegos de Gaelco contiene código crítico que maneja
la entradas de los jugadores, la manipulación de objetos u otros cálculos complejos
que hacen que los juegos no funcionen correctamente (prueba el World Rally 2 si no
sabes a lo que me refiero). El DS5002FP ha sido uno de los chips con más éxito a la
hora de proteger información en su época, haciendo que la emulación de estos juegos
fuera imposible. Hay laboratorios especializados que presumen de poder obtener el
código de un DS5002FP pero es un proceso increíblemente caro que no nos podemos permitir.
&lt;/p&gt;
&lt;p&gt;
Debo admitir que pensé que nunca vería el Word Rally emulado, ya que contacté con
varias personas de Gaelco y Zigurat preguntando por el código del Dallas pero no hubo
suerte en ese momento. Sin embargo, el otro día recibí un email que me hizo cambiar
de opinión. Miguel Angel Horna (ElSemi) dio una charla en la Lleida Lan Party sobre
emulación. En la party conoció a uno de los fundadores de Gaelco (Javier Valero) que
estaba allí para hablar acerca de la industria de los juegos recreativos. ElSemi y
Javier hablaron sobre la protección en algunos juegos de Gaelco y Javier tuvo el detalle
de dar el código del dallas que usa el World Rally. Con el código interno del DS5002FP
es sólo una cuestión de tiempo de que finalmente el juego pueda funcionar correctamente
en el MAME.
&lt;/p&gt;
&lt;p&gt;
He estado completamente inactivo en el desarrollo de cosas para el &lt;a href="http://mamedev.org/"&gt;MAME&lt;/a&gt; bastante
tiempo, pero como trabajé en los drivers de todos los juegos 2D de Gaelco (excepto
el Master Boy) y me he dejado un montón de tiempo y dinero en ellos, he pensado que
sería un buen momento para trabajar un poco más en el MAME.
&lt;/p&gt;
&lt;p&gt;
Mike Coates está tratando de obtener los posibles valores de la memoria encriptada
del World Rally para ir avanzando en ese aspecto.
&lt;/p&gt;
&lt;p&gt;
Por mi parte, estoy escribiendo un core para el procesador DS5002FP de forma que se
pueda ejecutar el código del dallas en MAME. El DS5002FP es un microcontrolador 8051
con ligeros cambios, y como ya hay un core del 8051 en MAME, la cosa avanza rápido.
Por ejemplo, las comprobaciones iniciales del coprocesador funcionan (aunque es un
test tan sencillo, que se puede parchear sin tener el código del dallas, pero bueno):
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrally1.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Emulando la interrupción de fallo de tension del dallas, he conseguido ver esta pantalla
que se muestra cuando se le acaba la pila al dallas y su contenido deja de funcionar:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrally2.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Después de que ámbas protecciones hayan sido emuladas el driver necesitara un poco
más de trabajo porque probablemente la emulación de video requiera unas mejoras pero
estoy convencido de que el World Rally será jugable en un futuro no muy lejano. No
se si Javier nos pasará más códigos del dallas para otros juegos o no, pero me quito
el sombrero por lo que ya nos ha dado. Muchísimas gracias a ElSemi por conseguir el
código del Dallas.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Actualización:&lt;/strong&gt; se ha avanzado un poco más.&amp;nbsp;Puedes leer sobre
ello&amp;nbsp;&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx"&gt;aquí&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=c20ef5fd-9018-4b83-bba6-63ce3edb5ba5" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx</comments>
      <category>Games</category>
      <category>MAME</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=1265968d-573a-42f2-8382-9a35e2226272</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,1265968d-573a-42f2-8382-9a35e2226272.aspx</pingback:target>
      <dc:creator>Manu</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,1265968d-573a-42f2-8382-9a35e2226272.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=1265968d-573a-42f2-8382-9a35e2226272</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Probably most of you have heard about AdSense, the ad serving program run by Google.
It is very simple to have a website to display ads using AdSense, as you only need
to include an external script with a few parameters (that mainly configure the size
and colors of the ads). For each click in a banner of the website, the associated
AdSense account gets a bit of money.
</p>
        <p>
However, this is not the only way to get AdSense in your pages. Google has the "<a href="http://code.google.com/apis/adsense/">AdSense
API</a>", which consists in several web services that allow sharing the revenue of
the banners between the website owner and the content publisher. That way, website
with user generated content can pay their users if their content is useful.
</p>
        <p>
A customer asked me to modify their website so they can share some of the benefits
of their banners with the creators of the articles in their site using the AdSense
API. I’ll detail some of my experiences with the integration of the AdSense API in
the webpage.
</p>
        <p>
As I had to deal with web services, and I was comfortable with the web service support
present in the .NET Framework 2.0, the easiest thing to do for me was to follow that
route. However, I always try to learn new stuff when I can, so it was an excellent
chance for me to learn WCF. Creating a proxy for a web service in WCF is as easy as
in .NET Framework 2.0. However, the problems started really soon. For some unknown
reason, the Google guys require some SOAP headers in the web service calls that are
not exposed in the AdSense’s WSDL. Reading some of the comments in the AdSense Group
revealed that the SOAP headers were exposed previously but they were removed without
giving any reason. I found this to be really annoying and. It can be fixed adding
the headers to the OutgoingMessageHeaders in the current OperationScope. Only for
this detail the Adsense API can be labeled as unfriendly for the developers.
</p>
        <p>
Once you set the headers manually, it is easy to call to the different methods to
create AdSense accounts, associate them with a publisher and generate the code to
display ads. However, I found very confusing some parts of the documentation, specially
all the ids available (you end up using clientId, publisherId,  synServiceId,
developerId, and in some methods having to pass the same id twice).
</p>
        <p>
Inspecting the generated code for the WCF proxy, I found one thing I didn’t like about
WCF. The DataContractSerializer does not handle bare arrays, so the generated code
was using the XmlSerializer for a lot of things that need directly or indirectly to
handle bare arrays in the AdSense API. The official statement of Microsoft about this
seems to be that bare arrays do not support the distinction between null arrays and
empty arrays, so the best is to use a wrapped collection.
</p>
        <p>
The AdSense API has a technical requirements page that informs you how to proceed
in some interactions with the users and how to react to error conditions. The AdSense
API methods expose the fault details as specified in the AdSenseApiException. When
an error happens when your WCF proxy is calling to the AdSense API, a FaultException
is generated. I was expecting the proxy to receive a FaultException&lt; AdSenseApiException&gt;
instead so I could easily access to the exception details but that wasn’t the case
(maybe that only works in WCF to WCF scenarios?). I tried to create a generic error
handler in order to convert the SOAP faults to the FaultException&lt;AdSenseApiException&gt;
type, but the information I found about WCF error handling in the web was only talking
about server side error handling using the IErrorHandler interface. It was clear that
I needed more in depth knowledge of WCF in order to do that. After some research I
bought Inside Windows Communication Foundation:
</p>
        <iframe style="WIDTH: 120px; HEIGHT: 240px" marginwidth="0" marginheight="0" src="http://rcm.amazon.com/e/cm?t=manuelabadias-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=0735623066&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" frameborder="0" scrolling="no">
        </iframe>
        <p>
The book was exactly what I was looking for. Good and detailed internal information
about how WCF worked.
</p>
        <p>
Thanks to the book I was able to make my proxy generate the FaultException&lt;AdSenseApiException&gt;
transparently, but it wasn’t easy. Well, it is not difficult but you have to create
a lot of classes to do something simple.
</p>
        <p>
A channel exposes a method called GetProperty&lt;T&gt;. When an exception is generated
in the channel, the GetProperty&lt;T&gt; method is called with a parameter of type
FaultConverter. The method should return an an instance of a FaultConverter, which
creates the appropriate exception/fault type. To solve my problem I created an AdSenseFaultConverter:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/adsenseapi1.gif" border="0" />
        </p>
        <p>
However, in order to expose the AdSenseFaultConverter I had to create a ChannelFactory
(AdSenseChannelFactory), a channel (AdSenseChannelBase and AdSenseRequestChannel),
a Binding (AdSenseHttpBinding), and a BindingElement (AdSenseBindingElement). A lot
of classes with little added value just to override the GetProperty&lt;T&gt; method
in the channel. Also, to be able to use the configuration instead of setting up the
communication programmatically, I had to create a configuration BindingElement(AdSenseHttpBindingElement)
and a CollectionBindingElement (AdSenseHttpBindingCollectionElement). As I said before,
it is a lot of code.
</p>
        <p>
One thing that I haven’t commented yet is that your AdSense API implementation needs
to be reviewed in order to be able to serve live ads, and you need to follow some
policy requirements that you need to carefully study as they want to control even
the help pages you put in your web site. One of the requirements to be eligible to
participate in the AdSense API program is to have more than 100000 daily page views.
This is a showstopper for most of the web sites making the AdSense API useless for
99.9% of the people.
</p>
        <p>
Another negative point of the AdSense API is that the WSDL has been broken for more
than a month. I planned to write this article a couple of months ago so I don’t know
if the WSDL of the AdSense API is still invalid or not, but having it broken for more
than a month can give you an idea of the overall satisfaction I have with the AdSense
API.
</p>
        <p>
To finish talking about the AdSense API, I have to mention the Sandbox. The development
web services don’t behave exactly as the live web services (something that I hate),
so some methods need to have additional headers when testing the API to work properly.
Why? Well, basically because they do not have a decent sandbox. They just have the
development version of the web services and you have to live with that. No GUI for
managing the developers accounts, payments or something similar to the AdSense account
webpage. If you compare this to other sandboxes like the paypal one where you can
even receive the IPN confirmation messages you can clearly see the difference.
</p>
        <p>
And the last rant of the post is about Google policies regarding to AdWords and AdSense.
If you are an European citizen and you want to advertise using AdWords, Google forces
you to pay in Euros. However, when you have AdSense in your page, Google will pay
you in dollars. Judging by the prices of the ads in AdWords and the money you receive
with AdSense, Google is taking advantage of the European citizens by charging a 60%
more for an ad in AdWords and paying a 60% less for it (the exchange rate is approximately
1 euro = 1.60 dollars). Is the European commission too busy fining Microsoft for including
free products with Windows to investigate things like this?
</p>
        <p>
To sum up, I’m completely disappointed with Google and their AdSense API. If some
people ever had the illusion that Google was a non evil company that did the things
the right way, they need to wake up.<br /></p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=1265968d-573a-42f2-8382-9a35e2226272" />
      </body>
      <title>Google and AdSense</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,1265968d-573a-42f2-8382-9a35e2226272.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,1265968d-573a-42f2-8382-9a35e2226272.aspx</link>
      <pubDate>Mon, 28 Apr 2008 21:25:28 GMT</pubDate>
      <description>&lt;p&gt;
Probably most of you have heard about AdSense, the ad serving program run by Google.
It is very simple to have a website to display ads using AdSense, as you only need
to include an external script with a few parameters (that mainly configure the size
and colors of the ads). For each click in a banner of the website, the associated
AdSense account gets a bit of money.
&lt;/p&gt;
&lt;p&gt;
However, this is not the only way to get AdSense in your pages. Google has the "&lt;a href="http://code.google.com/apis/adsense/"&gt;AdSense
API&lt;/a&gt;", which consists in several web services that allow sharing the revenue of
the banners between the website owner and the content publisher. That way, website
with user generated content can pay their users if their content is useful.
&lt;/p&gt;
&lt;p&gt;
A customer asked me to modify their website so they can share some of the benefits
of their banners with the creators of the articles in their site using the AdSense
API. I’ll detail some of my experiences with the integration of the AdSense API in
the webpage.
&lt;/p&gt;
&lt;p&gt;
As I had to deal with web services, and I was comfortable with the web service support
present in the .NET Framework 2.0, the easiest thing to do for me was to follow that
route. However, I always try to learn new stuff when I can, so it was an excellent
chance for me to learn WCF. Creating a proxy for a web service in WCF is as easy as
in .NET Framework 2.0. However, the problems started really soon. For some unknown
reason, the Google guys require some SOAP headers in the web service calls that are
not exposed in the AdSense’s WSDL. Reading some of the comments in the AdSense Group
revealed that the SOAP headers were exposed previously but they were removed without
giving any reason. I found this to be really annoying and. It can be fixed adding
the headers to the OutgoingMessageHeaders in the current OperationScope. Only for
this detail the Adsense API can be labeled as unfriendly for the developers.
&lt;/p&gt;
&lt;p&gt;
Once you set the headers manually, it is easy to call to the different methods to
create AdSense accounts, associate them with a publisher and generate the code to
display ads. However, I found very confusing some parts of the documentation, specially
all the ids available (you end up using clientId, publisherId,&amp;nbsp; synServiceId,
developerId, and in some methods having to pass the same id twice).
&lt;/p&gt;
&lt;p&gt;
Inspecting the generated code for the WCF proxy, I found one thing I didn’t like about
WCF. The DataContractSerializer does not handle bare arrays, so the generated code
was using the XmlSerializer for a lot of things that need directly or indirectly to
handle bare arrays in the AdSense API. The official statement of Microsoft about this
seems to be that bare arrays do not support the distinction between null arrays and
empty arrays, so the best is to use a wrapped collection.
&lt;/p&gt;
&lt;p&gt;
The AdSense API has a technical requirements page that informs you how to proceed
in some interactions with the users and how to react to error conditions. The AdSense
API methods expose the fault details as specified in the AdSenseApiException. When
an error happens when your WCF proxy is calling to the AdSense API, a FaultException
is generated. I was expecting the proxy to receive a FaultException&amp;lt; AdSenseApiException&amp;gt;
instead so I could easily access to the exception details but that wasn’t the case
(maybe that only works in WCF to WCF scenarios?). I tried to create a generic error
handler in order to convert the SOAP faults to the FaultException&amp;lt;AdSenseApiException&amp;gt;
type, but the information I found about WCF error handling in the web was only talking
about server side error handling using the IErrorHandler interface. It was clear that
I needed more in depth knowledge of WCF in order to do that. After some research I
bought Inside Windows Communication Foundation:
&lt;/p&gt;
&lt;iframe style="WIDTH: 120px; HEIGHT: 240px" marginwidth=0 marginheight=0 src="http://rcm.amazon.com/e/cm?t=manuelabadias-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=0735623066&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" frameborder=0 scrolling=no&gt;
&lt;/iframe&gt;
&lt;p&gt;
The book was exactly what I was looking for. Good and detailed internal information
about how WCF worked.
&lt;/p&gt;
&lt;p&gt;
Thanks to the book I was able to make my proxy generate the FaultException&amp;lt;AdSenseApiException&amp;gt;
transparently, but it wasn’t easy. Well, it is not difficult but you have to create
a lot of classes to do something simple.
&lt;/p&gt;
&lt;p&gt;
A channel exposes a method called GetProperty&amp;lt;T&amp;gt;. When an exception is generated
in the channel, the GetProperty&amp;lt;T&amp;gt; method is called with a parameter of type
FaultConverter. The method should return an an instance of a FaultConverter, which
creates the appropriate exception/fault type. To solve my problem I created an AdSenseFaultConverter:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/adsenseapi1.gif" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
However, in order to expose the AdSenseFaultConverter I had to create a ChannelFactory
(AdSenseChannelFactory), a channel (AdSenseChannelBase and AdSenseRequestChannel),
a Binding (AdSenseHttpBinding), and a BindingElement (AdSenseBindingElement). A lot
of classes with little added value just to override the GetProperty&amp;lt;T&amp;gt; method
in the channel. Also, to be able to use the configuration instead of setting up the
communication programmatically, I had to create a configuration BindingElement(AdSenseHttpBindingElement)
and a CollectionBindingElement (AdSenseHttpBindingCollectionElement). As I said before,
it is a lot of code.
&lt;/p&gt;
&lt;p&gt;
One thing that I haven’t commented yet is that your AdSense API implementation needs
to be reviewed in order to be able to serve live ads, and you need to follow some
policy requirements that you need to carefully study as they want to control even
the help pages you put in your web site. One of the requirements to be eligible to
participate in the AdSense API program is to have more than 100000 daily page views.
This is a showstopper for most of the web sites making the AdSense API useless for
99.9% of the people.
&lt;/p&gt;
&lt;p&gt;
Another negative point of the AdSense API is that the WSDL has been broken for more
than a month. I planned to write this article a couple of months ago so I don’t know
if the WSDL of the AdSense API is still invalid or not, but having it broken for more
than a month can give you an idea of the overall satisfaction I have with the AdSense
API.
&lt;/p&gt;
&lt;p&gt;
To finish talking about the AdSense API, I have to mention the Sandbox. The development
web services don’t behave exactly as the live web services (something that I hate),
so some methods need to have additional headers when testing the API to work properly.
Why? Well, basically because they do not have a decent sandbox. They just have the
development version of the web services and you have to live with that. No GUI for
managing the developers accounts, payments or something similar to the AdSense account
webpage. If you compare this to other sandboxes like the paypal one where you can
even receive the IPN confirmation messages you can clearly see the difference.
&lt;/p&gt;
&lt;p&gt;
And the last rant of the post is about Google policies regarding to AdWords and AdSense.
If you are an European citizen and you want to advertise using AdWords, Google forces
you to pay in Euros. However, when you have AdSense in your page, Google will pay
you in dollars. Judging by the prices of the ads in AdWords and the money you receive
with AdSense, Google is taking advantage of the European citizens by charging a 60%
more for an ad in AdWords and paying a 60% less for it (the exchange rate is approximately
1 euro = 1.60 dollars). Is the European commission too busy fining Microsoft for including
free products with Windows to investigate things like this?
&lt;/p&gt;
&lt;p&gt;
To sum up, I’m completely disappointed with Google and their AdSense API. If some
people ever had the illusion that Google was a non evil company that did the things
the right way, they need to wake up.&lt;br&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=1265968d-573a-42f2-8382-9a35e2226272" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,1265968d-573a-42f2-8382-9a35e2226272.aspx</comments>
      <category>General</category>
      <category>Microsoft .NET Framework</category>
      <category>AdSense</category>
      <category>WCF</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=a073bf47-5324-4884-9e2f-730fb8d78f7b</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,a073bf47-5324-4884-9e2f-730fb8d78f7b.aspx</pingback:target>
      <dc:creator>Manu</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,a073bf47-5324-4884-9e2f-730fb8d78f7b.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=a073bf47-5324-4884-9e2f-730fb8d78f7b</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
        </p>
        <p>
One of the tools I’m using is NDepend (<a href="http://www.ndepend.com/">http://www.ndepend.com/</a>).
It is a cool application that can be used for a lot of things, as will be detailed
later. 
</p>
        <p>
To use NDepend you have to feed it with a set of assemblies. After that, it will analyze
those assemblies and their reference assemblies. If the PDBs of the assemblies are
available it will use them so more data is analyzed, although the PDBs are not needed
for NDepend to work.
</p>
        <p>
After the analysis has been completed, NDepend looks like this:
</p>
        <img src="http://www.manuelabadia.com/blog/content/binary/ndepend1.png" border="0" />
        <p>
          <br />
I have used version 1.1 of Spring.NET Framework (<a href="http://www.springframework.net/">http://www.springframework.net/</a>)
for the sample. As you can see the application has a beautiful GUI. I’ll talk a bit
about the main windows of the tool:
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
• Metrics: this window gives a graphical high level view of the project. You
can see a lot of ellipses and some of them that are made of smaller ellipses. The
big ellipses are types of the project. If a big ellipse is made of several smaller
ellipses, those smaller ellipses are the methods of the type. The types of the same
namespace are distributed in the same rectangular region, separated by a small yellow
line. The assemblies are separated by a thicker yellow line. 
</p>
          <p>
By watching this window you can get an idea of which assemblies contain more code,
which types are big, which types have a lot of methods, etc. The window was in “Method
Level”. The available levels are Assembly, Namespace, Type, Method and Field.
</p>
          <p>
• Class Browser: this is where the assemblies of the project and its referenced
assemblies are shown. You can expand the assembly up to the field level. While you
hover over an item in most windows, the Metrics window gets updated highlighting the
hovered item. 
</p>
          <p>
What it’s really cool about the Class Browser is that for the referenced assemblies,
only the namespaces, types, methods and other items that are used by the project are
shown.
</p>
          <p>
• Info: When you hover over an item the information about it is displayed here,
with some metrics if applicable. There are a lot of metrics so it can take time to
interiorize them and judge their value appropriately.
</p>
          <p>
• Dependencies: this window is a bit intimidating at first but like a lot of
things, with a bit of effort you can master it. The window displays very important
information of the dependencies in a matrix form. As in other windows, the detail
level is selectable, from the assembly level to the field level. 
</p>
          <p>
A cell can have 3 colors. Blue means that the associated item in the top header uses
the associated item in the left header. Green means that the associated item in the
left header is using the associated item in the top header. Black means a cyclic dependency.
The blue and green cells express the same dependency using opposite points of view. 
</p>
          <p>
You can see a diagram of the dependencies clicking on a cell. For example, if you
click in the cell corresponding to System.Web.Extensions and System.Web you get this:
</p>
          <img src="http://www.manuelabadia.com/blog/content/binary/BoxAndArrowGraph.PNG" border="0" />
          <p>
To read more about the theory of dependencies take a look here:
</p>
          <p>
            <a href="http://www.theserverside.net/tt/articles/showarticle.tss?id=ControllingDependencies">ttp://www.theserverside.net/tt/articles/showarticle.tss?id=ControllingDependencies</a>
          </p>
          <p>
• CQL Queries: CQL stands for Code Query Language and it is a central piece of
NDepend. Being able to ask questions about the code is great. If you like using the
Analyzer window in Reflector you’ll love this. You can create new queries and modify
the existing ones.
</p>
        </blockquote>
        <p dir="ltr">
I have presented the main NDepend windows, but the main question is: what you can
do with NDepend?
</p>
        <p dir="ltr">
There are several uses that I can think of:
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p dir="ltr">
• It is an excellent tool to check differences between different builds of an
assembly. You can use it as a diff tool, as it will show in the Class Browser which
types, methods, etc have been added, removed or changed. This information is also
available for CQL Queries, with the power that it implies.
</p>
          <p>
• It can be used to understand code. When you are thrown with code that you have
no clue about how it works you have several options to accomplish that task:
</p>
          <ol dir="ltr" style="MARGIN-RIGHT: 0px">
            <li>
Look at the source code directly. 
</li>
            <li>
Make some diagrams from the source code (for example, using View Class Diagram in
Visual Studio). 
</li>
            <li>
Use NDepend.</li>
          </ol>
          <p dir="ltr">
These methods are not exclusive, and probably you’ll use a combination of them to
understand how the code works. However, the abstraction level is higher when you use
NDepend is higher than when you use a Class Diagram (and a Class Diagram is a high
level view compared to raw source code).  I’d use NDepend to have a global vision
of the main assemblies, type most used, dependencies between namespaces, more complex
methods, etc. and then focus my attention in the most important parts of the application,
going to a lower level of detail.
</p>
          <p dir="ltr">
• It can be used in the refactoring process, to see the impact of a change, and
to keep dependencies to a minimum, in order to have a project that is easier to understand
and maintain.
</p>
          <p>
• Integrating NDepend in the software development process. IMHO this is a key
point, as using NDepend regulary will certainly improve the quality of the software
that is being developed.  NDepend can generate a report of a project. A sample
report is available here:
</p>
          <p>
            <a href="http://www.ndepend.com/SampleReports/OnNUnit/NDependReport.html">http://www.ndepend.com/SampleReports/OnNUnit/NDependReport.html</a>
          </p>
          <p>
There are a lot of sections in the report, but I’ll concentrate on the section called
“CQL Queries and Constraints”. That section is really important as it shows a list
of items that can be problematic or don’t follow the standards of your company (methods
with a lot of lines of code, very complex methods, poorly commented methods, types
or methods or properties or fields with incorrect naming conventions, etc). This way
the project leader can make periodic checks of those problems and report them to the
people that are responsible for them. 
<br />
This also allows you to know more the people you’re working with. Some developers
don’t comment code, others like to make very long methods, and others tend to write
complex logic that is difficult to understand by others. With the review of the report,
they can be instructed so the resulting code and comments is better and more uniform.
</p>
          <p>
However, there are times where a method with more than 30 lines of code is necessary.
Or a method with a cyclomatic complexity of 25 is needed. So it is up to the project
leader to review the suspicious method and inform the developers of the problem or
simply acknowledge that it is necessary. 
</p>
          <p>
Unfortunately, NDepend does not provide built in support for this level of detail
of project management. I have been told that in a future version it will provide hooks
so custom scenarios like the exposed above are fully supported.
</p>
        </blockquote>
        <p dir="ltr">
So, after what I have said about NDepend, you can be thinking, is it for me? Well,
that depends on a lot of factors. I know a lot of companies that have no interest
in achieving high quality products and that they only care about having a project
done as soon as possible. If the maintenance of that project is a nightmare, well,
that is another problem for another moment. However, there are some companies that
actually spend time and effort to produce excellent products, so they may be interested
in what NDepend can add for them.
</p>
        <p dir="ltr">
I have used NDepend in several projects that are widely used when learning about it,
and I found something curious:
</p>
        <p dir="ltr">
          <img src="http://www.manuelabadia.com/blog/content/binary/nhibernate_dependencies.png" border="0" />
        </p>
        <p dir="ltr">
The image shows that almost all of the NHibernate code has a big dependency cycle.
I wish them good luck making the transition to ASTs.
</p>
        <p dir="ltr">
          <em>To finish this post, I have to say that I have received a free professional version
of NDepend. This has not conditioned my post about it. If I think it was a useless
product I will not have posted about it.<br /></em>
        </p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=a073bf47-5324-4884-9e2f-730fb8d78f7b" />
      </body>
      <title>NDepend</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,a073bf47-5324-4884-9e2f-730fb8d78f7b.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,a073bf47-5324-4884-9e2f-730fb8d78f7b.aspx</link>
      <pubDate>Fri, 08 Feb 2008 12:22:13 GMT</pubDate>
      <description>&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
One of the tools I’m using is NDepend (&lt;a href="http://www.ndepend.com/"&gt;http://www.ndepend.com/&lt;/a&gt;).
It is a cool application that can be used for a lot of things, as will be detailed
later. 
&lt;/p&gt;
&lt;p&gt;
To use NDepend you have to feed it with a set of assemblies. After that, it will analyze
those assemblies and their reference assemblies. If the PDBs of the assemblies are
available it will use them so more data is analyzed, although the PDBs are not needed
for NDepend to work.
&lt;/p&gt;
&lt;p&gt;
After the analysis has been completed, NDepend looks like this:
&lt;/p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/ndepend1.png" border=0&gt; 
&lt;p&gt;
&lt;br&gt;
I have used version 1.1 of Spring.NET Framework (&lt;a href="http://www.springframework.net/"&gt;http://www.springframework.net/&lt;/a&gt;)
for the sample. As you can see the application has a beautiful GUI. I’ll talk a bit
about the main windows of the tool:
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
•&amp;nbsp;Metrics: this window gives a graphical high level view of the project. You
can see a lot of ellipses and some of them that are made of smaller ellipses. The
big ellipses are types of the project. If a big ellipse is made of several smaller
ellipses, those smaller ellipses are the methods of the type. The types of the same
namespace are distributed in the same rectangular region, separated by a small yellow
line. The assemblies are separated by a thicker yellow line. 
&lt;/p&gt;
&lt;p&gt;
By watching this window you can get an idea of which assemblies contain more code,
which types are big, which types have a lot of methods, etc. The window was in “Method
Level”. The available levels are Assembly, Namespace, Type, Method and Field.
&lt;/p&gt;
&lt;p&gt;
•&amp;nbsp;Class Browser: this is where the assemblies of the project and its referenced
assemblies are shown. You can expand the assembly up to the field level. While you
hover over an item in most windows, the Metrics window gets updated highlighting the
hovered item. 
&lt;/p&gt;
&lt;p&gt;
What it’s really cool about the Class Browser is that for the referenced assemblies,
only the namespaces, types, methods and other items that are used by the project are
shown.
&lt;/p&gt;
&lt;p&gt;
•&amp;nbsp;Info: When you hover over an item the information about it is displayed here,
with some metrics if applicable. There are a lot of metrics so it can take time to
interiorize them and judge their value appropriately.
&lt;/p&gt;
&lt;p&gt;
•&amp;nbsp;Dependencies: this window is a bit intimidating at first but like a lot of
things, with a bit of effort you can master it. The window displays very important
information of the dependencies in a matrix form. As in other windows, the detail
level is selectable, from the assembly level to the field level. 
&lt;/p&gt;
&lt;p&gt;
A cell can have 3 colors. Blue means that the associated item in the top header uses
the associated item in the left header. Green means that the associated item in the
left header is using the associated item in the top header. Black means a cyclic dependency.
The blue and green cells express the same dependency using opposite points of view. 
&lt;/p&gt;
&lt;p&gt;
You can see a diagram of the dependencies clicking on a cell. For example, if you
click in the cell corresponding to System.Web.Extensions and System.Web you get this:
&lt;/p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/BoxAndArrowGraph.PNG" border=0&gt; 
&lt;p&gt;
To read more about the theory of dependencies take a look here:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.theserverside.net/tt/articles/showarticle.tss?id=ControllingDependencies"&gt;ttp://www.theserverside.net/tt/articles/showarticle.tss?id=ControllingDependencies&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
•&amp;nbsp;CQL Queries: CQL stands for Code Query Language and it is a central piece of
NDepend. Being able to ask questions about the code is great. If you like using the
Analyzer window in Reflector you’ll love this. You can create new queries and modify
the existing ones.
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p dir=ltr&gt;
I have presented the main NDepend windows, but the main question is: what you can
do with NDepend?
&lt;/p&gt;
&lt;p dir=ltr&gt;
There are several uses that I can think of:
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p dir=ltr&gt;
•&amp;nbsp;It is an excellent tool to check differences between different builds of an
assembly. You can use it as a diff tool, as it will show in the Class Browser which
types, methods, etc have been added, removed or changed. This information is also
available for CQL Queries, with the power that it implies.
&lt;/p&gt;
&lt;p&gt;
•&amp;nbsp;It can be used to understand code. When you are thrown with code that you have
no clue about how it works you have several options to accomplish that task:
&lt;/p&gt;
&lt;ol dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;li&gt;
Look at the source code directly. 
&lt;li&gt;
Make some diagrams from the source code (for example, using View Class Diagram in
Visual Studio). 
&lt;li&gt;
Use NDepend.&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=ltr&gt;
These methods are not exclusive, and probably you’ll use a combination of them to
understand how the code works. However, the abstraction level is higher when you use
NDepend is higher than when you use a Class Diagram (and a Class Diagram is a high
level view compared to raw source code).&amp;nbsp; I’d use NDepend to have a global vision
of the main assemblies, type most used, dependencies between namespaces, more complex
methods, etc. and then focus my attention in the most important parts of the application,
going to a lower level of detail.
&lt;/p&gt;
&lt;p dir=ltr&gt;
•&amp;nbsp;It can be used in the refactoring process, to see the impact of a change, and
to keep dependencies to a minimum, in order to have a project that is easier to understand
and maintain.
&lt;/p&gt;
&lt;p&gt;
•&amp;nbsp;Integrating NDepend in the software development process. IMHO this is a key
point, as using NDepend regulary will certainly improve the quality of the software
that is being developed.&amp;nbsp; NDepend can generate a report of a project. A sample
report is available here:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.ndepend.com/SampleReports/OnNUnit/NDependReport.html"&gt;http://www.ndepend.com/SampleReports/OnNUnit/NDependReport.html&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
There are a lot of sections in the report, but I’ll concentrate on the section called
“CQL Queries and Constraints”. That section is really important as it shows a list
of items that can be problematic or don’t follow the standards of your company (methods
with a lot of lines of code, very complex methods, poorly commented methods, types
or methods or properties or fields with incorrect naming conventions, etc). This way
the project leader can make periodic checks of those problems and report them to the
people that are responsible for them. 
&lt;br&gt;
This also allows you to know more the people you’re working with. Some developers
don’t comment code, others like to make very long methods, and others tend to write
complex logic that is difficult to understand by others. With the review of the report,
they can be instructed so the resulting code and comments is better and more uniform.
&lt;/p&gt;
&lt;p&gt;
However, there are times where a method with more than 30 lines of code is necessary.
Or a method with a cyclomatic complexity of 25 is needed. So it is up to the project
leader to review the suspicious method and inform the developers of the problem or
simply acknowledge that it is necessary. 
&lt;/p&gt;
&lt;p&gt;
Unfortunately, NDepend does not provide built in support for this level of detail
of project management. I have been told that in a future version it will provide hooks
so custom scenarios like the exposed above are fully supported.
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p dir=ltr&gt;
So, after what I have said about NDepend, you can be thinking, is it for me? Well,
that depends on a lot of factors. I know a lot of companies that have no interest
in achieving high quality products and that they only care about having a project
done as soon as possible. If the maintenance of that project is a nightmare, well,
that is another problem for another moment. However, there are some companies that
actually spend time and effort to produce excellent products, so they may be interested
in what NDepend can add for them.
&lt;/p&gt;
&lt;p dir=ltr&gt;
I have used NDepend in several projects that are widely used when learning about it,
and I found something curious:
&lt;/p&gt;
&lt;p dir=ltr&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/nhibernate_dependencies.png" border=0&gt;
&lt;/p&gt;
&lt;p dir=ltr&gt;
The image shows that almost all of the NHibernate code has a big dependency cycle.
I wish them good luck making the transition to ASTs.
&lt;/p&gt;
&lt;p dir=ltr&gt;
&lt;em&gt;To finish this post, I have to say that I have received a free professional version
of NDepend. This has not conditioned my post about it. If I think it was a useless
product I will not have posted about it.&lt;br&gt;
&lt;/em&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=a073bf47-5324-4884-9e2f-730fb8d78f7b" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,a073bf47-5324-4884-9e2f-730fb8d78f7b.aspx</comments>
      <category>ASP.NET</category>
      <category>Microsoft .NET Framework</category>
      <category>NHibernate</category>
    </item>
  </channel>
</rss>