DataContractSerializer.ReadObject() не может создать объект при использовании с SvcUtils.exe

Я запустил SvcUtil.exe против XSD-файла, чтобы создать класс. Затем попытался создать объект из XML, используя следующую строку. Я получаю ошибку, показанную ниже. Пожалуйста, смотрите подробный код ниже.

PersonType prs = (PersonType)xs.ReadObject(new MemoryStream(File.ReadAllBytes(sFileName)));

Error in line 3 position 58. Expecting element 'PersonType' from namespace 'http://service.a1.com/base1/2005/'.. Encountered 'Element'  with name 'Person', namespace 'http://service.a1.com/base1/2005/'. 

Используемая команда

svcutil.exe" "C:\Temp\S1\UseXSDExe\UseXSDExe\Sample2\Prs.xsd" /t:code /language:cs /out:C:\SPrxy.cs /dconly

Полный код

(class generated by SvcUtils.exe)
    [assembly: System.Runtime.Serialization.ContractNamespaceAttribute("http://service.a1.com/base1/2005/", ClrNamespace="service.a1.com.base1._2005")]
    namespace service.a1.com.base1._2005
    {
        using System.Runtime.Serialization;


        [System.Diagnostics.DebuggerStepThroughAttribute()]
        [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
        [System.Runtime.Serialization.DataContractAttribute(Name="PersonType", Namespace="http://service.a1.com/base1/2005/")]
        public partial class PersonType : object, System.Runtime.Serialization.IExtensibleDataObject
        {
            private System.Runtime.Serialization.ExtensionDataObject extensionDataField;

            private string LastNameField;

            private string FirstNameField;

            public System.Runtime.Serialization.ExtensionDataObject ExtensionData
            {
                get
                {
                    return this.extensionDataField;
                }
                set
                {
                    this.extensionDataField = value;
                }
            }

            [System.Runtime.Serialization.DataMemberAttribute(IsRequired=true, EmitDefaultValue=false)]
            public string LastName
            {
                get
                {
                    return this.LastNameField;
                }
                set
                {
                    this.LastNameField = value;
                }
            }

            [System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false, Order=1)]
            public string FirstName
            {
                get
                {
                    return this.FirstNameField;
                }
                set
                {
                    this.FirstNameField = value;
                }
            }
        }
    }

(code used for converting XML to object)
    public static void convertToObject(string sFileName)
    {
        DataContractSerializer xs = new DataContractSerializer(typeof(PersonType));
        PersonType Person = (PersonType)xs.ReadObject(new MemoryStream(File.ReadAllBytes(sFileName)));

    }

(XSD)

    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://service.a1.com/base1/2005/"  xmlns:bse1="http://service.a1.com/base1/2005/" elementFormDefault="qualified">
        <xs:complexType  name="PersonType">
            <xs:sequence>
                <xs:element minOccurs="1" maxOccurs="1" name="LastName" type="xs:string" />
                <xs:element minOccurs="0" maxOccurs="1" name="FirstName" type="xs:string" />
            </xs:sequence>
        </xs:complexType>
        <xs:element name="Person" type="bse1:PersonType"/> 
    </xs:schema>

(XML)

    <?xml version="1.0" encoding="utf-8"?>
    <pr:Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                xsi:schemaLocation="http://service.a1.com/base1/2005/ Prs.xsd" 
                xmlns:pr="http://service.a1.com/base1/2005/"> 
        <pr:LastName>   Lane </pr:LastName>
        <pr:FirstName>  Fane </pr:FirstName>
    </pr:Person>

Я запустил XSD.exe в том же файле XSD. Затем я смог преобразовать XML в объект, используя XmlSerializer.Deserialize(),

XSD не имеет никаких атрибутов. Я проверил XML против XSD.

Пожалуйста, дайте мне знать, почему Deserialize() выходит из строя.

1 ответ

Решение

Ваш XSD указывает имя корневого элемента и имя типа данных, которые различаются:

 <xs:element name="Person" type="bse1:PersonType"/> 

когда svcutil.exe генерирует классы контракта данных для этого типа, он помещает имя типа в контракт данных, а не имя корневого элемента. Это выглядит намеренно, см. Svcutil генерирует неправильное значение свойства Name в DataContractAttribute. Возможно, это происходит потому, что сам тип контракта может быть повторно использован где угодно в графе объектов, и нет никакого контракта данных, эквивалентного XmlRoot это применимо только тогда, когда рассматриваемый тип является корневым элементом документа.

В качестве обходного пути у вас есть несколько вариантов:

  1. Жесткий код ожидаемого имени корневого элемента при создании сериализатора:

        var xs = new DataContractSerializer(typeof(service.a1.com.base1._2005.PersonType), "Person", "http://service.a1.com/base1/2005/");
    
  2. Предварительная загрузка XML в XDocument и использовать фактическое имя корневого элемента при создании сериализатора:

        var doc = XDocument.Load(sFileName);
        service.a1.com.base1._2005.PersonType person;
        var xs = new DataContractSerializer(typeof(service.a1.com.base1._2005.PersonType), doc.Root.Name.LocalName, "http://service.a1.com/base1/2005/");
        using (var reader = doc.CreateReader())
        {
            person = (service.a1.com.base1._2005.PersonType)xs.ReadObject(reader);
        }
    
  3. Или использовать XmlSerializer,

Другие вопросы по тегам