Подтвердить что ты не робот

Ошибка "Это сообщение не может поддерживать операцию, потому что оно было прочитано"

У меня та же проблема, которая указана в следующем потоке.

WSDL первый сервер WCF, где клиент не отправляет SOAPAction

Я выполнил шаги, перечисленные в том же потоке (также показано ниже)

1) Загрузите примеры Microsoft WCF. Добавьте в свой проект следующие файлы из WF_WCF_Samples\WCF\Extensibility\Interop\RouteByBody\CS\service

DispatchByBodyOperationSelector.cs

DispatchByBodyBehaviorAttribute.cs

2) Добавьте в свой интерфейс (рядом с вашим ServiceContract) следующие атрибуты

XmlSerializerFormat

DispatchByBodyBehavior

3) Добавьте в свой сервисный интерфейс следующее:

[OperationContract(Action = "")]

public void DoNothing()
{
}

4) Для моей службы WrapperName и Wrappernamespace являются пустыми для всех сообщений. Мне пришлось войти в DispatchByBodyBehaviorAttribute и изменить ApplyDispatchBehavior(), чтобы добавить следующие строки, чтобы проверить это:

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

Теперь я получаю сообщение об ошибке "Это сообщение не может поддерживать операцию, потому что оно было прочитано". Я включил трассировку и захватил трассировку стека (ниже). Если кто-нибудь имеет представление о том, как это можно решить, я ценю, если вы можете опубликовать некоторые комментарии. Спасибо за любую помощь!

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
}
4b9b3361

Ответ 1

Вы должны использовать MessageBuffer.CreateMessage:

Тело экземпляра Message может использоваться только один раз или записываться один раз. Если вы хотите использовать экземпляр Message более одного раза, вы должны используйте класс MessageBuffer для полного хранения целого Messageэкземпляр в память.

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

Код из моего текущего проекта:

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 => ");
}

Добавить ref для Message param и вернуть новое сообщение.

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

Ответ 2

У меня была очень похожая проблема, используя код из WCF Samples (RouteByBody, если быть точным), и я смог решить ее по-другому, поэтому я отправлю его здесь, если это поможет кому-либо.

Ситуация: Клиентское приложение (потребитель) будет работать в Release, однако при подключении отладчика он всегда терпит неудачу с ошибкой "Это сообщение не может поддерживать операцию, потому что оно было прочитано".

После много трассировки и регистрации WCF-сообщений единственное решение, которое сработало для меня, оказалось настолько простым:

Моя служба была размещена в IIS и debug="true" в разделе <compilation> в файле web.config.

Сменив его на debug="false" на службе, все мои проблемы были исправлены.

Ответ 3

Ответ Дмитрия Харницкого не работает, если вы отлаживаете службу (она даст вам сообщение "Это сообщение не может поддерживать операцию, потому что оно было скопировано" ).

Это работает даже в режиме отладки:

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;
    }
}