Wednesday, January 21, 2009

Extending Asp.Net Dynamic Data

I recently had a requirement to quickly expose a database table via a web-page to allow some editing of data. Ah-ha I thought, lets see if we can get something for free. Being a .Net kind of bloke I decided the new Dynamic Data framework which ships with .Net 3.5 SP1 would be perfect.

Part of my requirement was not to allow inserts / deletes to the tables. Only updates. Pretty simple because you have access to the aspx / ascx templates and can literally remove the buttons / links and change the data sources to not allow inserts / deletes just for added protection to hand-crafted http posts.

You can create partials of the classes generated by Linq-Sql and attach attributes like MetadataType, or DisplayName to change the name of the table in the generated pages, or switch off columns from the dynamic scaffolding. You can also change columns in the linq-sql model to make them read-only. Nice :o) All is good in the world!

Not so fast though! The next requirement of course was to expose a table which absolutely must be inserted / deleted into. Damn! There didn't appear to be an in-built way to allow insert / delete for some tables but not others (not that I could see). But the answer was simple (so if there is an in-built way I don't have much code to change!!) and here's how I did it.

The template pages all have a MetaTable instance injected into it which amongst other things exposes an Attributes collection. These attributes are the Attributes from the table-model class, in my case the MetadataType / DisplayName attributes. So all you have to do is create another attribute, slap it on the partial classes, and pick it up from MetaTable.Attributes. In my case I created an attribute with two boolean properties, CanInsert and CanDelete. I also added an extension method to the MetaTable class, again CanInsert and CanDelete. The extension methods runs a quick query over the attributes to see if the attribute is there, and if so what the boolean value is. It looks something like this:

public static class MetaTableExtensions
  public static bool CanInsert(this MetaTable table)
    var attribute = table.Attributes.OfType<TableExtensionAttribute>().FirstOrDefault();
    if (attribute == null)
      return false;
    return attribute.CanInsert;

The template pages can now easily look for this attribute in for example the OnRowDataBound event of lists, and make a decision on whether or not to show a Delete button / Insert link.

Simple but effective.

No comments: