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
это применимо только тогда, когда рассматриваемый тип является корневым элементом документа.
В качестве обходного пути у вас есть несколько вариантов:
Жесткий код ожидаемого имени корневого элемента при создании сериализатора:
var xs = new DataContractSerializer(typeof(service.a1.com.base1._2005.PersonType), "Person", "http://service.a1.com/base1/2005/");
Предварительная загрузка 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); }
Или использовать
XmlSerializer
,