Marcin On ASP.NET

Keeping my eye on the dot

December, 2007

Posts
  • Marcin On ASP.NET

    Adding custom metadata providers in ASP.NET 3.5 Extensions Preview

    • 12 Comments

    5/22/08 Note: this post talks about an outdated ASP.NET release. Please have a look at this updated dynamic metadata provider sample.

    One of the most powerful elements of the new ASP.NET Dynamic Data feature we are working on is the ability to associate metadata (for example, range validation or formatting) with your data model. You can then query the model and use the provided information to customize the processing of your data. In the recently released ASP.NET 3.5 Extensions Preview this annotation is done by declaring special metadata attributes on the partial classes representing the entities in the model. The initial implementation is a bit limited, however, because the metadata association can only be done using CLR attributes and those attributes have to be declared on the class (even if they pertain to the class's properties):

    [Range("Quantity", 0, 10000)] 
    [Range("Price", 0, 20000)]
    partial class Product {
    }

    A better approach

    The MVC Toolkit (which incorporates a number of modifications to the Preview that will be included in later milestones – download here) contains an alternative implementation. This implementation has the following improvements:

    • A pluggable metadata model based on providers.
    • New metadata attributes that can be declared on the properties of a special metadata "buddy" class.
    • An alternative reference provider implementation based on XML files.

    The best way to familiarize yourself with the new model is to look at the samples included with the MVC toolkit. However, here are a few points to get you started:

    1. The registration of a metadata handler is done on a DataContext type using the MetadataHandlerRegistration class. This needs to be done only once per application, for example in the Global.asax file:
      protected void Application_Start(object sender, EventArgs e) {
          MetadataHandlerRegistration.Register(
      typeof(MyDataContext),
      MetadataHandlerRegistration.XmlMetadataProvider); }
      Note: Only Linq to SQL models are supported in this version. Future releases will support both Linq to SQL and ADO.NET Entities.
    2. MetadataHandlerRegistration contains references to 2 different metadata providers: buddy class-based and XML file-based.

    Buddy class metadata

    Buddy class metadata is a model in which you associate a "buddy class" with your actual data model class and declare the metadata attributes on properties of the buddy class. "Why do I need to declare a parallel class?", you ask. The simple answer is that the current versions of C# and VB have no concept of partial properties.

    This implementation supports two ways of associating the buddy class:

    1. Explicit: using an attribute on the model partial class that points to the type of the buddy class
    2. Implicit: using a name matching pattern (append "_Metadata" to the name of the model class and look for a class with that new name in the current namespace/assembly)

    Using the explicit option looks like this:

    [MetadataClass(typeof(Product_Metadata))]
    partial class Product {
    }
    
    public class Product_Metadata {
        [Range(0, 10000)]
        public int Quantity { get; set; }
    }

    Comment out the MetadataClass attribute and you get the implicit option.

    XML file metadata

    An alternative metadata provider uses an XML file as the metadata store. Currently the file location is hard-coded to be ~/metadata.xml. A very basic metadata.xml file could look like this (a slightly bigger one is included in the sample blog project of the MVC Toolkit):

    <metadata xmlns="http://tempuri.org/metadataFile"
        xmlns:m="http://tempuri.org/metadataElements"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://tempuri.org/metadataFile ../Schemas/MetadataFile.xsd
    http://tempuri.org/metadataElements ../Schemas/MetadataElements.xsd"> <metadataAttributes> <metadataAttribute tagPrefix="m" assembly="MVCToolkit" namespace="Microsoft.Web.DynamicData.Metadata"/> </metadataAttributes> <tables> <table name="Product"> <columns> <column name="Quantity"> <m:Range Minimum="0" Maximum="100000"/> </column> </columns> </table> </tables> </metadata>

    The metadataAttributes section defines metadata attribute mappings. These are used by the logic that creates a CLR attribute type instance from an XML element. For example, the m:Range element will be converted into the class Microsoft.Web.DynamicData.Metadata.RangeAttribute in the MVCToolkit assembly. The attributes on the element are automatically converted and set on the properties of the attribute type instance. You can add your own metadata attribute collection by defining a new metadataAttribute entry.

    The tables section allows you to define metadata on all of the tables and their columns that make up your model.

    As a final note, most of the attributes on the root metadata element are there to support IntelliSense in your XML editor. The relative URLs work in the sample Dynamic Data MVC blog project. You might have to change some of the paths if you decide to move the XSD files around or if you create a new project in a different location.

    Implementation details

    The underlying implementation uses the TypeDescriptor mechanism from System.ComponentModel. It is basically a pluggable layer on top of standard reflection. Have a look at the code to learn more.

    Conclusion

    This post discusses elements that will be incorporated in some way or another in future releases of ASP.NET Extensions. However, some of the implementation details might change. We will certainly have detailed documentation for the final release.

    In the meantime feel free to explore the provided code and make sure you give back any feedback you might have on how these features can be improved. You can post your comments/questions at:

    ASP.NET 3.5 Extensions Preview discussion
    ASP.NET Dynamic Data discussion

    Additional resources

    Visit these blogs for additional tips on ASP.NET 3.5 Extensions and Dynamic Data:

    David Ebbo's ASP.NET blog
    Scott Hunter: ASP.NET and .NET Musings

  • Marcin On ASP.NET

    Dynamic Data December preview context caching bug fix

    • 2 Comments

    Users of our recently released December preview of the new Dynamic Data feature in ASP.NET have noticed a pretty serious bug relating to foreign key column drop-downs. While this could be a breaking issue for many trying to test or adopt the new feature, I am glad to report that there is a workaround available.

    This post talks about what the bug is and what steps are needed to resolve it. I am also attaching a zip file that you can simply unzip in the root of your Dynamic Data project (warning: this could overwrite customizations you have made to the project files. Read on to see what files are affected).

    You can download the updated versions of the affected controls here (3 KB).

    Bug symptoms

    The bug affects the drop-down lists for foreign key relation columns as well foreign key filters. The problem occurs when you insert a new item into the parent table, then go to the child table and try to add a new entry, edit an existing one, or filter the table using the entry you added in the parent column. The drop-down list does not contain the newly added item and only restarting the entire app makes it appear (an analogous thing will happen if you remove an entry from the parent table).

    This bug occurs because the Dynamic Data framework is trying to cache an instance of the DataContext object that represent the data model. The DataContext instance is something that should be instantiated, used to retrieve/submit information to the database, and then discard it. Dynamic Data holds on to it a bit longer than it should.

    The solution

    You can download the file mentioned at the beginning of this post to get the updated versions of the affected files. Simply unzip into the root of your Dynamic Data project. The included files are in C# but they should work even if your project is in VB.

    The solution to the problem basically requires providing a new instance of the DataContext object to the controls responsible for rendering the drop-downs. This means you need to modify ForeignKey_Edit.ascx and FilterUserControl.ascx (both living in App_Shared\DynamicDataFields\ directory in the Dynamic Data project templates).

    • ForeignKey_Edit.ascx

      In the Page_Load method, replace the following line of code

      DropDownList1.DataSource = parentTable.Query;
      

      with this

      DropDownList1.DataSource = parentTable.DataContextProperty.GetValue(Activator.CreateInstance(DynamicDatabase.TheDatabase.CreateDataContext().GetType()), null);
    • FilterUserControl.ascx

      In the Page_Init method, replace the following line of code

      DropDownList1.DataSource = DataSource;

      with this

      var foreignKeyColumn = DynamicDatabase.TheDatabase.GetMetaTable(this.TableName).FindColumn(this.DataField) as DynamicMetaForeignKeyMember;
      if (foreignKeyColumn != null) {
          // only kick in if we are dealing with a foreign key column
          DropDownList1.DataSource = foreignKeyColumn.ParentMetaTable.DataContextProperty.GetValue(Activator.CreateInstance(DynamicDatabase.TheDatabase.CreateDataContext().GetType()), null);
      }
      else {
          DropDownList1.DataSource = DataSource;
      }

    The new code is a bit ugly but it should work. Upcoming versions of Dynamic Data will not have this problem.

  • Marcin On ASP.NET

    Dynamic Data screencast is available

    • 0 Comments

    David Ebbo has just posted a screencast covering the Dynamic Data feature in ASP.NET 3.5 Extensions Preview. It is 17 minutes long and covers the following topics:

    • Creating a Dynamic Data project
    • Creating a Linq to SQL model
    • Running the scaffolded version of a Dynamic Data project
    • Customizing data validation
    • Customizing UI presentation
    • Adding metadata to the model
    • Writing custom pages in place of the scaffolded ones

    Check out David's post.

  • Marcin On ASP.NET

    ASP.NET 3.5 Extensions Preview is available

    • 0 Comments

    The ASP.NET 3.5 Extensions Preview is out. Get it here.

    This includes:

    • MVC
    • Dynamic Data
    • AJAX browser history
    • Silverlight controls
    • REST based data services
    Have a look at this post by Brad Abrams for more details.
  • Marcin On ASP.NET

    Introduction

    • 0 Comments

    Hi everybody (and by everybody I mean the single person who accidentally stumbled upon these pages). My name is Marcin Dobosz and I am a developer on the ASP.NET team. I recently graduated from Duke University with a degree in Computer Science and for the last 3-4 months have been working on the new Dynamic Data feature of ASP.NET.

    In this blog I will write about my work and whatever else strikes my fancy, Enjoy.

Page 1 of 1 (5 items)