【问题标题】:WCF Message Inspector - modify invalid XML SOAP responseWCF 消息检查器 - 修改无效的 XML SOAP 响应
【发布时间】:2020-04-20 16:23:31
【问题描述】:

我正在使用 .NET 中的 WCF 客户端调用 SOAP 服务。 有时,SOAP 服务会发回无法序列化到 .NET 对象的响应。这里的罪魁祸首是一个日期时间字段,他们在其中发回“24:00:00”而不是“00:00:00”。

在这种情况下,我们会返回以下错误:“日历 System.Globalization.GregorianCalendar 不支持字符串表示的 DateTime。”

为了解决这个问题,我实现了一个 WCF 消息检查器,我想在“AfterReceiveReply”方法中修改消息。在这里我想找出错误的日期并更正它,然后再发回给客户。

我会通过字符串操作(查找+替换)来进行替换。

但是,我无法将回复消息的内容作为字符串检索.. 我尝试通过“reply.GetReaderAtBodyContents()”执行此操作,然后获取“OuterXml”,但这最终会因与上述相同的错误而崩溃,因为它将它作为 XML 对象读取(并且它包含无效的日期)。

我也尝试了以下操作,但我也遇到了同样的问题(因为我们无法将无效的 XML 写入 XmlWrite 对象),它会引发与上述相同的错误。

MemoryStream ms = new MemoryStream();
XmlWriter xw = XmlWriter.Create(ms);
reply.WriteMessage(xw);
xw.Flush();
string body = Encoding.UTF8.GetString(ms.ToArray());
xw.Close();

Message 对象只接受“XmlWriter”或“XmlDictionaryWriter”来写入不同的流:

任何想法如何将回复消息的原始正文内容作为字符串对象获取,而不将其解析为 XML 文档?

提前致谢!

最好的问候

【问题讨论】:

  • 也许不是使用 XmlWriter,而是使用字符串编写器并以这种方式更正内容?我认为任何形式的 XML 解析器都会在验证时失败,你必须在解析之前修复它。只是我的 2 美分
  • 感谢您的评论。确实,但我无法将流写入字符串写入器。消息对象只接受一个 XmlWriter 对象。所以我想找到一种使用 StringWriter 而不是 XmlWriter 的方法(我用这个信息更新了我的问题)
  • XML 本身不了解“类型”。它不应该知道一个元素代表一个日期,除非你给它一个 XML Schema。当您执行 GetReaderAtBodyContents 时崩溃时,您可以共享堆栈跟踪吗?
  • 消息需要被视为不可变的。您需要使用Message.CreateMessage 重载之一创建一个新消息,并将其分配给reply(这就是为什么replyref
  • 我在最初的问题中添加了错误详细信息。使用“GetReaderAtBodyContents”并调用“ReadOuterXml”函数时,会引发日期时间异常。我尝试使用其他可用方法之一,例如“reader.ReadContentAsString()”,但这只会返回一个空字符串。

标签: c# wcf


【解决方案1】:

如果我们假设您从 GetReaderAtBodyContents 获得的 XmlDictionary 本身没有验证,那么这个忽略 FormatExceptions 的小心 XmlReader 可能足以让您的 dateTime 重写。

这里是实现:

void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object state) 
{
    // settings to ignore errors ...
    XmlReaderSettings settings = new XmlReaderSettings();
    settings.ValidationType = ValidationType.Schema;
    settings.ValidationEventHandler += (o,e) => { 
        if (e.Exception != null && !(e.Exception.InnerException is FormatException))
        {
          throw e.Exception;
        }
    }; // ignore formatexception errors

    var xmlrdr = XmlReader.Create(reply.GetReaderAtBodyContents(),settings);
    var ms = new MemoryStream();
    using(var wr = XmlWriter.Create(ms))
    while(xmlrdr.Read())
    {
        // very simple and naive xml copy
         switch(xmlrdr.NodeType) 
         {
             case XmlNodeType.Element:
                 wr.WriteStartElement(xmlrdr.Name);
             break;
             case XmlNodeType.Text:
                 var text = xmlrdr.ReadContentAsString();
                 // names of nodes that are a date
                 if (xmlrdr.Name == "date") 
                 {
                     DateTime dtm;
                     if (!DateTime.TryParse(text, out dtm)) 
                     {
                         // let's assume this is the only thing that can go wrong
                         text = text.Replace("24:00:00", "23:59:59");
                     }
                     wr.WriteString(text);
                     wr.WriteEndElement(); // yeah, well, let's gamble
                 } 
                 else
                 {
                     wr.WriteString(text);
                 }
             break;
             case XmlNodeType.EndElement:
                 wr.WriteEndElement();
             break;
             default:
               // Debug.Assert
             break;
         }
    }
    ms.Position=0;
    // create a new message for the next handler
    reply = System.ServiceModel.Channels.Message.CreateMessage(
       reply.Version, 
       reply.Headers.Action, 
       XmlReader.Create(ms));

}

【讨论】:

  • 感谢您的建议,但在“xmlrdr.Read()”部分仍然失败,并出现 FormatException。由于服务发回时间“24:00:00”的情况非常有限,我们决定捕获异常并保持原样(有人将手动处理这些失败的事件)。无论如何感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-21
  • 2016-02-17
  • 1970-01-01
  • 2013-06-01
  • 1970-01-01
  • 2012-03-26
  • 1970-01-01
相关资源
最近更新 更多