IXmlSerializable 实现后的 WCF 服务 xsd 不正确 [英] WCF service xsd after IXmlSerializable implementation is not correct

查看:26
本文介绍了IXmlSerializable 实现后的 WCF 服务 xsd 不正确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 wcf 服务(使用 xmlserialization).有一些类在 SoapUI 中看起来像这样:

I have a wcf service (using xmlserialization). There is some class which looks in SoapUI like this:

     <MyClass>
        <propertyA>?</propertyA>
        <propertyB>?</propertyB>
     </MyClass>

我必须在其上实现 IXmlSerializable 接口.这样做后,类在 SoapUI 中有奇怪的结构:

I had to implement IXmlSerializable interface on it. After doing it, class has strange structure in 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 方法实现的结果?

May it be a result of the following implementation of the GetSchema method?

    public XmlSchema GetSchema()
    {
        return null;
    }

以下是 wsdl 服务中有关 MyClass 的部分:

Below is section about MyClass from service wsdl:

<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() 应始终返回 null.请参阅实现 IXmlSerializable 的正确方法?.

GetSchema() should always return null. See Proper way to implement IXmlSerializable?.

相反,您需要添加 [XmlSchemaProvider(string methodName)] 到您的类并实现一个静态方法,该方法返回一个 XML 架构和一个 XmlQualifiedName(或 XmlSchemaType 用于匿名类型) 指定类型的架构.

Instead, you need to add [XmlSchemaProvider(string methodName)] to your class and implement a static method that returns an XML schema and an XmlQualifiedName (or XmlSchemaType for anonymous types) that specifies the schema of the type.

例如,如果您的原始类型如下所示:

For instance, if your original type looks like:

[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 重新实现的类型应该类似于:

Then your IXmlSerializable re-implementation of the type should look something like:

[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
}

在这里,我将预期的模式作为字符串文字嵌入到类型中.或者,您可以从磁盘加载它或通过反射构建它.

Here I have embedded the expected schema as a string literal inside the type. Alternatively you could load it from disk or build it by reflection.

这篇关于IXmlSerializable 实现后的 WCF 服务 xsd 不正确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