Just sharing some of my inconsequential lunch conversations with you... RSS  

Sunday, September 28, 2008

Finally I've got myself a MVC project!

Yes, is true, I finally got myself a real project willing to accept the ASP.NET MVC Preview 5. I'll save my impressions for a future post, for now I'm just interested on sharing my options.

My first thing I had to opt was how to express the model. I've opted by a strongly-typed approach. For the backoffice models I've decided to create the following classes:

    /// <summary>
/// Base class for data driven models.
/// </summary>
public abstract class BaseViewData
{
private readonly List<string> displayList = new List<string>();

/// <summary>
/// List of messages to display.
/// </summary>
public IList<string> DisplayList
{
get
{
return displayList;
}
}
}



This is the base class for all the models - for now it just hold the list of messages to display. Please note that this is the MVC model, not the domain model.



Let's move to the first implementation: ListViewData<T>. This class is a generic of domain model entity classes, and represents a simple listing view data:



    /// <summary>
/// Model view data for simple listing pages.
/// </summary>
/// <typeparam name="T">Domain model entity class.</typeparam>
public class ListViewData<T> : BaseViewData
{
/// <summary>
/// List of items of type T.
/// </summary>
public IList<T> Items { get; set; }
}



Not precisely rocket science, but if simplicity is important to software process in general, adn according to my readings, it seems to be critical for the success of MVC implementations. Armed with this simple classes, we can now do a simple change to the view code behind:



    public partial class List : ViewPage<Models.ListViewData<DomainModel.MyEntity>>
{
}



So we can now fire away our view and code something like:



    <%= Html.DisplayMessages(ViewData.Model.DisplayList)%>



DisplayMessages is a simple extension that implements... the messaging displaying itself...



Now for the grid. I've opted for the MVCContrib Grid implementation. Ok, not as cool as rendering the markup from scratch, but what can I say, I'm lazy.



    <%
Html.Grid<MyEntity>(
ViewData.Model.Items,
column => {
column.For(p => p.Name, "Name");
column.For(p => p.Description, "Description");
column.For(p => Html.ActionLink("Edit", "Edit", new { id = p.ID }), "Edit").DoNotEncode();
column.For(p => Html.ActionLink<MyEntity>(
c => c.Delete(p.ID),
"Delete",
new { onclick = "javascript:return confirm('Confirm operation?');" })
).DoNotEncode();
}
);
%>



The only radical option I had was not to use ASP.NET server-side controls (like repeaters, textboxes and others). If I understand correctly, though these controls can be use on MVC, they are not MVC-ecosystem friendly, as they are fat, not always XHTML compatible, don't guarantee support for accessibility and still depends on ViewState for some operations.



For editing the entity itself, I wrote an equivalent class, ViewData<T>:



    /// <summary>
/// Model view data for simple editing pages.
/// </summary>
/// <typeparam name="T"></typeparam>
public class ViewData<T> : BaseViewData where T : new()
{
private T item = new T();

/// <summary>
/// An item of T.
/// </summary>
public T Item
{
get
{
return item;
}

set
{
item = value;
}
}
}




Same with the view code behind:



    public partial class Edit : ViewPage<Models.ViewData<DomainModel.MyEntity>>
{
}




And with the view itself:



    <form action="<%= ViewData.Model.Item.ID != 0 ? Url.Action("Update", new {id = ViewData.Model.Item.ID}) : Url.Action("Insert") %>" method="post">
<table>
<tr>
<td>Name:</td>
<td><%= Html.TextBox("Name", ViewData.Model.Item.Name)%></td>
</tr>
<tr>
<td>Description:</td>
<td><%= Html.TextBox("Description", ViewData.Model.Item.Description)%></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="<%= ViewData.Model.Item.ID != 0 ? "Update" :" Insert" %>"/></td>
</tr>
</table>
</form>



Naturally not all models depend entirely on a sole Domain Entity. Some do depend on depending entities, like:



    <%
Html.Grid<YetAnotherEntity>(
ViewData.Model.Item.YetAnotherEntities,
column => {
column.For(p => p.Name, "Name");
}
);
%>



But for the rest of the scenarios, we should define a class for the model. Something like:



    public class MySpecialListViewData : ViewPage<Models.ListViewData<DomainModel.AnotherEntity>>
{
public bool ShowSomething { get; set; }
}

No comments:

Development Catharsis :: Copyright 2006 Mário Romano