使用VS生成的WCF客户端调用WebService遇XmlInclude/SoapInclude报错
嘿,这个问题我之前帮同事解决过好几次!VS自动生成的WCF客户端有时候确实会犯这种“认不出子类”的毛病,本质就是XmlSerializer是静态类型序列化器,需要提前明确知道所有可能被序列化的派生类型,而自动生成的代码漏掉了相关声明。给你几个实用的解决办法:
方法一:用部分类添加XmlInclude属性(推荐,不怕更新服务引用)
VS生成的客户端类都是partial(部分类),这意味着我们可以单独新建一个代码文件来附加属性,完全不用碰自动生成的Reference.cs(不然更新服务引用时修改会被覆盖)。
假设QueryTypeCriteria是某个基类(比如BaseCriteria)的派生类,你只需要新建一个代码文件,写入以下内容:
using System.Xml.Serialization; // 这里的命名空间必须和自动生成的基类完全一致 namespace YourGeneratedClientNamespace { [XmlInclude(typeof(QueryTypeCriteria))] public partial class BaseCriteria { // 不需要写任何额外代码,只是用来附加XmlInclude属性 } }
这样XmlSerializer就能识别到这个派生类型了,而且以后更新服务引用也不会丢失这个修改。
方法二:临时修改自动生成的客户端代码(不推荐长期用)
如果你只是临时测试,不想新建文件,可以直接找到自动生成的Reference.cs,找到对应的基类(或被序列化的父类型),手动加上[XmlInclude(typeof(QueryTypeCriteria))]或者[SoapInclude(typeof(QueryTypeCriteria))]属性:
[XmlInclude(typeof(QueryTypeCriteria))] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.3752.0")] [System.SerializableAttribute()] [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://your-service-namespace")] public partial class BaseCriteria { ... }
⚠️ 注意:每次更新服务引用时,这个修改都会被VS覆盖,所以除非你确定不会再更新服务,否则别用这个方法。
方法三:生成客户端时指定包含的类型
如果是用svcutil命令行生成客户端,可以通过/reference参数指定包含QueryTypeCriteria类型的程序集,工具会自动帮你添加XmlInclude声明。命令示例:
svcutil http://your-service-url/Service.svc /out:GeneratedClient.cs /r:YourAssemblyWithQueryTypeCriteria.dll
如果是用VS的“添加服务引用”,可以在高级选项里检查是否有相关设置,不过命令行的方式通常更灵活。
方法四:切换到DataContractSerializer(如果服务端支持)
有些WCF服务默认使用DataContractSerializer,它的类型处理更灵活,基本不会出现这种“类型未知”的问题。你可以在添加服务引用时,点击“高级”按钮,把“序列化程序”改成“DataContract序列化程序”,重新生成客户端试试。不过前提是服务端也是用DataContract定义契约的,不然可能会有兼容性问题。
内容的提问来源于stack exchange,提问作者felixmondelo

