Eric Evans的Domain Driven Design一书描述了称为值对象的模式。值对象的一个重要特征是它是不可变的。
作为一个例子,我有一个值对象“Clinic”,必须有一个名字和一个id。为了使它成为一个值对象,我没有在name和id上提供setter。另外为了确保没有无效的实例,我在构造函数中使用name和id,并且不提供参数较少的构造函数。
公共类诊所 {
public Clinic(string name, string id)
{
Name = name;
Id = id;
}
public string Name{get; private set;}
public string Id{get; private set;}
}
问题是,当我尝试从WCF服务返回此对象时,我得到一个异常,即该对象没有参数较少的构造函数,并且属性没有公共setter。我想避免添加参数较少的构造函数和公共setter因为那时我的域模型模式需要折腾。我怎样才能解决这个问题呢?
此致 Unmesh
答案 0 :(得分:3)
我之前在序列化不可变类型时遇到了类似的问题,最后我决定实现ISerializable接口并使用SerializationInfo来存储&检索序列化/反序列化过程两端的私有变量:
http://theburningmonk.com/2010/04/net-tips-making-a-serializable-immutable-struct/
我刚刚使用相同的技术构建并运行测试应用程序,它似乎对我有用。因此,对于Clinic类的更改,您可以将其更改为:
[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);
}
}
这将解决您从WCF传回数据的问题。但从设计的角度来看,我同意Ladislav所说的内容,通常你会想要将你的域对象与纯粹用于消息传递的对象(DataTransferObjects)分开,在这种情况下,这是一个你可能如何接近它的例子:
// 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);
}
为了减轻从Clinic转换为ClinicDTO的痛苦,您可以在Clinic上添加方法来执行此操作或实现隐式/显式转换器。我在这里有一个如何做到这一点的例子: http://theburningmonk.com/2010/02/controlling-type-conversion-in-c/
希望这有帮助!
答案 1 :(得分:2)
问题是您的值对象不可序列化。您打算如何使用该服务?您是否计划与客户共享域对象/值对象?如果是,IMO违反了您的域驱动设计 - 只有业务层应该能够使用域对象并调用他们的方法。如果您不想共享对象,您可能会通过添加服务引用来创建代理,这将为客户端生成数据contrats。这些合同将具有公共无参数构造函数和所有可设置的属性(并且没有域方法)。
如果您想拥有真正的域驱动设计,则不应在WCF中公开您的域对象。相反,您应该创建一组DTO并公开这些DTO。服务层将负责将这些DTO转换为Domain对象/值对象,反之亦然。