【问题标题】:Can't Deserialize xml using DataContractSerializer无法使用 DataContractSerializer 反序列化 xml
【发布时间】:2021-02-13 02:17:45
【问题描述】:

我无法将此 XML 反序列化为对象,我不知道这有什么问题:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
    <ProcessOneWayEvent xmlns="http://schemas.microsoft.com/sharepoint/remoteapp/">
        <properties xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <CultureLCID>1033</CultureLCID>
        </properties>
    </ProcessOneWayEvent>
</s:Body>
</s:Envelope>

这是一个准备好的sample,有什么解决方法吗,因为我无法在请求中修改,所以我的模型有什么问题吗?是否有任何解决方案可以在不使用 XmlSerializer 的情况下反序列化 XML

https://dotnetfiddle.net/RfQMSD

【问题讨论】:

  • 您确实应该将您的代码包含在问题本身中,而不仅仅是在外部小提琴中。请参阅How to Ask如果可以创建一个可以链接到的问题的实时示例(例如,在sqlfiddle.comjsbin.com 上)然后这样做 - 但也将代码复制到问题中本身。不是每个人都可以访问外部网站,而且链接可能会随着时间的推移而中断。

标签: c# xml asp.net-core datacontractserializer


【解决方案1】:

BodySPRemoteEventProperties 需要在 "http://schemas.microsoft.com/sharepoint/remoteapp/" 命名空间中:

[DataContract(Name = "Body", Namespace = "http://schemas.microsoft.com/sharepoint/remoteapp/")]
public class Body
{
    [DataMember(Name = "ProcessOneWayEvent")]
    public ProcessOneWayEvent ProcessOneWayEvent;
}

[DataContract(Name = "properties", Namespace = "http://schemas.microsoft.com/sharepoint/remoteapp/")]
public class SPRemoteEventProperties
{
    [DataMember(Name = "CultureLCID") ]
    public int CultureLCID { get; set; }
}

DataContractAttribute.Namespace控制数据契约对象的数据成员元素序列化到的命名空间,以及当数据契约对象为根元素时根元素的命名空间。由于元素 &lt;ProcessOneWayEvent xmlns="http://schemas.microsoft.com/sharepoint/remoteapp/"&gt; 声明了一个新的默认 XML 命名空间,因此该元素本身及其子元素都在此命名空间中。因此,包含数据合约对象Body 必须相应地设置其数据成员命名空间。至于&lt;properties xmlns:i="http://www.w3.org/2001/XMLSchema-instance"&gt;i: 命名空间不是默认命名空间,因此实际上没有元素被分配给这个命名空间,SPRemoteEventProperties 类型不应该将自己分配给它。

固定小提琴here.

【讨论】:

  • 谢谢你,这个非常棒的解决方案和解释。
【解决方案2】:

我没有立即明白为什么它不起作用,但一种替代方法是使用 System.Xml.Serialization.XmlSerializer

首先通过将 XML 复制到新类中来创建适当的信封类(编辑 → 选择性粘贴 → 将 XML 粘贴为类)

然后以此为例进行反序列化:

byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(request);
using (var stream = new MemoryStream(byteArray))
{
    var serializer = new XmlSerializer(typeof(Envelope));
    Envelope response = (Envelope)serializer.Deserialize(stream);
    Console.WriteLine(JsonConvert.SerializeObject(response));
}

【讨论】:

  • 谢谢Berend,但我提到由于性能问题我不能使用XmlSerializer
  • @Houssem 那么更新您的问题并明确提及此要求可能是个好主意:-(
【解决方案3】:

尝试以下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication1
{

    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            string xml = File.ReadAllText(FILENAME);
            StringReader sReader = new StringReader(xml);
            XmlReader reader = XmlReader.Create(sReader);

            XmlSerializer serializer = new XmlSerializer(typeof(Envelope));
            Envelope envelope = (Envelope)serializer.Deserialize(reader);

        }
    }
    [XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
    public class Envelope
    {
        [XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
        public Body Body { get; set; }
    }
    public class Body
    {
        [XmlElement(ElementName = "ProcessOneWayEvent", Namespace = "http://schemas.microsoft.com/sharepoint/remoteapp/")]
        public ProcessOneWayEvent ProcessOneWayEvent { get; set; }
    }
    public class ProcessOneWayEvent
    {
        public Properties properties { get; set; } 
    }
    public class Properties
    {
        public string CultureLCID { get; set; }
    }
}

使用 Xml Linq

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
{

    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            string xml = File.ReadAllText(FILENAME);
            XDocument doc = XDocument.Parse(xml);
            string CultureLCID = (string)doc.Descendants().Where(x => x.Name.LocalName == "CultureLCID").FirstOrDefault();


        }
    }

}

【讨论】:

  • 我发布了两个解决方案。一种使用序列化程序,一种使用 xml linq
猜你喜欢
  • 2013-03-03
  • 2013-06-01
  • 2011-06-27
  • 1970-01-01
  • 1970-01-01
  • 2018-05-09
  • 1970-01-01
  • 2014-08-31
  • 1970-01-01
相关资源
最近更新 更多