简体   繁体   English

错误“此消息不支持该操作,因为它已被读取”

[英]Error “This message cannot support the operation because it has been read”

I have the same problem that is listed in the following thread. 我遇到了以下线程中列出的相同问题。

WSDL first WCF server where client does not send SOAPAction WSDL第一个WCF服务器,其中客户端不发送SOAPAction

I performed the steps that are listed in the same thread (also shown below) 我执行了同一个线程中列出的步骤(也显示在下面)

1) Download the Microsoft WCF examples. 1)下载Microsoft WCF示例。 Add the following files to your project from WF_WCF_Samples\\WCF\\Extensibility\\Interop\\RouteByBody\\CS\\service 从WF_WCF_Samples \\ WCF \\ Extensibility \\ Interop \\ RouteByBody \\ CS \\ service将以下文件添加到项目中

DispatchByBodyOperationSelector.cs DispatchByBodyOperationSelector.cs

DispatchByBodyBehaviorAttribute.cs DispatchByBodyBehaviorAttribute.cs

2) Add the following attributes to your interface (next to your ServiceContract) 2)将以下属性添加到您的界面(ServiceContract旁边)

XmlSerializerFormat

DispatchByBodyBehavior

3) Add the following to your service interface 3)将以下内容添加到服务界面

[OperationContract(Action = "")]

public void DoNothing()
{
}

4) For my service the WrapperName and Wrappernamespace are null for all messages. 4)对于我的服务,WrapperName和Wrappernamespace对于所有消息都为空。 I had to go into DispatchByBodyBehaviorAttribute and edit ApplyDispatchBehavior() to add the following lines to check for this: 我不得不进入DispatchByBodyBehaviorAttribute并编辑ApplyDispatchBehavior()以添加以下行来检查:

 if (qname.IsEmpty) {
     qname = new XmlQualifiedName(operationDescription.Messages[0].Body.Parts[0].Name, operationDescription.Messages[0].Body.Parts[0].Namespace);
 }

Now, I am getting an error message "This message cannot support the operation because it has been read". 现在,我收到一条错误消息“此消息无法支持该操作,因为它已被读取”。 I turned the tracing on and captured the stack trace (below). 我打开了跟踪并捕获了堆栈跟踪(下图)。 If anyone has any idea on how this can be resolved, I appreciate if you could post some comments. 如果有人知道如何解决这个问题,我很感激您是否可以发表一些评论。 Thanks for any help! 谢谢你的帮助!

