WCF RIA Services and a guide to use DTO/”Presentation Model”

NOTE: Examples in this blog post is based on the VS 2010 Beta 2, WCF RIA Services PDC Beta, some changes to the WCF RIA Services can happen until RTM.

I have seen several questions and request about how to use Data Transfer Objects (DTO), or a ”Presentation Model” (Model created for presentation purpose) with WCF RIA Services. In this post I will write something about it.


Why use DTO/”Presentation Model”?

Why use DTO/”Presentation Model” at all? Well, domain entities aren’t design with presentation in mind; they are design to solve business problems. Because of that a domain entity is not created with presentation in mind and shouldn’t be passed to the View. If we do it, we will end up with a lot of logic in our view only to make sure our view will show the domain entities in the way we wants, and it can also ends up that we send more data than a view is needed. So with a DTO/”Presentation Model” we can create a new “model” with is designed with presentation in mind, and also will only contains the data the View needs.

My Windows to my logic

If we have a domain model in place or a simple n-tier architecture with a business logic layer and data access layer, we need to add a Service layer on top of them, and this layer is designed and created for our client in a Rich Internet Application only. The Service Layer will be our window to our logic. It’s the Service layer responsibility to communicate to our domain model or business logic, it also has the responsibility to only pass the data a client needs. This kind of data passed to the client is a DTO/”Presentation Model”. The Service layer knows about the domain model and also the DTO/”Presentation Model”. The domain model doesn’t know about the Service layer. The client/view or should I say “presentation layer” will only know about the existents of the Service layers and its services it will use, and also the DTO/”Presentation Model”, it will not know about the domain model.

image

 

 

The above figure shows how I often design my RIA. But and a big BUT, I select the design which is best suited for the application I’m building. If you take a look at the figure above, you can see that the “DTO/PM” is also known to the View, this is not always the case, which is why there is a box which will stop at the ViewModel. I have seen several articles and blog post where they say they use a ViewModel, but what they do is to pass the DTO directly to the View for rendering. Is that wrong? I will not say it is, instead say “It depends”. If our DTO/”Presentation Model” is well designed for a specific View, it is ok to pass it along through a ViewModel, but if it isn’t, it’s not ok. The ViewModel in this case is similar to Martin Fowlers Presentation Model pattern. Some developers still uses code-behind and no ViewModel, so in that case the View will use the DTO.

Note: In this post I will not use the ViewModel, I will just simply use code-behind to call the Service layer, this post is only about how we can use DTO/”Presentation Model” with WCF RIA Services. If you want to read more about RIA Architecture etc, you can check our the following blog post: http://weblogs.asp.net/fredriknormen/archive/2009/04/19/ria-architecture-with-silverlight-in-mind.aspx

Creating a Service Layer with WCF RIA Services using DTO/”Presentation Model”

Before creating the Service Layer, we will take a look at the Entity I have in my domain model.

image

The following is the View which should display the Customer:

 

image

 

As you can see the View and the Customer entity are very different. If we pass our Customer to the View, we need to add logic which will combine the FirstName and LastName property, and also add logic which will check the checkbox Is Adult, if Age >= 18 (In Sweden you are an adult it you are 18 years old ). The View is not interested in the Address, Phone property, so why pass it to the View? So what we can do is to create a DTO/”Presentation Model” for the View. We can add this model in a separate class library or to the Web projects which will host our Silverlight application. In a small application I often only create a folder in my Web project called “PresentationModel” and put my DTO/”Presentation Model” classes to that folder. The reason I do that is because the DTO/”Presentation Model” I will create is only for my Silverlight application, not for other clients. Here is my DTO/”Presentation Model”:

 

public partial class CustomerPM
    {
        [key]
        public int CustomerID { get; set; }

        public string FullName { get; set; }

        public int Age { get; set; }
    }


Note: I will make the DTO/”Presentation Model” partial, the reason I do that is to make it possible to use the WCR RIA Services .shared feature.

The DTO/”Presentation Model” should only pass the data the view is needed, nothing more. The CustomerID is marked with the KeyAttribute, and we must at least mark one property to be a identifier of the object. WCF RIA Service’s DomainContext has an Identity Map, and it will cache objects based on the specified key. The View will check a CheckBox if the Customer is an adult. We can pass the Age along to the View and use a ViewModel to add the logic to know if the Customer is and adult or not, but in this case we will not use a ViewModel (I do prefer a ViewModel), we instead turn the DTO into a “Presentation Model” instead. So we will use the .shared feature to add an IsAdult property. A DTO will not have any kind of logic, it will only be used to pass data over the wire, so if we add logic to a DTO, it will instead be something else, and in this case I will say it will be a “Presentation Model”, a model used to simply the presentation of an domain entity. Here is the .shared code for the CustomerPM:

CustomerPM.shared.cs:

    public partial class CustomerPM
    {
        public bool IsAdult
        {
            get { return this.Age >= 18; }
        }
    }

 

