验证消息体时出错
本文关键字:出错 消息 验证 | 更新日期: 2023-09-27 17:54:47
我正在尝试验证wc消息的主体并获得异常
"对'ValidateEndElement'方法的调用不匹配对'ValidateElement'方法的相应调用。"
using (MessageBuffer messageBuffer = message.CreateBufferedCopy(int.MaxValue))
{
Message copiedMessage = messageBuffer.CreateMessage();
using (var xreader = XmlReader.Create(
copiedMessage.GetReaderAtBodyContents(), xmlReaderSettings))
{
while (xreader.Read()) ;
}
message = messageBuffer.CreateMessage();
}
XmlSchemaSet和reader设置在单独的方法中加载
xmlReaderSettings = new XmlReaderSettings
{
ValidationType = ValidationType.Schema,
Schemas = this.xmlSchemaSet,
ConformanceLevel = ConformanceLevel.Auto
};
xmlReaderSettings.ValidationEventHandler += (o, e) =>
{
if (e.Severity == XmlSeverityType.Error)
throw new ContractXmlSchemaValidationException(e.Message);
};
创建wcf消息(其中messageBody变量保存body xml)
Message msg = null;
var reader = XmlReader.Create(new StringReader(messageBody));
msg = Message.CreateMessage(MessageVersion.Soap12, "http://mysoapAction", reader);
msg.Headers.Add(MessageHeader.CreateHeader("To", "http://schemas.microsoft.com/ws/2005/05/addressing/none", "http://localhost/Service/Service1.svc"));
直接使用:GetReaderAtBodyContents().ReadSubtree()
你会得到一个阅读器,它只读取正文。
我用它验证我的请求。因为我们的webspherewebspherewebspherewebspherewebspherewebspherewebspherewebsphereserver Error (HTTP 500 Internal Server Error)——如果xml是无效的,就会出现错误。
var settings = new XmlReaderSettings();
settings.Schemas.Add(_schemas);
settings.CloseInput = true;
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags = XmlSchemaValidationFlags.AllowXmlAttributes
| XmlSchemaValidationFlags.ProcessInlineSchema
| XmlSchemaValidationFlags.ReportValidationWarnings;
settings.ValidationEventHandler += ValidationEventHandler;
using (XmlDictionaryReader bodyReader = message.GetReaderAtBodyContents())
using (XmlReader documentReader = XmlReader.Create(bodyReader.ReadSubtree(), settings))
{
documentReader.MoveToContent();
using (var memory = new MemoryStream())
//copy & validate in one step :)
using (XmlWriter writer = XmlWriter.Create(memory))
{
writer.WriteNode(documentReader, false);
writer.Flush();
}
#if DEBUG
memory.Seek(0, SeekOrigin.Begin);
string xml = new StreamReader(memory).ReadToEnd();
#endif
memory.Seek(0, SeekOrigin.Begin);
message = Message.CreateMessage(message.Version, null, XmlReader.Create(memory));
message.Headers.CopyHeadersFrom(message);
}
当您调用GetReaderAtBodyContents()时,它将完全这样做:获取整个消息的Reader,从Body内容开始。当您到达正文内容的末尾时,xreader.Read()将继续读取消息的其余部分,并为正文点击结束标记。你需要修改你的while循环来阻止读者点击这个。试试这个:
int startDepth = xreader.Depth;
while (xreader.Read())
{
if (xreader.Depth == startDepth && xreader.NodeType == XmlNodeType.EndElement)
{
break;
}
}
如果有更优雅的方法,请分享!
在他们的回答中,@masty忽略了自动关闭标签的大小写。应该是:
int startDepth = xreader.Depth;
while (xreader.Read())
{
if (xreader.Depth == startDepth && (xreader.IsEmptyElement || xreader.NodeType == XmlNodeType.EndElement))
{
break;
}
}