dinsdag 12 mei 2009
maandag 11 mei 2009
Moving…
Bear with me for a bit, moving to a subtext powered blog while trying to keep my history intact.
Isolating the domain model from your view
When working with the ASP.NET MVC framework I have a strong urge to not pass my domain models directly to the view (and I feel that’s a good thing). Actually, I should refine that. I do not pass my domain models to the view as a domain class. Let’s investigate.
My model at the moment consists of a class called Contact. It’s very simple:
public class Contact
{
public int Id { get; set; }
public string LastName { get; set; }
}
This class is populated with data from my datasource (a static List<Contact> for now), and later on it’ll be used in my domain logic. For now it’s a simple data class. Now, for a view which is used to edit this entity, the first idea is to go with a strongly typed viewdata, like such:
<%@ Page Title=""
Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="ViewPage<Contact>" %>
Basically I’m passing the domain model directly into the view. Not really a good thing in my opinion, because I’m exposing waaay too much of the model to the view. I only need a few simple getters, and perhaps some combined getters (in case of a person, one which appends first/lastname for instance). The solution I use for this is to wrap the domain model in a viewdata class, without exposing the actual model itself.
public class ViewContact
{
private readonly Contact contact;
public ViewContact(Contact contact)
{
this.contact = contact;
}
public int Id { get { return contact.Id; } }
public string DisplayName
{
get { return contact.LastName; }
}
}
As you can see, the actual model is passed in as a parameter to the constructor, but I’m not exposing it directly. What I can do now is pass this object to the view, without exposing the model:
<%@
Page Title=""
Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="ViewPage<ViewContact>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Editing: [<%= Model.Id %>] <%= Model.DisplayName %></h2>
<% using (Html.BeginForm("Update", "Contact")){ %>
…
…
<% } %>
</asp:Content>
Now I’ve got a simple way to isolate my domain model from my view, by using a wrapper class. This way I can explicitly specify what I want to be able to use in my views, without having to conform my domain model to that. I can have a rich domain model, while still limiting the amount of information I get in my view. I’m not sure how this will work out, so I’ll probably follow up on this blog with new insights, or perhaps a complete abandoning of the pattern later ;-)
donderdag 7 mei 2009
Taking a step back
So I recently started a personal project with a friend/developer, to try out serious development with ASP.NET MVC. Inspired by Rob Conery’s MVC Storefront/Kona series, we want to try out setting up all parts of a proper environment (automated builds, continuous integration, version control, the works basically). Learning by doing, more or less.
So far, we’ve only just started. We assessed that we want to build an application for record keeping, contact records to be precise, as we’re both interested in keeping our client relations in check. Our first ‘milestone’ is to create a system to insert, delete update and do reports on contact records. We’re working without a database at the moment, using mock repositories for testing purposes. Ok, enough about the background.
I wanted to create a listview, which worked with a set of contacts. Simple, no? Here’s where it went wrong. As you might know, the ASP.NET MVC default solution provides us with a very simple setup. A folder for your models, folder for controllers, folder for views. Let’s look at the views for a moment.
The view structure is set up as follows:
- ControllerX
- ControllerY
- Shared
Each attempt to render a view checks the folder named after the controller for a view with the specified name. If it’s not found, it defaults to the one in the highlighted ‘Shared’ folder. My problem here was that I was anticipating for future expansions right from the start. The WRONG assumption, looking back at it. I tried to create a list view, which would work on any object I’d throw in it. Or actually, in the view model. I have to take a step back.
So, while I started on a very complex solution, I actually decided to go for a view which would probably not live for very long. I will modify it in a later stadium to actually be generic over multiple classes I toss at it. Why don’t I do that now? Because I don’t have to. This is one major insight I had so far over the course of the project, which is actually only a few days old. Seems like it’s paying off already!