views:

52

answers:

2

Hello,

The book Domain Driven Design by Eric Evans describes pattern called value object. One of the important characteristics of a value object is that it is immutable.

As an example I have a value object "Clinic" which must have a name and an id. To make it a value object I do not provide setters on name and id. Also to make sure that there is not invalid instance I take name and id in a constructor and do not provide at parameter less constructor.

public class Clinic {

public Clinic(string name, string id)
{
    Name = name;
    Id = id;  
}

public string Name{get; private set;}
public string Id{get; private set;}

}

The problem is that when I try to return this object from a WCF Service I get an exception that the object does not have parameter less constructor and the properties do not have public setters. I want to avoid adding parameter less constructor and public setters because then my domain model pattern goes for a toss. How can I get around this problem?

Regards, Unmesh

A: 

The problem is that your value object is not serializable. How do you plan to use the service? Do you plan to share domain objects / value objects with your clients? If yes than it IMO violates your domain driven desing - only business layer should be able to work with domain objects and call their methods. If you don't want to share objects you will probably create proxy by add service reference which will generate data contrats for the client. These contrats will have public parameterless constructor and all properties settable (and no domain methods).

If you want to have real Domain driven design you should not expose your domain objects in WCF. Instead you should create set of DTO and expose those DTOs. Service layer will be responsible of converting those DTOs to Domain objects / value objects and vice-versa.

Ladislav Mrnka
Hello, I have a Repository of the value objects. The repository lets the client side code work as if it is dealing with a collection but actually stores and retrieves data from a remote database via a WCF service. The service is not exposed to external clients. Is it still not correct design?
Unmesh Kondolikar
Does it mean that domain layer is client of WCF service? If your repository of value objects is on client end of WCF you can use another object in WCF and convert it to value type inside repository.
Ladislav Mrnka
Yes .. we have a thick client and my domain is on client. But I agree, instead of tweaking the serialization process, I can use DTO behind the repository to save and retrieve the objects. After all my service is also outside my domain model required just to fetch\store data.
Unmesh Kondolikar
A: 

I had a similar problem with serializing immutable types before, in the end I decided to implement the ISerializable interface and use the SerializationInfo to store & retrieve the private variables at both ends of the serialization/deserialization process:

http://theburningmonk.com/2010/04/net-tips-making-a-serializable-immutable-struct/

I just built and run a test app using the same technique and it seems to work for me. So in terms of changes to your Clinic class you could change it to:

[Serializable]
public class Clinic : ISerializable
{
public Clinic(string name, string id)
{
    Name = name;
    Id = id;  
}

public Clinic(SerializationInfo info, StreamingContext context)
{
    Name= info.GetString("Name");
    Id= info.GetString("Id");
}

public string Name{get; private set;}
public string Id{get; private set;}

[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
    info.AddValue("Name", Name);
    info.AddValue("Id", Id);
}
}

This will solve the problem you're having passing the data back from WCF. But from a design point of view, I agree with what Ladislav is saying and typically you will want to separate your domain objects with objects purely intended for message passing (DataTransferObjects), and in that case here's an example of how you MIGHT approach it:

// the domain object (NOT EXPOSED through the WCF service)
public class Clinic
{
public Clinic(string name, string id)
{
    Name = name;
    Id = id;  
}

public string Name{ get; private set;}
public string Id{ get; private set;}

// other methods encapsulating some business logic, etc.
...
}
// the corresponding DTO object for the domain object Clinic
// this is the type exposed through the WCF layer, that the client knows about
[DataContract]
public class ClinicDTO
{
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public string Id { get; set; }
}
// WCF service contract, NOTE it returns ClinicDTO instead of Clinic
[ServiceContract]
public interface IClinicService
{
   [OperationContract]
   ClinicDTO GetClinicById(string id);
}

To ease the pain of converting from Clinic to ClinicDTO, you could either add a method on Clinic to do this or implement an implicit/explicit converter. I've got an example on how to do this here: http://theburningmonk.com/2010/02/controlling-type-conversion-in-c/

Hope this helps!

theburningmonk
Thank you, it helps a lot :P .. and you have a nice blog.
Unmesh Kondolikar
Thank you ;-) and glad to be of help!
theburningmonk