IXmlSerializable 实现后的 WCF 服务 xsd 不正确
WCF service xsd after IXmlSerializable implementation is not correct
我有一个 wcf 服务(使用 xmlserialization)。
有一些 class 在 SoapUI 中看起来像这样:
<MyClass>
<propertyA>?</propertyA>
<propertyB>?</propertyB>
</MyClass>
我必须在其上实现 IXmlSerializable 接口。
这样做之后,class 在 SoapUI 中有奇怪的结构:
<MyClass>
<xs:schema>
<!--Ignoring type [{http://www.w3.org/2001/XMLSchema}schema]-->
</xs:schema>
<!--You may enter ANY elements at this point-->
</MyClass>
可能是下面执行GetSchema方法的结果?
public XmlSchema GetSchema()
{
return null;
}
以下是服务 wsdl 中有关 MyClass 的部分:
<xs:element name="MyClass" form="unqualified" maxOccurs="1" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element ref="xs:schema"/>
<xs:any/>
</xs:sequence>
</xs:complexType>
</xs:element>
GetSchema()
应该总是 return null
。参见 Proper way to implement IXmlSerializable?。
相反,您需要将 [XmlSchemaProvider(string methodName)]
添加到 class 并实现一个静态方法,该方法 return 是一个 XML 模式和一个 XmlQualifiedName
(或 XmlSchemaType
对于匿名类型)指定类型的模式。
例如,如果您的原始类型如下所示:
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/Question38741035")]
[XmlRoot(Namespace = "http://schemas.datacontract.org/2004/07/Question38741035")]
public class MyClass
{
[DataMember]
public string PropertyA { get; set; }
[DataMember]
public decimal PropertyB { get; set; }
}
那么您的 IXmlSerializable
类型的重新实现应该类似于:
[XmlSchemaProvider("GetSchemaMethod")]
[XmlRoot(Namespace = "http://schemas.datacontract.org/2004/07/Question38741035")]
public class MyClass : IXmlSerializable
{
public string PropertyA { get; set; }
public decimal PropertyB { get; set; }
const string XmlNamespace = "http://schemas.datacontract.org/2004/07/Question38741035";
// This is the method named by the XmlSchemaProviderAttribute applied to the type.
public static XmlQualifiedName GetSchemaMethod(XmlSchemaSet xs)
{
string schema = @"<?xml version=""1.0"" encoding=""utf-16""?>
<xs:schema
xmlns:tns=""http://schemas.datacontract.org/2004/07/Question38741035""
elementFormDefault=""qualified""
targetNamespace=""http://schemas.datacontract.org/2004/07/Question38741035""
xmlns:xs=""http://www.w3.org/2001/XMLSchema"">
<xs:complexType name=""MyClass"">
<xs:sequence>
<xs:element minOccurs=""0"" name=""PropertyA"" nillable=""true"" type=""xs:string"" />
<xs:element minOccurs=""0"" name=""PropertyB"" type=""xs:decimal"" />
</xs:sequence>
</xs:complexType>
<xs:element name=""MyClass"" nillable=""true"" type=""tns:MyClass"" />
</xs:schema>";
using (var textReader = new StringReader(schema))
using (var schemaSetReader = System.Xml.XmlReader.Create(textReader))
{
xs.Add(XmlNamespace, schemaSetReader);
}
return new XmlQualifiedName("MyClass", XmlNamespace);
}
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
if (reader.IsEmptyElement)
{
reader.Read();
return;
}
var node = (XElement)XNode.ReadFrom(reader);
if (node != null)
{
var ns = (XNamespace)XmlNamespace;
PropertyA = (string)node.Element(ns + "PropertyA");
PropertyB = (decimal)node.Element(ns + "PropertyB");
}
}
public void WriteXml(System.Xml.XmlWriter writer)
{
if (PropertyA != null)
writer.WriteElementString("PropertyA", XmlNamespace, PropertyA);
writer.WriteStartElement("PropertyB", XmlNamespace);
writer.WriteValue(PropertyB);
writer.WriteEndElement();
}
#endregion
}
在这里,我将预期的模式作为字符串文字嵌入到类型中。或者,您可以从磁盘加载它或通过反射构建它。
我有一个 wcf 服务(使用 xmlserialization)。 有一些 class 在 SoapUI 中看起来像这样:
<MyClass>
<propertyA>?</propertyA>
<propertyB>?</propertyB>
</MyClass>
我必须在其上实现 IXmlSerializable 接口。 这样做之后,class 在 SoapUI 中有奇怪的结构:
<MyClass>
<xs:schema>
<!--Ignoring type [{http://www.w3.org/2001/XMLSchema}schema]-->
</xs:schema>
<!--You may enter ANY elements at this point-->
</MyClass>
可能是下面执行GetSchema方法的结果?
public XmlSchema GetSchema()
{
return null;
}
以下是服务 wsdl 中有关 MyClass 的部分:
<xs:element name="MyClass" form="unqualified" maxOccurs="1" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element ref="xs:schema"/>
<xs:any/>
</xs:sequence>
</xs:complexType>
</xs:element>
GetSchema()
应该总是 return null
。参见 Proper way to implement IXmlSerializable?。
相反,您需要将 [XmlSchemaProvider(string methodName)]
添加到 class 并实现一个静态方法,该方法 return 是一个 XML 模式和一个 XmlQualifiedName
(或 XmlSchemaType
对于匿名类型)指定类型的模式。
例如,如果您的原始类型如下所示:
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/Question38741035")]
[XmlRoot(Namespace = "http://schemas.datacontract.org/2004/07/Question38741035")]
public class MyClass
{
[DataMember]
public string PropertyA { get; set; }
[DataMember]
public decimal PropertyB { get; set; }
}
那么您的 IXmlSerializable
类型的重新实现应该类似于:
[XmlSchemaProvider("GetSchemaMethod")]
[XmlRoot(Namespace = "http://schemas.datacontract.org/2004/07/Question38741035")]
public class MyClass : IXmlSerializable
{
public string PropertyA { get; set; }
public decimal PropertyB { get; set; }
const string XmlNamespace = "http://schemas.datacontract.org/2004/07/Question38741035";
// This is the method named by the XmlSchemaProviderAttribute applied to the type.
public static XmlQualifiedName GetSchemaMethod(XmlSchemaSet xs)
{
string schema = @"<?xml version=""1.0"" encoding=""utf-16""?>
<xs:schema
xmlns:tns=""http://schemas.datacontract.org/2004/07/Question38741035""
elementFormDefault=""qualified""
targetNamespace=""http://schemas.datacontract.org/2004/07/Question38741035""
xmlns:xs=""http://www.w3.org/2001/XMLSchema"">
<xs:complexType name=""MyClass"">
<xs:sequence>
<xs:element minOccurs=""0"" name=""PropertyA"" nillable=""true"" type=""xs:string"" />
<xs:element minOccurs=""0"" name=""PropertyB"" type=""xs:decimal"" />
</xs:sequence>
</xs:complexType>
<xs:element name=""MyClass"" nillable=""true"" type=""tns:MyClass"" />
</xs:schema>";
using (var textReader = new StringReader(schema))
using (var schemaSetReader = System.Xml.XmlReader.Create(textReader))
{
xs.Add(XmlNamespace, schemaSetReader);
}
return new XmlQualifiedName("MyClass", XmlNamespace);
}
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
if (reader.IsEmptyElement)
{
reader.Read();
return;
}
var node = (XElement)XNode.ReadFrom(reader);
if (node != null)
{
var ns = (XNamespace)XmlNamespace;
PropertyA = (string)node.Element(ns + "PropertyA");
PropertyB = (decimal)node.Element(ns + "PropertyB");
}
}
public void WriteXml(System.Xml.XmlWriter writer)
{
if (PropertyA != null)
writer.WriteElementString("PropertyA", XmlNamespace, PropertyA);
writer.WriteStartElement("PropertyB", XmlNamespace);
writer.WriteValue(PropertyB);
writer.WriteEndElement();
}
#endregion
}
在这里,我将预期的模式作为字符串文字嵌入到类型中。或者,您可以从磁盘加载它或通过反射构建它。