I am trying to validate a wc message's body and getting exception
"The call to the 'ValidateEndElement' method does not match a corresponding call to 'ValidateElement' method."
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 and reader settings are loaded in separate method
xmlReaderSettings = new XmlReaderSettings
{
ValidationType = ValidationType.S开发者_开发知识库chema,
Schemas = this.xmlSchemaSet,
ConformanceLevel = ConformanceLevel.Auto
};
xmlReaderSettings.ValidationEventHandler += (o, e) =>
{
if (e.Severity == XmlSeverityType.Error)
throw new ContractXmlSchemaValidationException(e.Message);
};
To create a wcf message ( where messageBody variable holds the 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"));
When you call GetReaderAtBodyContents() it will do exactly that: get a Reader for the whole message, starting at the Body contents. When you reach the end of your body content, xreader.Read() is continuing to read the rest of the message and hitting the close tag for the body. You need to modify your while loop to stop the reader from hitting this. Try this:
int startDepth = xreader.Depth;
while (xreader.Read())
{
if (xreader.Depth == startDepth && xreader.NodeType == XmlNodeType.EndElement)
{
break;
}
}
If there's a more elegant way of doing this, please share!
simply use: GetReaderAtBodyContents().ReadSubtree()
you will get a reader, which just reads the body.
EDIT:
I used it to validate my request. Because our awesome WebSphere sends just an "HTTP 500 Internal Server Error"-Error if the xml is invalid.
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);
}
In their answer, @masty missed case with self-closing tags. It should be:
int startDepth = xreader.Depth;
while (xreader.Read())
{
if (xreader.Depth == startDepth && (xreader.IsEmptyElement || xreader.NodeType == XmlNodeType.EndElement))
{
break;
}
}
精彩评论