Showing posts with label DTOs. Show all posts
Showing posts with label DTOs. Show all posts

Sunday, 12 December 2010

Turning DTOs into a domain layer

Following on from this blog: Do WCF Data Contracts have relevance outside of WCF where I talk about using WCF Data Contracts outside of service calls. This is part of a strategy for re-using DTOs for more than just a transport layer and building them for use across all layers.

Obviously you will instantly think about domain object behaviours, Object Oriented Design etc. In my experience you want to separate out the behaviour of a class in different layers. For example you will want to bind your View to a Model in the UI or use persistent objects in the Data layer, additionally you will want to have business behaviours in the domain layer. What if you could share the underlying shape of the data across all of these tiers.

In this article I will talk about reusing DTOs as a domain model. The obvious benefit is that you don't need to maintain 2 sets of objects and a mapping layer between them.

The main premise of this model is to have the DTO model representing the data shape of the domain object and adding behaviours through the use of extension methods to add this behaviour. For example you might have a Person DTO:


    [DataContract]
    public class Person
    {
        [DataMember(IsRequired=true)]
        public string Title { get; set; }

        [DataMember(IsRequired = true)]
        public string FirstName { get; set; }
       
        [DataMember(IsRequired = true)]
        public string LastName { get; set; }

        [DataMember(IsRequired = true)]
        public DateTime DateOfBirth { get; set; }

        [DataMember(IsRequired = true)]
        public Address Address { get; set; }

        [DataMember(IsRequired = true)]
        public PersonSex Sex { get; set; }

        [ContractInvariantMethod]
        private void EnforceInvariant()
        {
            Contract.Invariant(this.DateOfBirth < DateTime.Now);
            Contract.Invariant(!string.IsNullOrWhiteSpace(this.FirstName));
            Contract.Invariant(!string.IsNullOrWhiteSpace(this.LastName));
            Contract.Invariant(!string.IsNullOrWhiteSpace(this.LastName));
            Contract.Invariant(this.Address != null);

            Contract.Invariant(Enum.IsDefined(typeof(PersonSex), this.Sex));
        }
    }

Note that this uses the code contract model that I describe in Combing Code Contracts with DataContracts for better contract expressiveness and quality

To build a domain layer on top of this you can add a set of extension methods like this to add some business logic to the class:

    public static class PersonBusinessLayerExtensions
    {
        public static bool IsOver18(this Person person)
        {
            return (person.DateOfBirth <= DateTime.Now.AddYears(18));
        }

        public static bool LivesInUK(this Person person)
        {
            Contract.Requires(person.Address != null);

            return (string.Compare(person.Address.Country, "UK", StringComparison.OrdinalIgnoreCase) == 0);
        }

        public static bool CanVoteInUKElection(this Person person)
        {
            return (IsOver18(person) && LivesInUK(person));
        }
    }



You can see from this that we've added a bunch of methods which query some semantic value on top of the raw data, but you could easily add some modification of the state.

Remember that you can combine this with the Transaction Script pattern for longer business logic transactions spanning DTOs or other calls.

One of the elements that makes it powerful is that you can add polymorphic behaviour in different layers and protect the business logic from the presentation or database layers or change the behaviour. This is enforced by deploying the appropriate assembly in the layer.


    public static class PersonUIExtensions
    {
        public static string GetFullName(this Person person)
        {
            return string.Format(CultureInfo.InvariantCulture, "{0} {1} {2}", person.Title, person.FirstName, person.LastName);
        }
    }


A potential disadvantage with this model is polymorphism of behaviours through abstract and virtual methods on the domain classes. However this can still be simulated via inheritance of the DTOs and extension methods on the base classes with extended behaviours on derived classes. This will require different names, but that can be a good thing, as sometimes polymorphism can be abused by overloading the behaviours in ways which aren't described by the method name.

Your thoughts on this approach?

Sunday, 7 November 2010

Combing Code Contracts with DataContracts for better contract expressiveness and quality

I'm going to write some more about Code Contracts (http://research.microsoft.com/en-us/projects/contracts/) soon, but wanted to show you a neat example of using in combination with DataContracts.

