2016-11-12 2 views
0

Я пытаюсь deserialise небольшой фрагмент XML с DataContractSerializer:DataContractSerializer: SerializationException «EndElement» не ожидается

<iopbase:SoapFaultException xmlns:iopbase=""http://example.com/foo/""> 
    <faultcode></faultcode> 
    <faultstring>Hello World</faultstring> 
</iopbase:SoapFaultException> 

Проблема заключается в DataContractSerializer не «видеть» <faultcode> и <faultstring> элементы и я получаю следующее исключение:

SerializationException: 'EndElement' 'SoapFaultException' from namespace 
'http://example.com/foo/' is not expected. Expecting element 'faultcode'. 

Вот урезанная немного кода, чтобы повторить вопрос:

[DataContract(Namespace = "http://example.com/foo/")] 
public class SoapFaultException 
{ 
    [DataMember(IsRequired = true)] 
    public string faultcode { get; set; } 

    [DataMember(IsRequired = true)] 
    public string faultstring { get; set; } 
} 

var xml = System.Xml.Linq.XElement.Parse(@" 
<iopbase:SoapFaultException xmlns:iopbase=""http://example.com/foo/""> 
    <faultcode></faultcode> 
    <faultstring>Hello World</faultstring> 
</iopbase:SoapFaultException>"); 

var serializer = new DataContractSerializer(typeof(SoapFaultException)); 
var e = (SoapFaultException) serializer.ReadObject(xml.CreateReader()); <- Exception Here 

И, наконец, трассировка стека Исключения.

at System.Runtime.Serialization.XmlObjectSerializerReadContext.ThrowRequiredMemberMissingException(XmlReaderDelegator xmlReader, Int32 memberIndex, Int32 requiredIndex, XmlDictionaryString[] memberNames) 
    at ReadSoapFaultExceptionFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[]) 
    at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context) 
    at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader) 
    at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract) 
    at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, String name, String ns) 
    at System.Runtime.Serialization.DataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName, DataContractResolver dataContractResolver) 
    at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver) 
    at System.Runtime.Serialization.DataContractSerializer.ReadObject(XmlReader reader) 
    at XXX.Program.Main() in C:\Git\XXX\Program.cs:line 161 
    at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 
    at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 
    at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
    at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
    at System.Threading.ThreadHelper.ThreadStart() 

ответ

1

Причина вы видите исключение в том, что пространство имен элементов <faultcode> и <faultstring> несовместимы с контрактом данных.

С одной стороны, в вашем XML корневой элемент находится в пространстве имен xmlns:iopbase="http://example.com/foo/", но его дочерние элементы не находятся в каком-либо пространстве имен, лишенном префикса xmlns:. С другой стороны, добавив [DataContract(Namespace = "http://example.com/foo/")] в SoapFaultException, вы указываете, что корневой элемент SoapFaultException, а также его дочерние элементы должны появиться в указанном пространстве имен. И поскольку элементы XML не находятся в этом пространстве имен, они не десериализованы успешно.

Чтобы подтвердить это, если я сериализовать из экземпляра вашего типа, установив префикс пространства имен xmlns:iopbase="http://example.com/foo/", я получаю:

<iopbase:SoapFaultException xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://example.com/foo/" xmlns:iopbase="http://example.com/foo/"> 
    <iopbase:faultcode></iopbase:faultcode> 
    <iopbase:faultstring>Hello World</iopbase:faultstring> 
</iopbase:SoapFaultException> 

Использование кода

var test = new SoapFaultException { faultcode = "", faultstring = "Hello World" }; 

var serializer = new DataContractSerializer(typeof(SoapFaultException)); 
var doc = new XDocument(); 
using (var writer = doc.CreateWriter()) 
{ 
    serializer.WriteObject(writer, test); 
} 
// Add the iopbase prefix for clarity 
doc.Root.Add(new XAttribute(XNamespace.Xmlns + "iopbase", "http://example.com/foo/")); 
Debug.WriteLine(doc); 

Чтобы решить эту проблему, в идеале вы хотели бы иметь возможность указывать пространства имен имен данных независимо от общего пространства имен контрактов данных, но, к сожалению, сериализатор данных по контракту doesn't support that. Вместо этого, у вас есть следующие варианты:

  • Вы можете разделить ваши SoapFaultException в иерархию классов и указать другое пространство имен для каждого уровня в иерархии, размещая наиболее производный тип в пространстве имен корневого элемента следующим образом:

    [DataContract(Namespace = "")] 
    public abstract class SoapFaultExceptionBase 
    { 
        [DataMember(IsRequired = true)] 
        public string faultcode { get; set; } 
    
        [DataMember(IsRequired = true)] 
        public string faultstring { get; set; } 
    } 
    
    [DataContract(Namespace = "http://example.com/foo/")] 
    public class SoapFaultException : SoapFaultExceptionBase 
    { 
    } 
    
  • Вы можете оставить свой SoapFaultException в пустом пространстве имен, и construct your DataContractSerializer с прилагаемым корневой XML имя элемента и пространства имен:

    [DataContract(Namespace = "")] 
    public class SoapFaultException 
    { 
        [DataMember(IsRequired = true)] 
        public string faultcode { get; set; } 
    
        [DataMember(IsRequired = true)] 
        public string faultstring { get; set; } 
    } 
    

    А потом сделать:

    var serializer = new DataContractSerializer(typeof(SoapFaultException), "SoapFaultException", "http://example.com/foo/"); 
    var e = (SoapFaultException)serializer.ReadObject(xml.CreateReader()); 
    
+0

теперь вы отмечаете дочерние элементы не принадлежат к пространству имен кажется очевидным! Я использовал ваш реферат и предложение суб-класса. Большое спасибо! – jameskind

Смежные вопросы