at System.ServiceModel.Channels.Message.GetReaderAtBodyContents()
at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeBodyContents(Message message, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeRequest(Message message, Object[] parameters)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.DeserializeInputs(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(RequestContext request, Boolean cleanThread, OperationContext currentOperationContext)
at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(RequestContext request, OperationContext currentOperationContext)
at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(IAsyncResult result)
at System.ServiceModel.Dispatcher.ChannelHandler.OnAsyncReceiveComplete(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.Runtime.InputQueue`1.AsyncQueueReader.Set(Item item)
at System.Runtime.InputQueue`1.EnqueueAndDispatch(Item item, Boolean canDispatchOnThisThread)
at System.Runtime.InputQueue`1.EnqueueAndDispatch(T item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue(QueueItemType item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived(HttpRequestContext context, Action callback)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContextCore(IAsyncResult result)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContext(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.ListenerAsyncResult.WaitCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
</StackTrace>


class DispatchByBodyElementOperationSelector : IDispatchOperationSelector
{
    Dictionary<XmlQualifiedName, string> dispatchDictionary;

    public DispatchByBodyElementOperationSelector(Dictionary<XmlQualifiedName, string> dispatchDictionary)
    {
        this.dispatchDictionary = dispatchDictionary;            
    }

    #region IDispatchOperationSelector Members

    private Message CreateMessageCopy(Message message, XmlDictionaryReader body)
    {
        //Message copy = Message.CreateMessage(message.Version, message.Headers.Action, body);
        //copy.Headers.CopyHeaderFrom(message, 0);
        //copy.Properties.CopyProperties(message.Properties);
        //return copy;    

        MessageBuffer buffer = message.CreateBufferedCopy(Int32.MaxValue);
        Message copy = buffer.CreateMessage();
        buffer.Close();
        copy.Headers.CopyHeaderFrom(message, 0);
        copy.Properties.CopyProperties(message.Properties);

        return copy;
    }

    public string SelectOperation(ref System.ServiceModel.Channels.Message message)
    {
        XmlDictionaryReader bodyReader = message.GetReaderAtBodyContents();

        XmlQualifiedName lookupQName = new XmlQualifiedName(bodyReader.LocalName, bodyReader.NamespaceURI);
        message = CreateMessageCopy(message,bodyReader);
        if (dispatchDictionary.ContainsKey(lookupQName))
        {
            return dispatchDictionary[lookupQName];
        }
        else
        {
            return null;
        }
    }

    #endregion
}

[AttributeUsage(AttributeTargets.Class|AttributeTargets.Interface)]
sealed class DispatchByBodyBehaviorAttribute : Attribute, IContractBehavior
{
    #region IContractBehavior Members

    public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
        // no binding parameters need to be set here
        return;
    }

    public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
    {
        // this is a dispatch-side behavior which doesn't require
        // any action on the client
        return;
    }

    public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)
    {
        // We iterate over the operation descriptions in the contract and
        // record the QName of the request body child element and corresponding operation name
        // to the dictionary to be used for dispatch 
        Dictionary<XmlQualifiedName,string> dispatchDictionary = new Dictionary<XmlQualifiedName,string>();
        foreach( OperationDescription operationDescription in contractDescription.Operations )
        {
            XmlQualifiedName qname =
                new XmlQualifiedName(operationDescription.Messages[0].Body.WrapperName, operationDescription.Messages[0].Body.WrapperNamespace);




            if (qname.IsEmpty)
            {
                qname = new XmlQualifiedName(operationDescription.Messages[0].Body.Parts[0].Name, operationDescription.Messages[0].Body.Parts[0].Namespace);
            }

            dispatchDictionary.Add(qname, operationDescription.Name);                
        }

        // Lastly, we create and assign and instance of our operation selector that
        // gets the dispatch dictionary we've just created.
        dispatchRuntime.OperationSelector = 
            new DispatchByBodyElementOperationSelector(dispatchDictionary);
    }

    public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
    {
        // 
    }

    #endregion
}

You should use MessageBuffer.CreateMessage : 您应该使用MessageBuffer.CreateMessage

The body of a Message instance can only be consumed or written once. Message实例的主体只能被使用或写入一次。 If you wish to consume a Message instance more than once, you should use the MessageBuffer class to completely store an entire Message instance into memory. 如果您希望多次使用Message实例,则应使用MessageBuffer类将整个Message实例完全存储到内存中。

http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.messagebuffer.aspx http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.messagebuffer.aspx

Code from my current project: 我当前项目的代码:

public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
    MessageBuffer buffer = reply.CreateBufferedCopy(Int32.MaxValue);
    reply = buffer.CreateMessage();
    Message m = buffer.CreateMessage();
    LogMessage(m, " Response => ");
}

Add ref for Message param and return new message. Message param添加ref并返回新消息。

 private Message CreateMessageCopy(ref Message message, XmlDictionaryReader body)
{
...
   message = buffer.CreateMessage();

I had a very similar issue, using code from WCF Samples (RouteByBody to be precise) as well, and was able to solve it in a different way so I'll post it here in case it helps anybody. 我有一个非常类似的问题,使用WCF Samples中的代码(精确地说是RouteByBody),并且能够以不同的方式解决它,所以我会在这里发布它,以防它对任何人有帮助。

Situation: The client application (consumer) would work in Release , however, when the debugger was attached it would always fail with the error "This message cannot support the operation because it has been read" . 情况:客户端应用程序(使用者)将在Release中工作,但是,当附加调试器时,它将始终失败,并显示错误“此消息因为已被读取而无法支持该操作”

After much tracing and logging WCF messages, the only solution that worked for me turned out to be so simple: 经过大量跟踪和记录WCF消息之后,唯一对我有用的解决方案就是如此简单:

My Service was hosted on IIS, and with debug="true" in the <compilation> section of the web.config. 我的服务托管在IIS上,并在web.config的<compilation>部分中使用debug="true"

Changing it to debug="false" on the service fixed all my problems. 在服务上将它更改为debug="false"修复了我的所有问题。

Dmitry Harnitski's answer does not work if you are debugging the service (It will give you a "This message cannot support the operation because it has been copied." error.) 如果你正在调试服务,Dmitry Harnitski的答案不起作用(它会给你一个“这条消息不能支持操作,因为它已被复制。”错误。)

This works even in debug mode: 即使在调试模式下也可以:

XmlDictionaryReader GetReader(ref Message message)
{
    MessageBuffer buffer = message.CreateBufferedCopy(Int32.MaxValue);
    message = buffer.CreateMessage();
    newMessage = buffer.CreateMessage();
    XmlDictionaryReader rv = buffer.CreateMessage().GetReaderAtBodyContents();
    buffer.Close();
    return rv;
}

static System.ServiceModel.Channels.Message newMessage = null;
static System.ServiceModel.Channels.Message lastMessage = null;

public string SelectOperation(ref System.ServiceModel.Channels.Message message)
{
    try
    {
        if(message == lastMessage)
            message = newMessage;

        XmlDictionaryReader bodyReader = GetReader(ref message);

        lastMessage = message;

        XmlQualifiedName lookupQName = new XmlQualifiedName(bodyReader.LocalName, bodyReader.NamespaceURI);
        if (dispatchDictionary.ContainsKey(lookupQName))
        {
            return dispatchDictionary[lookupQName];
        }
        else
        {
            return null;
        }
    }
    catch(Exception ex)
    {
        throw ex;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 WCF:此消息无法支持该操作,因为它已被复制 - WCF : This message cannot support the operation because it has been copied 此消息不支持该操作,因为它已被复制 - This message cannot support the operation because it has been copied MessageInspector消息:“此消息不支持该操作,因为它已被复制。” - MessageInspector message: “This message cannot support the operation because it has been copied.” WCF服务Wsdl错误:操作引用了已经导出的消息元素 - WCF Service Wsdl Error: operation references a message element that has already been exported WCF服务返回400错误:邮件正文为空,因此无法读取 - WCF Service returning 400 error: The body of the message cannot be read because it is empty 通信对象不能用于通信,因为它已被中止 - The communication object cannot be used for communication because it has been Aborted 访问我的WCF服务的WSDL时出错:“...操作引用已从...导出的消息元素...” - Error when accessing access the WSDL of my WCF services: “The … operation references a message element … that has already been exported from the …” 无论我尝试什么:由于线程退出或应用程序请求,I/O 操作已中止 - No matter what I try: The I/O operation has been aborted because of either a thread exit or an application request 由于 WCF 中的线程退出或应用程序请求,I/O 操作已中止 - The I/O operation has been aborted because of either a thread exit or an application request in WCF 由于线程退出或应用程序请求,I / O操作已中止 - The I/O operation has been aborted because of either a thread exit or an application request
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM