June 2009 Entries

A few weeks ago, I blogged about building an alternative to Dynamic Data.  I have to say, it’s pretty sweet.  I added a new entity type yesterday, including a couple of minor overrides and I was done.

Here are the steps I had to take (testing left out for clarity):

  • Create the entity:
  •    1: public class ExcludedCounterparty : IAuditedWithId
       2: {
       3:     public virtual int Id { get; set; }
       4:     public virtual Counterparty Counterparty {get; set;}
       5:     public virtual string CreatedByUser { get; set; }
       6:     public virtual DateTime? CreatedOnDate { get; set; }
       7:     public virtual string ModifiedByUser { get; set; }
       8:     public virtual DateTime? ModifiedOnDate { get; set; }
       9: }
  • Override the Fluent NHibernate conventions:
  •    1: public void Override( AutoMap<ExcludedCounterparty> mapping )
       2: {
       3:     mapping.References( ec => ec.Counterparty, "FK_CounterpartyId" );
       4: }
  • Override the UI conventions:
  •    1: public override void Override()
       2: {
       3:     Config.AllowEdit = false;
       4:     Config.AllowDelete = true;
       5:     Field( ec => ec.ModifiedByUser ).ShouldDisplay = false;
       6:     Field( ec => ec.ModifiedOnDate ).ShouldDisplay = false;
       7: }
  • Add the menu configuration
  •    1: <siteMapNode url="~/../ManageEntities.aspx?type=ExcludedCounterparty" title="Counterparty Exclusions" roles="…"></siteMapNode>
  • Update security
  • Done.

Notice that nowhere did I say that I had to create a aspx page or ascx control.  How sweet is that!  Also, both Fluent and my UI automation automatically pick up the new entity based on the assembly configuration.  It’s days like this that makes software development fun.

A couple of weeks ago I was searching for an alternative to Dynamic Data.  My motivation was simple.  Integrating Dynamic Data with Oracle and/or NHibernate would be challenging.  I was amazed at how little I could find that would solve this problem.  Surely Dynamic Data wasn’t the first or only.  Eventually, I gave up and worked with a coworker to develop our own alternative.

Fresh off a Fluent Nhibernate implementation, we decided to take the convention-over-configuration approach.  The Fluent interface worked very well for us, in particular the auto-mapping feature.  This is what we wanted to accomplish with our UI automation.

Configuration Points:
First we had to identify the configuration points.  Things like, label or header text, visibility, formatting, editor, among others.  We introduced two basic configuration objects, one for the entity and one for the fields (properties).  Our goal was to have a simple CRUD user interface that would be completed automated by reading information from these configuration objects.  Everything from subtitles, to actions, to data grids would be automated.

Conventions:
To avoid wasting time configuring individual entity classes, we decided to “auto-map” our UI.  We started off with simple conventions.  For example, deriving the subtitle from the class name.  The subtitle for “BookStore” would be “Book Stores” by convention.  We handled the singular case as well to support our actions, like “Add Book Store” or “Edit Book Store”.  Also, fields would follow a similar convention for labels and headers.

Eventually as our needs grew, we defined more conventions.  The nice thing about this approach is that we are following the Open/Closed Principle.  If we need something new, we simply add another convention.

 

Overrides:
Clearly, there will be exceptions to these conventions.  We took another page out of the Fluent Nhibernate book and implemented an Override model.  We simple allow implementations of IOverride<T> that provide an opportunity to change the auto-mapping behavior.   For example, IOverride<Party> might include “config.PluralLabel = "Parties"”.  When the automation service is initialized, we register the assembly containing our overrides.

 

Consumption:
We created a few automation aware web controls that bring our entities to life.  Really all we needed was a custom grid view and data entry table.  Presenting the data in the grid view was really quite simple since grid views already support simple data binding.  Data entry turned out to be not so difficult as well, we simply kept track of a list of properties and values.  Then it was a matter of getting values from the entities with reflection, and later setting those values before persisting the entity. 

Of course, the fact that we are using Nhibernate with methods like Save<T>( object ) helped with generic CRUD a lot.

 

Cost Effectiveness:
Many will question, “Why reinvent the wheel?”  Others will ask, “Have you really saved that much development time by building this framework?” 

First, I felt that Dynamic Data would not meet our needs and I searched long and hard for an alternative to Dynamic Data and couldn’t find one.  So, I don’t feel like I am reinventing the wheel here.  Perhaps there are Nhibernate integrations now available for Dynamic Data, but there weren’t at the time.  Also, even if there were, being an infant, Dynamic Data would likely have problems that would take too long to resolve.  With our in house solution, we built only what we need.  And with the tests in place, we feel confident that we can make a change quickly if necessary.

Second, we already experienced productivity gains more than once since adding the UI automation.  After defining a new entity, a simple one line override, and a menu item we were able to perform all CRUD on that entity because of the automation both on the UI side and the data side.  We didn’t have to write a single additional line of ASP.Net code.  In fact, my coworker wrote a prototype that takes an existing Java application (not web) and port it to our web interface.  He basically plugged in the new web application to a Java web service and the rest was cake.  When my boss saw the prototype, he about fell out of his chair.

Tags: ,