WCF抽象类继承对象返回时序列化错误求助
首先来说你遇到的序列化错误——这是WCF里非常常见的问题,因为DataContractSerializer是静态类型感知的,它默认不知道你会返回License的哪个子类实例,必须明确告诉它哪些类型是“已知的”才能正常序列化。
一、修复序列化错误的核心方案
方法1:直接标注已知类型(适合子类数量固定的场景)
给你的抽象类License添加KnownTypeAttribute,把所有继承它的子类都列进去,让序列化器提前知晓这些类型:
[DataContract] [KnownType(typeof(LicenseMay2018))] [KnownType(typeof(LicenseApril2018))] public abstract class License { [DataMember] public int ManagedObjectCount { get; set; } }
这样修改后,DataContractSerializer在处理返回值时,就能识别并序列化LicenseMay2018或LicenseApril2018的实例了。
方法2:动态获取已知类型(适合子类动态新增或数量较多的场景)
如果后续会频繁新增License子类,或者子类是动态加载的,可以用KnownType的动态方法形式,通过反射自动获取所有继承License的类型:
[DataContract] [KnownType("GetKnownLicenseTypes")] public abstract class License { [DataMember] public int ManagedObjectCount { get; set; } private static IEnumerable<Type> GetKnownLicenseTypes() { // 反射获取当前程序集中所有继承License的非抽象类 return typeof(License).Assembly.GetTypes() .Where(t => t.IsSubclassOf(typeof(License)) && !t.IsAbstract); } }
这种方式不用每次加新子类都修改抽象类的属性,灵活性更高。
额外注意点
要确保BE端和FE端的License类及其子类命名空间完全一致,WCF是通过“命名空间+类型名”来识别数据契约的,命名空间不匹配也会导致序列化失败。
二、关于两个URL的来源解释
- http://tempuri.org/:这是WCF服务契约的默认命名空间。当你创建WCF服务时,如果没有在
ServiceContractAttribute里显式指定命名空间,WCF就会自动使用这个默认值。你可以通过修改服务契约的属性自定义它,比如:[ServiceContract(Namespace = "http://yourcompany.com/services")]。 - http://schemas.datacontract.org/2004/07/:这是
DataContract的默认命名空间前缀,后面拼接的是你的类的实际命名空间(比如NMS.Frontend.DataTypes)。DataContractSerializer会自动把类的命名空间转换成这种URL格式,用来唯一标识数据契约。你也可以通过DataContractAttribute的Namespace属性自定义,比如:[DataContract(Namespace = "http://yourcompany.com/license/types")]。
错误信息回顾
你遇到的错误本质就是序列化器未识别到LicenseMay2018这个子类类型,按照上面的方法添加已知类型后,问题就能解决:
There was an error while trying to serialize parameter http://tempuri.org/:ActivateLicenseResult. The InnerException message was 'Type 'NMS.Frontend.DataTypes.LicenseMay2018' with data contract name 'LicenseMay2018:http://schemas.datacontract.org/2004/07/NMS.Frontend.DataTypes' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.'. Please see InnerException for more details.
内容的提问来源于stack exchange,提问作者Azzurro94




