Bob*_*son 2 c# serialization soap xml-serialization xmlserializer
我正在尝试为一项规格确实不足的服务实现一个客户端。它类似于 SOAP,尽管它没有 WSDL 或等效文件。该规范也没有提供有关元素正确排序的任何信息 - 它们在规范中按字母顺序列出,但如果它们在请求中的顺序不正确,则服务会返回 XML 解析错误(所述顺序由检查示例)。
我可以用它来提交请求,即使这很痛苦。但是,我不知道如何正确处理响应。
使用两者SoapEnvelope和直接使用XmlSerializer,如果响应包含我尚未正确订购的元素,它会显示null在我的对象上。再次,我可以设法处理这个问题,并使用 attribute 手动排序类属性,Order但我无法判断原始 XML 是否有一个我没有正确排序并因此保留为 的字段null。
这引出了当前的问题: 如何检查 XmlSerializer 是否删除了字段?
您可以使用XmlSerializer.UnknownElementon 事件XmlSerializer来捕获无序元素。这将允许您手动查找并修复反序列化中的问题。
更复杂的答案是在序列化时正确排序元素,但在反序列化时忽略顺序。这需要使用XmlAttributes类和XmlSerializer(Type,\xe2\x80\x82XmlAttributeOverrides)构造函数。请注意,以这种方式构建的序列化器必须缓存在哈希表中并重新使用,以避免严重的内存泄漏,因此这个解决方案有点“挑剔”,因为 Microsoft 没有提供有意义的GetHashCode()for XmlAttributeOverrides. 以下是一种可能的实现,它取决于提前了解需要忽略其属性XmlElementAttribute.Order和XmlArrayAttribute.Order属性的所有类型,从而避免需要创建复杂的自定义哈希方法:
// /sf/ask/2345469591/\npublic class XmlSerializerFactory : XmlOrderFreeSerializerFactory\n{\n static readonly XmlSerializerFactory instance;\n\n // Use a static constructor for lazy initialization.\n private XmlSerializerFactory()\n : base(new[] { typeof(Type2), typeof(Type1), typeof(TestClass), typeof(Type3) }) // These are the types in your client for which Order needs to be ignored whend deserializing\n {\n }\n\n static XmlSerializerFactory()\n {\n instance = new XmlSerializerFactory();\n }\n\n public static XmlSerializerFactory Instance { get { return instance; } }\n}\n\npublic abstract class XmlOrderFreeSerializerFactory\n{\n readonly XmlAttributeOverrides overrides;\n readonly object locker = new object();\n readonly Dictionary<Type, XmlSerializer> serializers = new Dictionary<Type, XmlSerializer>();\n\n static void AddOverrideAttributes(Type type, XmlAttributeOverrides overrides)\n {\n if (type == null || type == typeof(object) || type.IsPrimitive || type == typeof(string))\n return;\n\n var mask = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public;\n foreach (var member in type.GetProperties(mask).Cast<MemberInfo>().Union(type.GetFields(mask)))\n {\n XmlAttributes overrideAttr = null;\n foreach (var attr in member.GetCustomAttributes<XmlElementAttribute>())\n {\n overrideAttr = overrideAttr ?? new XmlAttributes();\n overrideAttr.XmlElements.Add(new XmlElementAttribute { DataType = attr.DataType, ElementName = attr.ElementName, Form = attr.Form, IsNullable = attr.IsNullable, Namespace = attr.Namespace, Type = attr.Type });\n }\n foreach (var attr in member.GetCustomAttributes<XmlArrayAttribute>())\n {\n overrideAttr = overrideAttr ?? new XmlAttributes();\n overrideAttr.XmlArray = new XmlArrayAttribute { ElementName = attr.ElementName, Form = attr.Form, IsNullable = attr.IsNullable, Namespace = attr.Namespace };\n }\n foreach (var attr in member.GetCustomAttributes<XmlArrayItemAttribute>())\n {\n overrideAttr = overrideAttr ?? new XmlAttributes();\n overrideAttr.XmlArrayItems.Add(attr);\n }\n foreach (var attr in member.GetCustomAttributes<XmlAnyElementAttribute>())\n {\n overrideAttr = overrideAttr ?? new XmlAttributes();\n overrideAttr.XmlAnyElements.Add(new XmlAnyElementAttribute { Name = attr.Name, Namespace = attr.Namespace });\n }\n if (overrideAttr != null)\n overrides.Add(type, member.Name, overrideAttr);\n }\n }\n\n protected XmlOrderFreeSerializerFactory(IEnumerable<Type> types)\n {\n overrides = new XmlAttributeOverrides();\n foreach (var type in types.SelectMany(t => t.BaseTypesAndSelf()).Distinct())\n {\n AddOverrideAttributes(type, overrides);\n }\n }\n\n public XmlSerializer GetSerializer(Type type)\n {\n if (type == null)\n throw new ArgumentNullException("type");\n lock (locker)\n {\n XmlSerializer serializer;\n if (!serializers.TryGetValue(type, out serializer))\n serializers[type] = serializer = new XmlSerializer(type, overrides);\n return serializer;\n }\n }\n}\n\npublic static class TypeExtensions\n{\n public static IEnumerable<Type> BaseTypesAndSelf(this Type type)\n {\n while (type != null)\n {\n yield return type;\n type = type.BaseType;\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n然后在反序列化类型时,使用XmlSerializer工厂提供的类型。鉴于它SoapEnvelope是 的子类XmlDocument,您应该能够按照Deserialize object property with StringReader vs XmlNodeReader中的答案反序列化主体节点。
注意——仅经过适度测试。演示小提琴在这里。
\n| 归档时间: |
|
| 查看次数: |
3574 次 |
| 最近记录: |