草庐IT

.net - SOAP 客户端未正确处理 XML 实体;遇到 "There is an error in XML document"

coder 2024-07-01 原文

我们的 WCF Web 服务的一些消费者在尝试解析我们的响应时遇到异常:

System.InvalidOperationException: There is an error in XML document (5, -349).
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
   at [Consumer's Code]

内部异常看起来像这样:

'', hexadecimal value 0x0B, is an invalid character. Line 5, position -349.

   at System.Xml.XmlTextReaderImpl.Throw(Exception e)
   at System.Xml.XmlTextReaderImpl.Throw(String res, String[] args)
   at System.Xml.XmlTextReaderImpl.ThrowInvalidChar(Int32 pos, Char invChar)
   at System.Xml.XmlTextReaderImpl.ParseNumericCharRefInline(Int32 startPos, Boolean expand, BufferBuilder internalSubsetBuilder, Int32& charCount, EntityType& entityType)
   at System.Xml.XmlTextReaderImpl.ParseCharRefInline(Int32 startPos, Int32& charCount, EntityType& entityType)
   at System.Xml.XmlTextReaderImpl.ParseText(Int32& startPos, Int32& endPos, Int32& outOrChars)
   at System.Xml.XmlTextReaderImpl.ParseText()
   at System.Xml.XmlTextReaderImpl.ParseElementContent()
   at System.Xml.XmlTextReaderImpl.Read()
   at System.Xml.XmlTextReader.Read()
   at System.Xml.XmlReader.ReadElementString()
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read43_TextWidgetConfig(Boolean isNullable, Boolean checkType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read45_TextWidgetInfo(Boolean isNullable, Boolean checkType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read49_WidgetInfo(Boolean isNullable, Boolean checkType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read50_InstantPageData(Boolean isNullable, Boolean checkType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read128_GetInstantPageDataResponse()
   at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer141.Deserialize(XmlSerializationReader reader)
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)

不知何故返回的客户数据中有垂直制表符。查看我们的 XML,我们可以看到这些字符被正确呈现为 实体。通过快速 Google 搜索,我们发现 XmlSerializer 存在一个错误,它无法处理某些实体,必须通过更改自动生成的代理的 XML 阅读器中的选项来修复该错误.

消费者承认他们需要修复客户端代码,但他们无法通过补丁快速响应此问题。他们希望我们在自己的代码中应用补丁来过滤掉这些禁用字符。

  1. 是否在任何地方记录了 XmlSerializer 的问题字符列表?
  2. 是否有一种干净的方法来更改我们的 WCF 服务,以便我们可以自动删除字符,而无需在我们所有的网络方法中进行字符串替换?

更新:

我找到了#1 的答案。根据the XML spec , 只允许某些字符代码:

Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]

所以我们服务器上的 DataContractSerializer 似乎是这里的错误所在。我现在正在研究如何自定义该序列化程序。

更新 2:

看起来 DataContractSerializer 问题是已知的并且 logged in Microsoft Connect .

最佳答案

这是我的解决方法代码。我对此不是很高兴;它并没有涵盖所有情况(尽管它满足了我的需求),而且感觉应该有一个更简单的解决方案。我会把它贴在这里,希望其他人可以做得更好,或者有人有更简单的答案。

为了解决这个问题,我创建了一个新的操作行为属性来将序列化程序更改为自定义序列化程序,该序列化程序会去除将呈现为无效 XML 实体的字符:

public class StripInvalidXmlCharactersBehaviorAttribute 
    : Attribute, IOperationBehavior
{
    public void AddBindingParameters(
        OperationDescription operationDescription, 
        BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(
        OperationDescription operationDescription, 
        ClientOperation clientOperation)
    {
        IOperationBehavior behavior =
            new StripInvalidXmlCharactersBehavior(operationDescription);
        behavior.ApplyClientBehavior(operationDescription, clientOperation);
    }

    public void ApplyDispatchBehavior(
        OperationDescription operationDescription, 
        DispatchOperation dispatchOperation)
    {
        IOperationBehavior behavior =
            new StripInvalidXmlCharactersBehavior(operationDescription);
        behavior.ApplyDispatchBehavior(
            operationDescription, dispatchOperation);
    }

    public void Validate(OperationDescription operationDescription)
    {
    }
}

行为本身看起来像这样:

internal class StripInvalidXmlCharactersBehavior 
    : DataContractSerializerOperationBehavior
{
    public StripInvalidXmlCharactersBehavior(OperationDescription opDesc)
        : base(opDesc)
    {
    }

    public override XmlObjectSerializer CreateSerializer(
        Type type, string name, string ns, IList<Type> knownTypes)
    {
        return new InvalidXmlStrippingSerializer(type, name, ns, knownTypes);
    }

    public override XmlObjectSerializer CreateSerializer(
        Type type, XmlDictionaryString name, XmlDictionaryString ns, 
        IList<Type> knownTypes)
    {
        return new InvalidXmlStrippingSerializer(type, name, ns, knownTypes);
    }
}

这是序列化器:

internal class InvalidXmlStrippingSerializer : XmlObjectSerializer
{
    private DataContractSerializer _innerSerializer;

    public InvalidXmlStrippingSerializer(
        Type type, string name, string ns, IList<Type> knownTypes)
    {
        _innerSerializer = 
            new DataContractSerializer(type, name, ns, knownTypes);
    }

    public InvalidXmlStrippingSerializer(
        Type type, XmlDictionaryString name, XmlDictionaryString ns, 
        IList<Type> knownTypes)
    {
        _innerSerializer =
            new DataContractSerializer(type, name, ns, knownTypes);
    }

    public override bool IsStartObject(XmlDictionaryReader reader)
    {
        return _innerSerializer.IsStartObject(reader);
    }

    public override object ReadObject(
        XmlDictionaryReader reader, bool verifyObjectName)
    {
        return _innerSerializer.ReadObject(reader, verifyObjectName);
    }

    public override void WriteEndObject(XmlDictionaryWriter writer)
    {
        _innerSerializer.WriteEndObject(writer);
    }

    public override void WriteObjectContent(
        XmlDictionaryWriter writer, object graph)
    {
        graph = fixBadStringsRecursive(graph);
        _innerSerializer.WriteObjectContent(writer, graph);
    }

    private object fixBadStringsRecursive(object graph)
    {
        var objType = graph.GetType();
        if (objType == typeof(string))
        {
            graph = removeInvalidCharacters(graph as string);
        }
        else if (graph is IEnumerable)
        {
            foreach (var item in graph as IEnumerable)
            {
                fixBadStringsRecursive(item);
            }
        }
        else if (objType.IsClass)
        {
            // Look through the properties of the object 
            foreach (var prop in graph.GetType().GetProperties())
            {
                var propParams = prop.GetIndexParameters();
                if ((propParams == null || propParams.Length == 0)
                    && prop.GetGetMethod() != null)
                {
                    var propVal = prop.GetValue(graph, null);
                    if (propVal != null)
                    {
                        propVal = fixBadStringsRecursive(propVal);
                        if (prop.GetSetMethod() != null)
                        {
                            prop.SetValue(graph, propVal, null);
                        }
                    }
                }
            }
        }
        return graph;
    }

    private static string removeInvalidCharacters(string source)
    {
        // This is per the W3C XML spec:
        // http://www.w3.org/TR/xml/#NT-Char
        return new string(
            (
                from ch in source
                where
                    ch == '\u0009' || ch == '\u000a' || ch == '\u000d'
                    || (ch >= '\u0020' && ch <= '\ud7ff')
                    || (ch >= '\ue000' && ch <= '\ufffd')
                select ch
            ).ToArray()
        );
    }

    public override void WriteStartObject(
        XmlDictionaryWriter writer, object graph)
    {
        _innerSerializer.WriteStartObject(writer, graph);
    }
}

要将行为应用于我的操作,我现在只需添加我创建的属性即可。

关于.net - SOAP 客户端未正确处理 XML 实体;遇到 "There is an error in XML document",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5021083/

有关.net - SOAP 客户端未正确处理 XML 实体;遇到 "There is an error in XML document"的更多相关文章

  1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  2. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  3. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  4. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  5. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  6. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  7. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  8. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  9. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

    我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

  10. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

随机推荐