【发布时间】:2016-03-17 13:35:15
【问题描述】:
(类似于this 问题,但在这种情况下最终不需要它)
我正在使用 IErrorHandler 实现——创建一个 FaultException 以便服务的客户端在发生未处理的异常时接收“漂亮”的错误。
我现在想在 request 消息中使用一个元素并在 FaultException 中将其退回,但我没有获胜。
我可以访问OperationContext.Current.RequestContext.RequestMessage,并且可以使用它的ToString() 查看完整的信封(包括我希望 FaultResponse 包含的“消息 ID”属性),但是我想“手动”反序列化请求消息,甚至只是将正文读取为 XML 以提取我正在寻找的请求属性。
但是我无法从消息中读取,因为(我假设)消息已经在 WCF 管道中的某个地方之前被读取过:
'该消息无法支持该操作,因为它已被复制'
这是我的 ProvideFault() 实现(我知道 XElement 解析甚至可能无法以这种形式工作——我现在不关注那个):
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);
} }
最好的方法是什么?
编辑:在 IErrorHandler 事件期间似乎无法读取 OperationContext 的请求消息——大概是因为它已经在 WCF 管道中读取过(因此创建了使用 MessageBuffer 的消息将不起作用)。接受的答案中描述了该问题的“解决方法”。
【问题讨论】:
-
我认为您的问题是您在进行复制之前正在读取故障对象。这是一个by ref流,所以如果你阅读它的内容,它会导致'消息不能支持操作,因为它已被复制'的错误。尝试先复制它,如下所示: MessageBuffer buffer = fault.CreateBufferedCopy(Int32.MaxValue);故障 = buffer.CreateMessage();消息 messageFault = buffer.CreateMessage();并改用 messageFault 对象
-
我在这里根本没有阅读故障(尽管在我的实际实现中,我正在记录它)——这是我试图处理的请求消息。对请求消息调用 CreateBufferedMessage() 也会导致引发“已复制”异常。
-
我明白了。究竟什么时候发生错误?
-
当我尝试阅读(或复制)请求消息时。在我上面的代码中,它是:req.GetReaderAtBodyContents()