After Thought

Archive for March 2010

Separation of concerns in Input Builders

with 2 comments

Note: We have moved on to use UIMaps as described in this blog post.

In our ASP.Net MVC application we want to separate the presentation code associated with HTML views from the act of binding data to HTML controls. We also want to get more of the UI control generation under test. This is our latest refinement towards those goals.

Html page for Address:

<div>
	<%= Model.Street
	.WithLabel("Street:")
	.Width("400px") %>
</div>
<div>
	<%= Model.City
	.WithLabel("City:") %>
</div>
<div>
	<%= Model.States
	.WithDefault("Select", "")
	.WithLabel("State:") %>
</div>
<div>
	<%= Model.ZipCode
	.WithLabel("Zip:")
	.Width("50px") %>-<%=
	Model.ZipPlus
	.Width("50px")%>
</div>

Here we only set css and other view related attributes. Now our HTML views are more concerned with how to display the data rather than what to display. Our model uses FluentWebControls to build the HTML inputs:

public class AddressInputProvider
{
	private readonly IRepository _repository;
	private Address _address;
	public AddressInputProvider(IRepository repository)
	{
		_repository = repository;
	}
	public void SetAddress(Address address)
	{
		_address = address;
	}
	public TextBoxData Street
	{
		get
		{
			return Fluent.TextBoxFor(_address, x => x.Street)
				.WithId((AddressModel address) => address.Street);
		}
	}
	public TextBoxData City
	{
		get
		{
			return Fluent.TextBoxFor(_address, x => x.City)
				.WithId((AddressModel address) => address.City);
		}
	}
	public DropDownListData States
	{
		get
		{
			return Fluent.DropDownListFor<State, AddressModel, string>(
				_repository.GetAll<State>(),
				state => state.Name,
				state => state.StateCode,
				x => x.State)
				.WithSelectedValue(() => _address.State);
		}
	}
	public TextBoxData ZipCode
	{
		get
		{
			return Fluent.TextBoxFor(_address, x => x.ZipCode)
				.WithId((AddressModel address) => address.ZipCode);
		}
	}

	public TextBoxData ZipPlus
	{
		get
		{
			return Fluent.TextBoxFor(_address, x => x.ZipPlus)
				.WithId((AddressModel address) => address.ZipPlus);
		}
	}
}

Now we can test the AddressInputBuilder, including the HTML control types and their properties in unit tests. We can eliminate mapping Domain objects to a Model before building the view. As FluentWebControls can bind against the model to get validation information, we only have to define the validation in one place – just in our Domain object or however we choose to do that. Other benefit is that it reduces our reliance on UI tests.

co-authored with Clinton Sheppard

Written by shashankshetty

March 5, 2010 at 4:56 pm

Posted in ASP.net MVC, C#, Uncategorized

Tagged with