【问题标题】:RESTSharp has problems deserializing XML including Byte Order Mark?RESTSharp 在反序列化 XML 时遇到问题,包括字节顺序标记?
【发布时间】:2013-10-29 15:50:28
【问题描述】:

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

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

检索响应时出错。检查内部细节以获取更多信息。 ---> System.Xml.XmlException: 根级别的数据无效。 1号线, 位置 1. 在 System.Xml.XmlTextReaderImpl.Throw(Exception e)
在 System.Xml.XmlTextReaderImpl.Throw(String res, String arg) 在 System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace() 在 System.Xml.XmlTextReaderImpl.ParseDocumentContent() 在 System.Xml.XmlTextReaderImpl.Read() 在 System.Xml.Linq.XDocument.Load(XmlReader 阅读器,LoadOptions 选项) 在 System.Xml.Linq.XDocument.Parse(字符串文本,LoadOptions 选项)
在 System.Xml.Linq.XDocument.Parse(字符串文本)在 RestSharp.Deserializers.XmlDeserializer.Deserialize[T](IRestResponse 响应)在 RestSharp.RestClient.Deserialize[T](IRestRequest 请求,IRestResponse 原始)
--- 内部异常堆栈跟踪结束 ---

这是一个使用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 中处理这个问题吗?我究竟做错了什么?提前谢谢你!

【问题讨论】:

    标签: c# restsharp byte-order-mark


    【解决方案1】:

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

    您也可以使用#RESTSharp 中的“RestRequest.OnBeforeDeserialization”事件,而不是包装 XMLDeserializer。所以你只需要在 new 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);
                };
    

    【讨论】:

    • 很高兴我能帮上忙。我喜欢解决方案的简单性。
    • 这将工作!试试这个看看为什么:var preamble = System.Text.Encoding.UTF8.GetPreamble(); var preambleString = System.Text.Encoding.UTF8.GetString(preamble); var message = new byte[] { 60, 63, 120, 109, 108, 32 }; // "&lt;?xml " var messageString = System.Text.Encoding.UTF8.GetString(message); Console.WriteLine(preamble); Console.WriteLine(preambleString.Length); Console.WriteLine(messageString); Console.WriteLine(messageString.StartsWith(preambleString));
    【解决方案2】:

    我也遇到过同样的问题,但不是专门针对 RestSharp。使用这个:

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

    原讨论:XmlReader breaks on UTF-8 BOM

    来自答案的相关引用:

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

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

    【讨论】:

    • 谢谢!但是如何将它与 RESTSharp 一起使用?
    【解决方案3】:

    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 尚未设置为值时才会转换为字符串。

    【讨论】:

      【解决方案4】:

      要使其与 RestSharp 一起使用,您可以手动解析响应内容并删除“

      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));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多