WCF类型序列化异常:单独传参时RefDomain属性值全为null
WCF序列化问题排查与解决
问题现象
项目中存在RefDomain类型,当它作为WCF服务方法的直接参数时,服务端接收的对象所有属性均为null,无法正常反序列化;但当它作为RefEntity类型的属性嵌套传递时,却能正常完成序列化与反序列化。
RefDomain代码如下:
public class RefDomain { private string name; private RefDomain parent; private Type entityType; public string Name { get => this.name; protected set => this.name = value; } public RefDomain Parent { get => this.parent; protected set => this.parent = value; } public Type RefEntityType { get => this.entityType; protected set => this.entityType = value; } }
原因分析
- 序列化器访问权限限制:
RefDomain的属性setter为protected,WCF默认使用的DataContractSerializer在处理直接作为操作参数的类型时,若未显式标记序列化特性,无法通过反射访问protected setter完成反序列化赋值;而作为嵌套属性时,父类型的序列化上下文允许更宽松的反射访问,因此能正常赋值。 - 缺少序列化标记:
RefDomain未标记[DataContract]和[DataMember],也未标记[Serializable],当直接作为操作参数时,WCF无法明确识别需要序列化的成员,导致反序列化时无法填充属性值。 - 已知类型未配置:若
RefDomain未被添加到服务的已知类型集合中,WCF在处理直接参数时无法解析该类型,进而无法完成反序列化。
解决方法
方法1:添加DataContract与DataMember标记
显式标记类型和属性,让DataContractSerializer明确序列化成员,同时允许访问protected setter(添加IsReference = true解决Parent属性的循环引用问题):
[DataContract(IsReference = true)] public class RefDomain { private string name; private RefDomain parent; private Type entityType; [DataMember] public string Name { get => this.name; protected set => this.name = value; } [DataMember] public RefDomain Parent { get => this.parent; protected set => this.parent = value; } [DataMember] public Type RefEntityType { get => this.entityType; protected set => this.entityType = value; } }
方法2:将属性setter改为public
如果业务逻辑允许,将属性的setter改为public,让序列化器可直接赋值:
public class RefDomain { private string name; private RefDomain parent; private Type entityType; public string Name { get => this.name; set => this.name = value; } public RefDomain Parent { get => this.parent; set => this.parent = value; } public Type RefEntityType { get => this.entityType; set => this.entityType = value; } }
方法3:配置服务已知类型
在服务契约或服务实现类上添加[ServiceKnownType(typeof(RefDomain))],确保WCF能识别该类型:
[ServiceContract] [ServiceKnownType(typeof(RefDomain))] public interface IYourService { [OperationContract] void ProcessRefEntity(RefEntity entity); [OperationContract] void ProcessRefDomain(RefDomain domain); }
额外注意点
Type类型的序列化可能存在限制,若出现异常,可考虑传递Type.AssemblyQualifiedName字符串,在服务端再转换为Type对象。- 确保服务端与客户端的序列化器配置一致(均使用
DataContractSerializer或XmlSerializer)。
内容的提问来源于stack exchange,提问作者Santhosh Shanmugam
相关产品推荐
相关产品推荐

