2010-08-23 1 views
3

Le livre Domain Driven Design d'Eric Evans décrit le modèle appelé objet valeur. Une des caractéristiques importantes d'un objet de valeur est qu'il est immuable.Sérialisation WCF et modèle d'objet Value dans la conception par domaine

A titre d'exemple, j'ai un objet de valeur "Clinic" qui doit avoir un nom et un id. Pour en faire un objet de valeur, je ne fournis pas de setters sur le nom et l'identifiant. Aussi pour m'assurer qu'il n'y a pas d'instance invalide je prends name et id dans un constructeur et ne fournis pas de paramètre less constructor.

public class Clinique {

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

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

}

Le problème est que lorsque je tente de retourner cet objet à partir d'un service WCF-je obtenir une exception que l'objet n'a pas le paramètre moins constructeur et les propriétés n'ont pas de setters publics. Je veux éviter d'ajouter des paramètres constructeurs moins et public, car alors mon modèle de modèle de domaine va pour un tirage au sort. Comment puis-je contourner ce problème?

Cordialement, Unmesh

Répondre

3

J'ai eu un problème similaire avec sérialisation types immuables avant, à la fin j'ai décidé de mettre en œuvre l'interface ISerializable et utiliser SerializationInfo pour stocker & récupérer les variables privées aux deux extrémités du processus de sérialisation/désérialisation:

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

Je viens de créer et d'exécuter une application de test en utilisant la même technique et cela semble fonctionner pour moi. Donc, en termes de changements à votre classe clinique, vous pouvez changer à:

[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); 
} 
} 

Cela permettra de résoudre le problème que vous rencontrez passer les données à partir WCF. Mais d'un point de vue design, je suis d'accord avec ce que dit Ladislav et vous voudrez généralement séparer vos objets de domaine avec des objets purement destinés au passage de messages (DataTransferObjects), et dans ce cas voici un exemple de la façon dont vous pourriez l'aborder:

// 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); 
} 

pour soulager la douleur de conversion de la clinique à ClinicDTO, vous pouvez soit ajouter une méthode à la clinique pour faire ceci ou mettre en œuvre un convertisseur implicite/explicite. J'ai un exemple sur la façon de le faire ici: http://theburningmonk.com/2010/02/controlling-type-conversion-in-c/

Espérons que cela aide!

+0

Merci, ça aide beaucoup: P .. et vous avez un joli blog. –

+0

Merci ;-) et heureux de vous aider! – theburningmonk

2

Le problème est que votre objet de valeur n'est pas sérialisable. Comment prévoyez-vous d'utiliser le service? Avez-vous l'intention de partager des objets de domaine/objets de valeur avec vos clients? Si oui que l'IMO ne viole pas votre domaine de desing - seule la couche de gestion devrait être capable de travailler avec des objets de domaine et d'appeler leurs méthodes. Si vous ne voulez pas partager d'objets, vous créerez probablement un proxy en ajoutant une référence de service qui générera des contrats de données pour le client. Ces contrats auront un constructeur public sans paramètre et toutes les propriétés paramétrables (et aucune méthode de domaine).

Si vous voulez avoir une véritable conception orientée domaine, vous ne devez pas exposer vos objets de domaine dans WCF. Au lieu de cela, vous devez créer un ensemble de DTO et exposer ces DTO. La couche de service sera responsable de la conversion de ces DTO en objets de domaine/objets de valeur et vice-versa.

+0

Bonjour, j'ai un dépôt des objets de valeur. Le référentiel permet au code côté client de fonctionner comme s'il s'agissait d'une collection, mais stocke et récupère les données d'une base de données distante via un service WCF. Le service n'est pas exposé à des clients externes. Est-il toujours pas de conception correcte? –

+0

Cela signifie-t-il que la couche de domaine est client du service WCF? Si votre référentiel d'objets de valeur se trouve à la fin du WCF client, vous pouvez utiliser un autre objet dans WCF et le convertir en type de valeur dans le référentiel. –

+0

Oui .. nous avons un client lourd et mon domaine est sur le client. Mais je suis d'accord, au lieu de peaufiner le processus de sérialisation, je peux utiliser DTO derrière le dépôt pour sauvegarder et récupérer les objets. Après tout mon service est également en dehors de mon modèle de domaine requis juste pour extraire \ stocker des données. –

Questions connexes