I love the UI, I love the UI, I love...

Well, no. It's all great that you have a nice Domain Object. Grant you, it's now populated with an ugly Id attribute which it slugs around because someone, somewhere decided that it was important enough to save the information into a database and databases need a primary key to find stuff. The problem is when I have to show a list to pick from, one of which is what the user selected previously. My Domain Object has this attribute:

Name: Author; Value: 21

And there's a collection of Roles to pick from:

Name: Reader; Id: 10
Name: Author; Id: 21
Name: Administrator; Id: 321

So I have a simple LookupDTO I use in my UI and Service Layer that looks like this:

class LookupDTO
{
  string Name;
  int Id;
}

It's generic (all lookups follow the same pattern). Problem is that if you have a collection of Roles you can't just bind it to a DropDownList like this:

// this returns an array of LookupDTO objects from the service layer
uiName.DataSource = RoleService.FindListForProject(projectId);
uiName.DataTextField = "Name";
uiName.DataValueField = "Id";
uiName.DataBind();

Because the values are 10, 21, and 321 and you can't set uiName.SelectedIndex = 21 or else ASP.NET blows it's head up with a boundary problem (it's 0-based). Ugly. I hate the fact that my Domain Object says that it's Id is 21 (because that's the database id that was created when it got saved) but ASP.NET needs a 0 or 1 to let a user pick from. So do I need a mapper for my mapper? And then there's going back that you have to do another mapping. So maybe there's a UI component that has both the "real" value and the UI value? I don't know.

I'm almost thinking that I should use a Guid in the database, but autoincrement is so nice and easy. A Guid would have it's advantage (other than driving my dba nuts) because I can pregenerate it in my Domain when a real object is created so I don't have to do fancy stuff in my SQL to get the ID that was just created. A common problem with using autoincrement in SQL is that you don't get it before the INSERT call. It's unique. I still think I'll have a problem in my UI layer because setting the HTML for a selected item in a dropdown list doesn't like "A04759E3-509C-42c6-BE27-20562B2BA6CA" as a selected value.

I know there's a better solution out there to map "real" values to ASP.NET UI controls like dropdown lists that don't like indices that don't match the 0 based counting that HTML creates. There's a good blog by Steve Eichert here on Hooking your Domain Model to the UI. I think we need a good UI Mapper tool/pattern/something to make this a no-brainer.

There's also a very nice add-in from Manuel Abadia over at CodeProject. It provides two way data binding in ASP.NET and looks pretty simple. You just hook up your collection to the fields on your webpage (through a designer) to set the databindings to your DTOs and call BindToWebForm (or BindFromWebForm). It turns this:

// populate the webform with the customer data
lName.Text = cus.Name;
lSurname.Text = cus.Surname;
lEmail.Text = cus.Email;
lAddress.Text = cus.Address;
lAge.Text = cus.Age.ToString();

// get the customer data from the webform
cus.Name = lName.Text;
cus.Surname = lSurname.Text;
cus.Email = lEmail.Text;
cus.Address = lAddress.Text;
cus.Age = Int32.Parse(lAge.Text);

Into this:

// populate the webform with the customer data
bindingManager1.BindToWebForm(this);

// get the customer data from the webform
bindingManager1.BindFromWebForm(this);

You can check out here. I need to find some time to look at it because this is nuts (or else I'm so out of it I'm missing the obvious). Maybe I haven't had enough coffee to think correctly. Friends don't let friends blog drunk (or semi-awake) might be a more appropriate title for this entry.

4 Comments

  • Hi,

    I don't quite understand. I thought the Ddl takes a text and value field. When the user selects a row in the Ddl, you get the value field from the row which is at the selected index, parse it to an int and you've got your dbId of 21 or whatever - the selectedIndex wouldn't be 21...

    Have I missed your difficulty ?

    Cheers

    i/Noodle

  • I think the problem here (besides being the thing between the keyboard and chair) is selecting the right choice coming back from the Domain to the UI.

  • Yeah, my UI controls tend to have their own 'model' too, so it ends up going from:

    domainModel -> uiModel at the simplest, or often (especially with service interfaces / DTOs) domainModel -> DTO -> uiModel. It would certainly be nice to be able to metaDataMap a domainModel directly to a UI control, and have the DTO automatically created if going via service interface. Having said that, its pretty much what is provided with datasets / databinding....

    *ramble ramble* ;)

    i/Noodle

  • I think I found the pattern here:



    control.SelectedIndex = control.Items.IndexOf(control.Items.FindByValue(dto.PublicProperty.Id.ToString()));



    Messy, but works.

Comments have been disabled for this content.