Now when the “Presentation Model” is created we need to create our Service Layer. The Service Layer in this case is the WCF RIA Services DomainSerivce, so here is the DomainService which will use the “Presentation Model”:

    [EnableClientAccess()]
    public class CustomerService : DomainService
    {
        private ICustomerRepository _customerRepository;


        public CustomerService()
        {
            _customerRepository = new CustomerRepository();
        }


        public CustomerService(ICustomerRepository customerRepository)
        {
            _customerRepository = customerRepository;
        }

        public CustomerPM GetCustomer(int customerID)
        {
            var customer = _customerRepository.GetCustomerByID(customerID)
            return new CustomerPM()
                   {
                      CustomerID = customer.CustomerID,
                      FullName = customer.FirstName + " " + customer.LastName,
                      Age = customer.Age
                   };
        }
    }


As you can see a WCF RIA Services query method can return a simple object, in this case the CustomerPM. The Query method will make a call to our domain model to get the Customer entity.

Note: In the current WCR RIA Services PDC beta for VS 2008, you can’t return a single entity, but it can be done in the VS 2010 version.

The CustomerRepository’s GetCustomerByID method can use Entity Framework, Linq To SQL, nHibernate or normal ADO.NET etc to fill a Customer entities with data from a data source.

By using Object Initializer we can simply map our domain entity to our “Presentation Model”. Normally I will do some refactoring here, and create a MapCustomerToCustomerPM method, which will handle the mapping. As you can see the CustomerService will take a ICustomerRepository as an argument to the constructor, this constructor can be used when we write unit test to test the DomainService. The default constructor will create a “real” instance of the CustomerRepository. Normally I would use a Dependency Injection framework, like Unity or StructueMap etc, can also use MEF (which is not a “pure” DI framework) to inject a ICustomerRepostiroy when the DomainService is created, to make that possible when using WCF RIA Services, we can for example create our own IDomainServiceFactory, I prefer my own IDomainServiceFactory instead, I will post a blog post about that later.

Now when our DomainService is in place we can now use it from our Silverlight application.

Calling our DomainService from Silverlight

WCF RIA Services will generate classes for us on the client-side, it will create a state-full context class for us (DomainContext), which will have Dirty tracking, Unit or Work and a Identity Map, we will use that class to load our entities into the context. The name of the DomainContext will be CustomerContext. WCR RIA Services will take the name of the DomainService when it creates the DomainContext, if the name has the suffix “Service”, it will rename it to “Context” on the client-side, if not it will keep the name of the DomainService. The following code will make an asynchronous call to our DomainService and get a specific customer and set the LayoutRoot’s DataContext to the CustomerPM and use data-bounding:

var customerContext = new CustomerContext();

            customerContext.Load<CustomerPM>(customerContext.GetCustomerByIDQuery(10),
                                            loadOperation =>
                                            {
                                                LayoutRoot.DataContext = loadOperation.Entities.First();
                                            }, null);

 

Here is the XAML:

<UserControl x:Class="SilverlightApplication1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
  <Grid x:Name="LayoutRoot">

        <StackPanel>
            
            <TextBox Text="{Binding FullName}"></TextBox>
            <CheckBox IsChecked="{Binding IsAdult}"></CheckBox>
            
        </StackPanel>
      
  </Grid>
</UserControl>
 

Summary

As you may notice in  this blog post, it’s quite easy to use DTP/”Presentation Model”, if we want to add validations to our DTO/”Presentation Model”, we can simply do that with annotation.

If you want to read more about DTO/”Presentation Model” you can take a look at the following posts:

http://weblogs.asp.net/fredriknormen/archive/2009/11/20/wcf-ria-services-and-dto-with-association.aspx

http://weblogs.asp.net/fredriknormen/archive/2009/11/20/wcf-ria-services-what-you-need-to-know-when-creating-dto-presentation-model.aspx

If you want to know when I have published a new blog post, you can follow me on twitter: http://www.twitter.com/fredrikn

4 Comments

  • Thanks! Most of the blog just tell you what WCF RIA Serives is capable of but didn't show you how you can apply them in real life!that is great. a more realistic sample! Hope to see more of your post!

  • I have been "playing" with RIA and SL for the last couple of months and using it with prism.Your use of a DTO is interesting as it is architecturally pure however unless i am missing something you lose the attribute based validation that is so handy.If one is using prism it is really a bad to include RIA classes outside of a data access provider but that is what all the examplesI have seen do.


  • @johnmcfet:


    You aren't loosing the validation attributes, just add them to the DTO's property:


    [Required]

    public string FirstName



    This post is about DTO not MVVM, I wrote about it and Prism is a MVVM framework.. so if you want to see how you can use DTO and MVVM together take a look at this post:



    http://weblogs.asp.net/fredriknormen/archive/2009/11/30/silverlight-4-mvvm-with-commanding-and-wcf-ria-services.aspx

  • The transfer-object pattern received a bad rap in light of POJO and POCO solutions. Transfer object, they argued, simply mask the odor of having to use types inextricably bound to the persistence engine (EJB 2.0 being the worst offenders). Some called transfer objects an anti-pattern. However, free-range data models are no panacea as Fredrick points out. It's not just heavy footprints, you also need to keep primary keys "private", as well as certain business logic. That is, you do not want that all the way up in the client. Sure, you might accomplish that with annotations, but having a separate model projection is more manageable, that is to say, transfer objects.

Comments have been disabled for this content.