This shows the power of CodeContracts in enforcing more semantic information about a DataContract than is currently expressible in WSDL or DataContracts.

For example take a look at this DataContract:

   [DataContract]
   public class Address
   {
       [DataMember(IsRequired=false)]
       public int? HouseNumber { get; set; }
       [DataMember(IsRequired = false)]
       public string HouseName { get; set; }
       [DataMember(IsRequired = true)]
       public string Street { get; set; }
       [DataMember(IsRequired = true)]
       public string City { get; set; }
       [DataMember(IsRequired = true)]
       public stringRegion { get; set; }
       [DataMember(IsRequired = true)]
       public string Country { get; set; }
       [DataMember(IsRequired = false)]
       public string PostCode { get; set; }
   }

Then we can see that there are several attributes which indicate that they are optional, for example the House Number and House Name. In the UK then many houses will have either one or the other or both. However no address should be missing both, the problem with this contract is that this isn't clear or enforceable.

If we enhance this DataContract with CodeContracts:

   [DataContract]
   public class Address
   {
       [DataMember(IsRequired=false)]
       public int? HouseNumber { get; set; }
       [DataMember(IsRequired = false)]
       public string HouseName { get; set; }
       [DataMember(IsRequired = true)]
       public string Street { get; set; }
       [DataMember(IsRequired = true)]
       public string City { get; set; }
       [DataMember(IsRequired = true)]
       public stringRegion { get; set; }
       [DataMember(IsRequired = true)]
       public string Country { get; set; }
       [DataMember(IsRequired = false)]
       public string PostCode { get; set; }
       [ContractInvariantMethod]
       private void EnforceInvariant()
       {
           Contract.Invariant(HouseNumber > 0);
           Contract.Invariant(!(HouseNumber == null && string.IsNullOrWhiteSpace(HouseName)));
           Contract.Invariant(!string.IsNullOrWhiteSpace(Street));
           Contract.Invariant(!string.IsNullOrWhiteSpace(City));
           Contract.Invariant(!string.IsNullOrWhiteSpace(Region));
           Contract.Invariant(!string.IsNullOrWhiteSpace(Country));
       }
   }

Here you can see I have added a method that is decorated with a ContractInvariantMethod attribute. When you run the code through the Code Contract post compiler then this will ensure that at each point that the class changes that these invariants remain true. I've also added some invariants that ensure that the values are not null, empty or whitespace strings and that the house number is greater than 0. This can be analysed with a static analysis tool, with PEX and CHESS tools for testing and runtime checks.

When I am working with WSDL produced from .NET WCF services then I like to get the DataContract assemblies so that these checks are possible. It is also better to go to the source rather than generating these from the WSDL - as long as the people that wrote the contracts have done the decent thing and put their DataContracts in a separate assembly to isolate it from the other layers and behaviours.

What do you think of this approach - do you think it enhances the data contract? Leave some comments below.

Friday, 1 October 2010

Do WCF Data Contracts have relevance outside of WCF

In working with WCF you will come across DataContract attributes which decorate DTOs. DataContracts are great because they allow you to specify the WCF contract and are much more flexible than the XML serializer used by the original web services in .NET in that you can specify the attributes on prvate fields so you don't need to break encapsulation. It also supports versioning, optional parameters and a much fuller XSD model

However, can we take this feature which appears to have been created for WCF and use it more generically?

My view and way that I use this is for any sort of data contracts between layers of an application, so between the UI and the business tier, between services, between service layers and even into serialized persistent stores (e.g. XML datatype in the database).

Why?

  • It is flexible in terms of versioning, optionality and data encapsulation
  • It is faster than Binary or XML Serialization (in my testing)
  • It creates compact, concise output
It seems Microsoft had this in mind when they created the class as it is placed in the System.Runtime.Serialization namespace.

So I would recommend that you use data contracts when passing data between any layer of an application and enforce that contract to ensure compatibility.

This relates to a number of upcoming articles, so stick with me while I evolve the story around DataContracts and how you might use them across the application from the data tier, to the UI and avoid writing lots of mappers between domain objects, DTOs and persistent entities.

Feel free to give your views on this, either positive or negative in the comments below