c# - WCF 消息检查器 - 修改无效的 XML SOAP 响应
问题描述
我在 .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 文档?
提前致谢!
此致
解决方案
如果我们假设您从 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));
}
推荐阅读
- protobuf-c - 通过 vcpkg 安装旧版本的 protobuf
- tableau-api - 如何在 Tableau 中为轴刻度使用范围而不是单个值?
- mysql - 从 SQL 中输入的日期查找最近的日期,两种方式
- javascript - 如何选择()元素背景颜色?
- c# - 如何将数字从十进制传送到整个字节数组
- bash - 如何重新运行脚本?
- angular - ViewEncapsulation.ShadowDom 与 ViewEncapsulation.Native
- javascript - i 在 JavaScript for 循环中不递增
- python - 如何序列化包含原始 JSON 的模型字段?
- javascript - 单击按钮将数组值加载到变量中