7

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

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

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

这是使用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

4 回答 4

8

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

除了包装 XMLDeserializer,您还可以使用#RESTSharp 中的“RestRequest.OnBeforeDeserialization”事件。因此,您只需要在 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);
            };
于 2013-10-30T13:24:06.100 回答
2

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

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

原始讨论:XmlReader 在 UTF-8 BOM 上中断

来自答案的相关引用:

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

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

于 2013-10-29T16:32:12.090 回答
2

@dataCore 发布的解决方案不太奏效,但这个应该。

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.Contentnull作为安全防护,只有在尚未设置为值RawBytes时才转换为字符串。Content

于 2019-06-12T03:56:51.657 回答
0

要使其与 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));
于 2017-08-21T00:08:27.427 回答