RESTSharp在反序列化XML时遇到问题,包括字节顺序标记?

时间:2013-10-29 15:50:29

标签: c# restsharp byte-order-mark

我想在一个简短的C#应用​​程序中使用一个公共Web服务: http://ws.parlament.ch/

此Web服务返回的XML在开头有一个“BOM”,这会导致RESTSharp无法反序列化XML,并显示以下错误消息:

  

检索响应时出错。查看内部细节以获取更多信息。 --->   System.Xml.XmlException:根级别的数据无效。第1行,   位于System.Xml.XmlTextReaderImpl.Throw的位置1。(例外e)
  在System.Xml.XmlTextReaderImpl.Throw(String res,String arg)at   System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace()at   System.Xml.XmlTextReaderImpl.ParseDocumentContent()at   System.Xml.XmlTextReaderImpl.Read()at   System.Xml.Linq.XDocument.Load(XmlReader reader,LoadOptions选项)   在System.Xml.Linq.XDocument.Parse(String text,LoadOptions options)
  在System.Xml.Linq.XDocument.Parse(String text)at   RestSharp.Deserializers.XmlDeserializer.Deserialize [T](IRestResponse   在RestSharp.RestClient.Deserialize [T](IRestRequest   请求,IRestResponse raw)
  ---内部异常堆栈跟踪结束---

以下是使用http://ws.parlament.ch/sessions?format=xml获取“会话”列表的简单示例:

public class Session
{
    public int Id { get; set; }
    public DateTime? Updated { get; set; }
    public int? Code { get; set; }
    public DateTime? From { get; set; }
    public string Name { get; set; }
    public DateTime? To { get; set; }
}


static void Main(string[] args)
    {
        var request = new RestRequest();
        request.RequestFormat = DataFormat.Xml;
        request.Resource = "sessions";
        request.AddParameter("format", "xml");

        var client = new RestClient("http://ws.parlament.ch/");
        var response = client.Execute<List<Session>>(request);

        if (response.ErrorException != null)
        {
            const string message = "Error retrieving response.  Check inner details for more info.";
            var ex = new ApplicationException(message, response.ErrorException);
            Console.WriteLine(ex);
        }

        List<Session> test = response.Data;

        Console.Read();
    }

当我第一次使用Fiddler操作返回的xml以删除前3位(“BOM”)时,上面的代码可以正常工作!有人可以帮我直接在RESTSharp中处理这个吗?我究竟做错了什么?谢谢你提前!

4 个答案:

答案 0 :(得分:7)

我找到了解决方案 - 谢谢@arootbeer的提示!

您也可以使用&#39; RestRequest.OnBeforeDeserialization&#39;而不是包装XMLDeserializer。来自#RESTSharp的活动。所以你只需要在新的RestRequest()之后插入这样的东西(参见我的初始代码示例)然后它就完美了!

request.OnBeforeDeserialization = resp =>
            {
                //remove the first ByteOrderMark
                //see: http://stackoverflow.com/questions/19663100/restsharp-has-problems-deserializing-xml-including-byte-order-mark
                string byteOrderMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
                if (resp.Content.StartsWith(byteOrderMarkUtf8))
                    resp.Content = resp.Content.Remove(0, byteOrderMarkUtf8.Length);
            };

答案 1 :(得分:2)

我遇到了同样的问题,但没有专门针对RestSharp。使用此:

var responseXml = new UTF8Encoding(false).GetString(bytes);

原始讨论:XmlReader breaks on UTF-8 BOM

答案中的相关引言:

  

xml字符串不能(!)包含BOM,BOM仅允许在用UTF-8编码的字节数据(例如流)中。这是因为字符串表示不是编码的,而是已经是一系列unicode字符。

编辑: 通过他们的文档,看起来最简单的处理方法(除了GitHub问题)是调用非泛型Execute()方法并反序列化该字符串的响应。您还可以创建一个包装默认XML反序列化器的IDeserializer

答案 2 :(得分:1)

solution that @dataCore posted不能正常工作,但是这个应该可以。

request.OnBeforeDeserialization = resp => {
    if (resp.RawBytes.Length >= 3 && resp.RawBytes[0] == 0xEF && resp.RawBytes[1] == 0xBB && resp.RawBytes[2] == 0xBF)
    {
        // Copy the data but with the UTF-8 BOM removed.
        var newData = new byte[resp.RawBytes.Length - 3];
        Buffer.BlockCopy(resp.RawBytes, 3, newData, 0, newData.Length);
        resp.RawBytes = newData;

        // Force re-conversion to string on next access
        resp.Content = null;
    }
};

可以将resp.Content设置为null作为安全防护,因为RawBytes仅在Content尚未设置为值的情况下才转换为字符串。 / p>

答案 3 :(得分:0)

要使其与RestSharp一起使用,您可以手动解析响应内容并删除“&lt;”之前的所有“有趣”字符。

var firstChar = responseContent[0];

// removing any 'funny' characters coming before '<'
while (firstChar != 60)
{
    responseContent= responseContent.Remove(0, 1);
    firstChar = responseContent[0];
}

XmlReader.Create(new StringReader(responseContent));