What do you think about using a presentation model for presenting your domain model?

 

I’m writing a small app for a demonstration purpose. What I have is a domain model where I have a Customer, I also have CustomerRepository.

public class Customer
{   public int ID { get; set; }

       public string CompanyName { get; set; }

       public string FirstName { get; set; }

       public string Lastname { get; set; }
}
public interface ICustomerRepository
{
       IList<Customer> GetCustomers();

       Customer GetCustomerByID(int ID);

       void Remove(Customer customer);

       void Update(Customer customer);

       void Add(Customer customer);
}

I decided to not make the Customer immutable and use the new automatic property feature to speed up the creation of the Customer entity. My CustomerRepository have some few method. About the Get methods, should they have the name GetCustomerByID, or GetByID or only Get!? The name of the class indicates that it's a customer I want, do I need to repeat my self and add the word Customer to the method name? The argument of the GetCustomerByID method indicates that I need an ID, so the method could be Get(int ID). But of some reason I feel more comfortable to name it GetCustomerByID, because the method should get a Customer based on a given ID. What do you think, how should you have named that method and why, please feel free to add a comment. This was out of the topic of this blog post, but I'm very interested in how you should have named it.

I use ASP.Net to build my client. What I was needed was a model for the presentation, I call it Presentation Model. A Presentation Model is a model used for presentation purpose only. For example if I want to bind a Customer entity to a Grid and one column should display the FullName of a Customer, it's not sure that every country want to display the FirstName first. I didn't want to add the logic of how a FullName should be displayed into the code-behind of my page or on the .aspx page. Instead I created a Presentation class for my Customer which has a FullName property.

public class PresentationCustomer : MyApp.DomainLayer.Entities.Customer
{
    public PresentationCustomer()
    {
    }


    public string Fullname
    {
        get { return base.FirstName + " " + base.Lastname; }
    }
}

I still wanted to have the same members as the Customer entity so I inherited the Customer class and added a Fullname property to my new Presenstion model. I didn't know what I should named the Presentation class of the Customer, so I used what it is, a presentation of the Customer (PresentationCustomer). In this example I do not have logic to display the FirstName and LastName in a specific order. I often use a Presentation Model in my app, for example say that I have a checkbox, this should be selected or note based on the domain entities state. Instead of adding a condition statement to my code-behind, I use a presentation class with a property which return true or false based on condition, for example let say I have a Customer and I wanted to mark a checkbox if the Customer is and adult or not. The only information my Customer entity has is Age. So instead of adding the code into the code-behind or .aspx page, I created a Presentation class of the Customer and added a IsAdult property, which I bound to a checkbox.

public bool IsAdult
{
    get { return (this.Age > 18) }
}

This will of course require me to write several of new classes, but by using a Presentation Model I can easy reuse my client even if my underlying data source is changed, just map the new data to my Presentaion Model, so the data could for example be simple XML documents. It's still the Presentation Model my Views will work against and not directly to my domain model. As you may know if we use a ObjectDataSource and bind an object to it, only the fields which are bounded to the Grid will be updated and passed down to the Update method. In that case we can't map our ObjectDataSource directly to a Repository. Well we can hook up to the Updating event and get the original customer and make sure the unbound field will be filled with the original value instead of getting the null value. But use a another solution to reduce the code in the code-behind, I use a "Controller", and each View can have it's own "Controller" which can handle View specific problems. So I can add a Update method to my "Controller" which will be used by a ObjectDataSource, this method can then help me solve the null problem with unbound fields.

When I use a Presentation Model, I need a way to easy map my Customer to a PresentationCustomer, this can for example be done by using constructor injection, where I inject the Customer entity into the PresentationCustomer's constructor.

public class PresentationCustomer
{
    Customer _customer;

    public PresentationCustomer(Customer customer)
    {
        this._customer = customer;
    }

    public string Fullname
    {
        get { return this._customer.FirstName + " " + this._customer.Lastname; }
    }
}

In this case if I want to use the Customer entity's members, I need to add all of them again to the PresentationCustomer class. This is something that I didn't wanted to do. I wanted to reuse as much code as possible. So I decided to inherit the Customer class instead and do a manual mapping by using code. I could have used a object to object mapping tool, but that may require me to setup the mapping, and the time to do that is the same time to write the mapping by code.

To make sure my Views work against my Presentation Model, I created a new class which should also have the responsibility to handle the flow and state of my Views. I'm so bad at naming things, but I used the name CustomerController. This class has several method to handle navigation after a new customer is added or updated etc. Two methods that I have is ViewCustomer and GetCustomers. The ViewCustomer method's responsibility is to display a Customer, the GetCustomers should be used by a ObjectDataSource control to fill a Grid with Customers, those method should return and use a PresentationCustomer and not the Customer entity. To do that I need to map all Customer into PresentationCustomer. I did that by using the new object initializer feature of C# 3.0.

private PresentationCustomer MappCustomerToPresentationCustomer(Customer customer)
{
     return new PresentationCustomer()
     {
        ID = customer.ID,
        FirstName = customer.FirstName,
        Lastname = customer.Lastname,
        CompanyName = customer.CompanyName
     };
}

The ViewCustomer and GetCustomers in the CustomerController now use this method, the implementation of the methods look like this:

public void ViewCustomer(int? ID)
{
    if (!ID.HasValue)
        throw new ApplicationException(Resources.Resource.CustomerIDCantBeNullArgumentValidation);

    var customer = this._customerRepository.GetCustomerByID(ID.Value);

    if (customer == null)
        throw new ApplicationException(string.Format(Resources.Resource.CantFintCustomerByIDErrorMsg, ID));

    var presentationCustomer = this.MappCustomerToPresentationCustomer(customer);

    base.AddPageState("Customer", presentationCustomer);
    base.MoveToView("CustomerDetails.aspx");
}

public IList<PresentationCustomer> GetCustomers()
{
    var customers = this._customerRepository.GetCustomers() as List<Customer>;

    var presentationCustomers = new List<PresentationCustomer>();

    customers.ForEach(c => presentationCustomers.Add(this.MappCustomerToPresentationCustomer(c)));

    return presentationCustomers;
}

My question is how should you have done it? Is there a way you think is much easier and faster way to implement it, do you like this approached with a Presentation Model or is there anything that you think is much better? Please feel free to add a comment, I would like to hear about your thoughts and suggestions etc.

3 Comments

  • I had chosen this way of creating my PresentationCustomer.

    With this way, I win two things, I don't have to map my PresentationCustomer back to an Customer.
    I can easy implement IEditable just Cloneing my inner Customer and change my inner customer if the user chooses to Cancel the updates :).

    public class PresentationCustomer
    {
    Customer _customer;

    public PresentationCustomer(Customer customer)
    {
    this._customer = customer;
    }

    public string Fullname
    {
    get { return this._customer.FirstName + " " + this._customer.Lastname; }
    }
    }

  • You can name your Get methods as GetCustomerBy(int Id).

  • I don't like to pass the Customer as a constructor parameter to the PresentationCustomer. That's because i often have the presentation-model and the domain model in different assemblies. I don't want to have a reference from the presentation-model to the domain-model.
    I see presentationCustomer as a customized DTO-object (transfer data to the client). I have used reflection to copy values from presentation model to domain model and vice versa (I know it isn't fast...)

Comments have been disabled for this content.