我有两个课程如下:
[DataContract]
public class Address
{
[DataMember]
public string Line1
[DataMember]
public string Line2
[DataMember]
public string City
[DataMember]
public string State
[DataMember]
public string Zip
}
[DataContract]
public class Customer
{
public Customer()
{
CustomerAddress = new Address();
}
[DataMember]
public string FirstName
[DataMember]
public string LastName
[DataMember]
public Address CustomerAddress
}
如果我生成使用Customer类的服务代理,会发生什么?如果我正确理解了这个概念,那么我认为Customer类中的构造函数不会在客户端被调用,它可能会给出不同的行为。
如何摆脱Customer类中的构造函数,并且仍然具有CustomerAddress
类型的Address
属性,以使其表现为一个愚蠢的DTO对象?
人们用来避免这种情况的一般准则或最佳做法是什么?
答案 0 :(得分:6)
如果您使用默认的DataContractSerializer
来序列化您的对象,那么,是的,您的构造函数未被序列化,并且当反序列化对象时,您的客户端将不会调用您可能拥有的任何逻辑。 / p>
关于删除构造函数逻辑并填充嵌套Address
类的问题,DataContractSerializer
将对此进行处理。如果我有这样的代码:
Customer c = new Customer() {
FirstName = "David",
LastName = "Hoerster",
CustomerAddress = new Address() {
Line1 = "1 Main Street",
City = "Smallville",
State = "AA",
Zip = "12345"
}
};
然后从服务方法返回,Customer
对象将与Address
信息一起正确序列化。生成的客户端上的代理将知道Address
,并且能够反序列化来自服务方法的流以正确构建您的Customer
对象。你的Customer
将是一个虚拟DTO - 没有逻辑,只有属性。
在WCF序列化中查看Aaron Skonnard的MSDN article,在那里他谈到了DataContractSerializer。
答案 1 :(得分:1)
如果你生成客户端(使用svcutil或“添加服务引用”),那么生成的DataContract将如下所示:
[DataContract]
public class Customer
{
// empty default constructor
public Customer()
{
}
[DataMember]
public string FirstName
[DataMember]
public string LastName
[DataMember]
public Address CustomerAddress
}
您的实施细节不会结转。所有生成的都是WSDL中的内容,在这种情况下只是[DataMember]
属性。
我之所以提到这一点是因为您的原始问题是:“如果我生成代理将会发生什么。”
如果这是从服务器发送到客户端的对象,那么您可以在将CustomerAddress发送到客户端之前始终初始化它。事实上,如果您的原始代码在服务器上,那么将运行该构造函数,并且WCF将序列化CustomerAddress
并且基本上从不发送null(除非您在构造函数之后将其设置回null)。
如果您想让客户端始终向您发送CustomerAddress
,那么您可以:
if(x.CustomerAddress == null) x.CustomerAddress = new Address();
[DataMember(IsRequired=true)] public Address CustomerAddress;
否则,我认为没有办法强制生成的WCF客户端为您初始化该字段。
答案 2 :(得分:0)
您最好定义程序集中的所有数据协定类,并将服务器项目和客户端项目引用到程序集,以便可以共享初始化行为。生成服务引用时,可以指示代码生成器使用现有的数据协定类。