2012-06-14 12 views
14

Mam ten sam problem, który jest wymieniony w następującym wątku.Błąd "Ten komunikat nie może obsłużyć operacji, ponieważ został odczytany"

WSDL first WCF server where client does not send SOAPAction

że przeprowadza się etapy, które są wymienione w tym samym wątku (także pokazany poniżej)

1) Pobierz przykłady Microsoft WCF. Dodaj następujące pliki do projektu z WF_WCF_Samples \ WCF \ Rozszerzalność \ Interop \ RouteByBody \ CS \ służby

DispatchByBodyOperationSelector.cs

DispatchByBodyBehaviorAttribute.cs

2) Dodaje się następujące atrybuty do interfejsu (obok ServiceContract)

XmlSerializerFormat 

DispatchByBodyBehavior 

3) Dodaj poniższe do interfejsu serwisowego

[OperationContract(Action = "")] 

public void DoNothing() 
{ 
} 

4) Dla mojej usługi WrapperName i Wrappernamesspace są puste dla wszystkich wiadomości. Miałem iść do DispatchByBodyBehaviorAttribute i edytować ApplyDispatchBehavior(), aby dodać następujące linie do sprawdzenia to:

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

Teraz otrzymuję komunikat o błędzie „Ta wiadomość nie może wspierać działania, ponieważ został przeczytany”. Włączyłem śledzenie i przechwyciłem ślad stosu (poniżej). Jeśli ktoś ma pojęcie, jak można to rozwiązać, doceniam, czy mógłbyś opublikować komentarze. Dzięki za pomoc!

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 
} 

Odpowiedz

28

Należy użyć MessageBuffer.CreateMessage:

Ciało instancji Message mogą być spożywane lub napisane tylko raz. Jeśli chcesz użyć instancji komunikatu więcej niż jeden raz, powinieneś użyć klasy MessageBuffer, aby całkowicie zapisać całą instancję Message w pamięci.

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

Kod z moim obecnym projekcie:

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

Dodaj ref dla Message param i powrócić nową wiadomość.

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

Dziękujemy za opublikowanie kodu. W moim scenariuszu ponownie używam klas z pobierania próbek WCF. Próbowałem umieścić kod MessageBuffer w metodzie CreateMessageCopy, jak opisano poniżej, ale nie działa on dla mnie. – Jyina

+0

Mam edytowane moje oryginalne pytanie i opublikowałem dwie klasy, które używam z próbek WCF. Skomentowałem istniejący kod w CreateMessageCopy() i próbowałem utworzyć wiadomość za pomocą MessageBuffer. Kiedy uruchamiam mojego klienta, nie działa on na linii. Bufor MessageBuffer = message.CreateBufferedCopy (Int32.MaxValue); – Jyina

+0

Wygląda na to, że wiadomość została już przeczytana, zanim trafi w tę linię. Nie jestem pewien, gdzie powinienem umieścić kod MessageBuffer. Jakieś pomysły? Dzięki! – Jyina

4

miałem bardzo podobny problem, używając kodu z próbek WCF (RouteByBody być precyzyjne), jak również, i był w stanie go rozwiązać w inny sposób, więc będę pisać tutaj w przypadku pomaga nikomu .

Sytuacja: Aplikacja kliencka (konsument) będzie działać w Release jednak, kiedy debugger został dołączony będzie zawsze niepowodzeniem z błędem „Ta wiadomość nie może wspierać działania, ponieważ została odczytana”.

Po długich komunikatów śledzenia i rejestrowania WCF, jedynym rozwiązaniem, który pracował dla mnie okazała się tak prosta:

Moje życzenie zostało gospodarzem na IIS, a także z debug="true" w sekcji <compilation> w web.config.

Zmiana na debug="false"na usługę naprawiono wszystkie moje problemy.

+0

Ale jak będziemy mogli debugować? –

+0

To działało dla nas. Odłączenie debuggera od procesu umożliwia komunikaty. Dołączenie debuggera spowodowałoby wyjątek InvalidOperationException "Komunikat nie może obsłużyć tej operacji, ponieważ został odczytany". Co więcej, błąd pojawia się tylko wtedy, gdy dla usługi używana jest opcja "DispatchByBodyBehavior". – knittl

+0

, który działał dobrze !!! Kocham was, mężczyźni – MirlvsMaximvs

2

odpowiedź Dmitrija Harnitski nie działa, jeśli debugowanie usługę (będzie ona daje „Ta wiadomość nie może wspierać działania, ponieważ został skopiowany.” Błąd.)

To działa nawet w trybie debugowania:

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; 
    } 
} 
Powiązane problemy