(Similar to this question, however it ended up not being needed in that case)
I'm using an IErrorHandler implementation -- creating a FaultException so that clients to the service receive 'pretty' errors in the event of unhandled exceptions.
I'd now like to use an element in the request message and bounce it back in the FaultException and I'm not winning.
I can access the OperationContext.Current.RequestContext.RequestMessage
, and can see the full envelope (including the 'message ID' property I want the FaultResponse to contain) using its ToString()
, however I'd like to either 'manually' deserialize the request Message, or even just read the body as XML in order to extract the request property I'm looking for.
However I'm not able to read from the message, as (I assume) the Message has already been read somewhere previous in the WCF pipeline:
'The message cannot support the operation because it has been copied'
Here's my ProvideFault()
implementation (I'm aware the XElement parsing may not even work in this form -- I'm not focusing on that now):
public void ProvideFault(Exception error, MessageVersion version, ref Message fault) {
if (error is FaultException)
{
// Let WCF handle
}
else
{
// Extract the 'messageID' element from the request message
var req = OperationContext.Current.RequestContext.RequestMessage;
// Throws the 'has been copied' exception
XElement body = XElement.Parse(XElement.ReadFrom(req.GetReaderAtBodyContents()).ToString());
var msgId = (string)body.Descendants("messageID").FirstOrDefault();
var err = new FaultException<Foo>(new Foo
{
MessageID = msgId
}, "Server error");
var msgFault = err.CreateMessageFault();
fault = Message.CreateMessage(
version,
msgFault,
null);
} }
What's the best way to do this?
EDIT: It doesn't look like it's possible to read the OperationContext's Request Message during the IErrorHandler events -- presumably because it's already been read earlier in the WCF pipeline (so creating a copy of the message using the MessageBuffer will not work). A 'workaround' to the problem is described in the accepted answer.