XmlSerializer未序列化非string类型字段及命名空间问题求助
嘿,这两个问题都是用Visual Studio添加服务引用后序列化时的常见坑,我来给你拆解清楚:
当你通过Visual Studio添加服务引用生成ResponseMsg类时,工具会针对WSDL里标记为minOccurs="0"的非string类型元素(比如CurBalance、AvlBalance这类double/int/long字段),自动生成对应的[字段名]Specified布尔属性(比如CurBalanceSpecified、LoadAmountSpecified)。
这是XmlSerializer的设计逻辑:对于可以省略的非引用类型字段(值类型不能为null),它需要通过这个Specified标记来判断是否要序列化该字段——只有当你把对应的布尔属性设为true时,这个非string字段才会被输出到XML中。
举个实际的例子,如果你只写了:
var response = new ResponseMsg(); response.CurBalance = 123.45; // 但没设置 response.CurBalanceSpecified = true;
那序列化的时候CurBalance就会被直接忽略。而string类型属于引用类型,默认可以为null,XmlSerializer会直接输出(哪怕是空值),所以不需要这个Specified标记,也就不会被遗漏。
这个属性来自生成的类默认绑定的临时命名空间,有几种简单的解决方法:
方法1:序列化时用XmlSerializerNamespaces指定空命名空间(推荐)
在调用序列化方法时,创建一个XmlSerializerNamespaces实例,添加空命名空间的映射,再传给序列化方法:
var serializer = new XmlSerializer(typeof(ResponseMsg)); var ns = new XmlSerializerNamespaces(); ns.Add("", ""); // 空前缀对应空命名空间 // 假设你用XmlWriter来序列化 using var writer = XmlWriter.Create("output.xml"); serializer.Serialize(writer, yourResponseMsgInstance, ns);
这样生成的XML元素就不会带有xmlns="http://tempuri.org/"属性了。
方法2:修改生成类的XmlTypeAttribute
找到自动生成的ResponseMsg类定义,把类上面的[XmlType(Namespace = "http://tempuri.org/")]改成[XmlType(Namespace = "")]。不过要注意:如果后续你更新服务引用,这个修改会被覆盖,所以适合不需要频繁更新服务的场景。
方法3:添加服务引用时自定义命名空间
在添加服务引用的对话框里,点击「高级」按钮,在弹出的设置窗口中,把「命名空间」改成空字符串(或者你自己需要的命名空间)。这样生成的类默认就不会绑定http://tempuri.org/,序列化出来的XML自然也不会有这个属性。
内容的提问来源于stack exchange,提问作者GordonS

