Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Making ASP.NET databinding via # work, without reflection

0.00/5 (No votes)
10 Dec 2006 1  
Describes a way to design a custom type in a way, so ASP.NET data binding syntax (DataBinder) will work without using reflection.

Introduction

There is a nice underused feature in .NET framework / ASP.NET � the TypeDescriptors mechanism. The mechanism resides in the System.ComponentModel namespace, and is generally represented by the TypeDescriptor, CustomTypeDescriptor classes, a ICustomTypeDescriptor interface, and some other supporting classes. As we can see by using the brilliant Lutz Roeder�s Reflector, these classes are mostly used by some controls (including the brand new AJAX Toolkit) and DataGrids / DataBinder.

Shortly said, this class allow us to design a type, a datasource, that when bound to a .NET control, for example, via the convenient <%# %> ASP.NET syntax, does not lead to reflection calls. This is done by providing property information dynamically, at runtime. Here�s a quick how to, with a real world scenario.

Details

In our project, we had some legacy code that returned data in some form of object[][] (actually, jagged array) which contained some metadata (columns, length, availability of next data pages, etc.). We needed to easily bind it in ASPX pages. That quickly led us to ugly things like <%# ((object[])DataItem)[3][4]%>, or something like that.

What I wanted to do was to have a custom class containing tabular data (columns and values for each row) + some custom metadata. I also wanted that class to be bindable the same way as a DataTable does, i.e.: <%# Eval(�ColumnName�) %>.

First of all, I thought that designing a simple class with an indexed property would be enough, but that led us to: <%# Eval(�[ColumnName]�) %>. Without unneeded brackets that didn�t work. That was an �OK� solution, but I was still curios: if a DataTable can do that type of thing, I should be able to do it too.

So, again, I took the reflector and went to the DataBinder class where I quickly found the following code (the GetPropertyValue method):

PropertyDescriptor descriptor1 = 
       TypeDescriptor.GetProperties(container).Find(propName, true);

//omitted check for clarity

return descriptor1.GetValue(container);

Woa! That�s not just the easy reflection way, as I always thought. Actually, as further investigation revealed, TypeDecriptor when not provided with an implementation of the ICustomTypeDescriptor interface just reverts to the plain old reflection way. So, the other part was easy -> read MSDN, see how DataTable implements ICustomTypeDescriptor, and write my own implementation for it:

//�Row� class

public class DataRetriverResultRow: CustomTypeDescriptor
{
  // Parent �DataTable� class

  private DataRetriverResultSet proxy;

  // other code omited

  public override PropertyDescriptorCollection GetProperties()
  {
   return proxy.GetPropertyDescriptorCollection(null);
  }
}

In the �DataTable� class, it's the place where actual property information is created (because all "DataTable" rows have the same properties - one for each column):

internal PropertyDescriptorCollection 
        GetPropertyDescriptorCollection(Attribute[] attributes)
  {
   if (this.propertyDescriptorCollectionCache == null)
   {
    int colCount = this.columns.Length;
    PropertyDescriptor[] descriptors = new PropertyDescriptor[colCount];
    for (int i = 0; i < colCount; i++)
    {
     descriptors[i] = new DataRetriverResultRowPropertyDescriptor(i, 
                                                   this.columns[i]);
    }
    this.propertyDescriptorCollectionCache = 
           new PropertyDescriptorCollection(descriptors);
   }
   return this.propertyDescriptorCollectionCache;
  }

And finally, the PropertyDescriptor (which is the class that actually describes a property and knows how to get a value from it). Treat it as a custom variant of the PropertyInfo class:

private class DataRetriverResultRowPropertyDescriptor : PropertyDescriptor
{
       int columnIndex; 
    
       public DataRetriverResultRowPropertyDescriptor(int index, 
                                                      string name)
        : base(name, null)
       {
        this.columnIndex = index;
       }
    
       // some dummy code implementing PropertyDescriptor ommited

    
       public override Type ComponentType
       {
        get { return typeof(DataRetriverResultRow); }
       }
    
        // component � is the object containing

        // the property, wich we are describing.  

	// So we can safely cast it and use it�s method to retrieve 

        // a value without any reflection.

       public override object GetValue(object component)
       {
           return ((DataRetriverResultRow)
                    component).GetValue(columnIndex);
       }

}

And that�s all. Basically, we just created some kind of meta descriptor which generates property info at runtime, using dynamic data (in this case, the number and order of columns in the parent �data table�).

Now, when DataBinder.Eval gets the data row of our object, it operates with a custom created and cached PropertyDescriptorCollection and uses our GetValue method, instead of PropertyInfo.GetValue. That's definitely a perfomance bonus. Also, we get a nifty syntax of databinding without a bit odd ["here goes a column name"].

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here