Reputation: 1060
I'm calling a SOAP service using a WCF client in .NET. It sometimes happens that the SOAP service is sending back a response that can't be serialized to the .NET objects. The main culprit here is a datetime field in which they are sending back "24:00:00" instead of "00:00:00".
In this case, we get back the following error: "The DateTime represented by the string is not supported in calendar System.Globalization.GregorianCalendar."
In order to solve this, I implemented a WCF Message Inspector, where I want to modify the message in the "AfterReceiveReply" method. Here I would like to find the incorrect date and correct it, before sending it back to the client.
I would do the replacement through string manipulation (find + replace).
However, I am not able to retrieve the content of the reply message as a string.. I tried doing this through "reply.GetReaderAtBodyContents()" and then get the "OuterXml", but this ends up crashing with the same error as above, since it's reading it as an XML object (and it contains an invalid date).
I also tried following, but there I have the same issue as well (since we can't write invalid XML to the XmlWrite object), it throws the same error as above.
MemoryStream ms = new MemoryStream();
XmlWriter xw = XmlWriter.Create(ms);
reply.WriteMessage(xw);
xw.Flush();
string body = Encoding.UTF8.GetString(ms.ToArray());
xw.Close();
The Message object only accepts an "XmlWriter" or "XmlDictionaryWriter" to write to a different stream:
Any ideas how I can get the raw body content of the reply message as a string object, without parsing it as an XML Document?
Thanks in advance!
Best regards
Upvotes: 0
Views: 945
Reputation: 42414
If we assume the XmlDictionary that you get from GetReaderAtBodyContents isn't validating by itself, maybe this careful XmlReader that ignores FormatExceptions might be enough to get your dateTime rewritten.
Here is the implementation:
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));
}
Upvotes: 1