53505

MessageInspector message: “This message cannot support the operation because it has been copied.”

Here's the thing:

I have a business request that all WCF messages should have a specific header, for tracking and security reasons.

Anyway, I setup an implementation of MessageInspector on both the client and the service -- we control both ends so far -- and all worked well on the prototype phase.

However, today, something went awire and stopped working.

I redid the prototype from scratch and things works just fine. I'm loosing my marbles over it for the entire afternoon.

The relevant code is as follow:

public class DispatchEndpointBehavior : IEndpointBehavior { public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { var mi = new MessageInspector(); endpointDispatcher.DispatchRuntime.MessageInspectors.Add(mi); } // ... } public class DispatchMessageInspector : IDispatchMessageInspector { public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { var index = request.Headers.FindHeader("name", ""); if (index == -1) throw new MessageSecurityException("..."); var value = request.Headers.GetHeader<Guid>(index); // do something with the value return null; } // ... } public class ClientEndpointBehavior : IClientEndpointBehavior { public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { var mi = new ClientSecurityMessageInspector(); clientRuntime.MessageInspectors.Add(mi); } // ... } public class ClientSecurityMessageInspector : IClientMessageInspector { public object BeforeSendRequest(ref Message request, IClientChannel channel) { request.Headers.Add(MessageHeader.CreateHeader("name", "", Guid.NewGuid())); return null; } // ... }

Here is the configuration for the service:

<system.serviceModel> <services> <service behaviorConfiguration="Default" name="[Service Name]"> <endpoint address="" binding="basicHttpBinding" behaviorConfiguration="headerBehavior" contract="[Service Contract]"/> <endpoint address="mex" ... /> </service> </services> <behaviors> <serviceBehaviors> <behavior name="Default"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true" /> </behavior> </serviceBehaviors> <endpointBehaviors> <behavior name="headerBehavior"> <headerBehavior headerName="token" /> </behavior> </endpointBehaviors> </behaviors> <extensions> <behaviorExtensions> <add name="headerBehavior" type="[Implementation Type]" /> </behaviorExtensions> </extensions> </system.serviceModel>

Analogous, the client configuration is:

<system.serviceModel> <bindings> <basicHttpBinding> <binding name="[Service name]" ... > <readerQuotas ... /> <security mode="None"> <transport clientCredentialType="None" proxyCredentialType="None" realm=""/> <message clientCredentialType="UserName" algorithmSuite="Default" /> </security> </binding> </basicHttpBinding> </bindings> <client> <endpoint address="http://.../MyService.svc" binding="basicHttpBinding" bindingConfiguration="Default" contract="[Service Contract]" name="[Service Name]" behaviorConfiguration="headerBehavior" /> </client> <behaviors> <endpointBehaviors> <behavior name="headerBehavior"> <headerBehavior headerName="prosper-security-token" securityTokenValueService="[Implementation Type]" securityTokenValueGetterMethodName="[Method Name]" /> </behavior> </endpointBehaviors> </behaviors> <extensions> <behaviorExtensions> <add name="headerBehavior" type="[Implementation Type]" /> </behaviorExtensions> </extensions> </system.serviceModel>

<strong>Edited to Add</strong>

As requested, the exception stack trace is as follows:

(System.ServiceModel.FaultException) This message cannot support the operation because it has been copied. Server stack trace: at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) Exception rethrown at [0]: at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) at ConsoleApplication1.UserManagementService.IUserManagement.CreateUser(String username, String password, String[] systemCodes) at ConsoleApplication1.UserManagementService.UserManagementClient.CreateUser(String username, String password, String[] systemCodes) in C:\Users\Paulo Santos\Documents\Visual Studio 2008\Projects\PJonDevelopment\ConsoleApplication1\ConsoleApplication1\Service References\UserManagementService\Reference.cs at ConsoleApplication1.Program.Main(String[] args) in C:\Users\Paulo Santos\Documents\Visual Studio 2008\Projects\PJonDevelopment\ConsoleApplication1\ConsoleApplication1\Program.cs

<strong>Edited to Add</strong>

As told in one of the comments I've posted a prototype project that works here: ServiceModel.zip

I can't stress enough that the prototype works. The only thing I don't know is why I suddenly started getting this weird message. I don't copy the message and only deal with headers, and everywhere I search say that reading the message is a big no-no.

I dread the fact that with so many points to inspect, even replace, the entire message within <strong>WCF</strong> model, the architects designed with such an object that even if you look at it it goes poof.

If you're giving the opportunity to inspect, make a solid objec that can sustain the hardships of behing manipulated by anyone who wants to inspect it.

Answer1:

This is because a Message object can only be read once. Try using a buffer copy:

public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { MessageBuffer buffer = reply.CreateBufferedCopy(MaxMessageSize); Message requestCopy = buffer.CreateMessage(); var index = requestCopy.Headers.FindHeader("name", ""); if (index == -1) throw new MessageSecurityException("..."); var value = requestCopy.Headers.GetHeader<Guid>(index); // do something with the value return null; }

For more info, check out MSDN.

Answer2:

Use Greg Sansoms solution but replace the original message with a copy of the original message:

public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { MessageBuffer buffer = request.CreateBufferedCopy(MaxMessageSize); Message requestCopy = buffer.CreateMessage(); var index = requestCopy.Headers.FindHeader("name", ""); if (index == -1) throw new MessageSecurityException("..."); var value = requestCopy.Headers.GetHeader<Guid>(index); // do something with the value //make sure the orignal message is set to a value wich has not been copied nor read request = buffer.createMessage(); return null;

}

be sure to pass the request object by ref

Recommend

  • How to uploadfile using WCF 4.0 Template (REST)
  • Database migration adds new column Tenancy_Id when adding Tenant to User class
  • How to download a file with ajax window.location
  • Subsonic 3 Guid as PK always gives me 00000000-0000-0000-0000-000000000000
  • Synchronize threads on per-item base
  • How create UIHit YesNoNull?
  • ORA-01745 when executing insert
  • Outlook 2010 AddIn behaves weirdly when mail invoked from other office client
  • Multiple Insert statements in one connection
  • Generate serial numbers for each product key and validate them [closed]
  • Get rid of root element when serializing array
  • Minimal Repository implementation using Entity Framework
  • Attaching a file to an iCalendar
  • Access bindingsource column value
  • Random(staticSeed).Next() alternative that will never change implementation and is guaranteed consis
  • Zend Framework bassed projects
  • Are Richfaces and Primefaces compatible with each other?
  • Request response issues in biztalk
  • encoding issues with content in response from HttpWebRequest
  • Consuming a WCF service in a Java Client using wsHttpBinding
  • How can I replace the server in Web Component Tester
  • cordova is not defined - cordova.js has already been loaded :: Ionic
  • Salesforce Different WSDL files and when to use
  • Clear fused location provider's location for testing
  • Is there some graphical way to create my own configuration file on SonarLint?
  • Spring Cloud Microservice Architecture Confusion
  • Specifying Castle WCF Integration Facility Endpoint Behavior per Endpoint
  • azure media services - The request body is too large and exceeds the maximum permissible limit
  • Syntax for setting draggablecursor property in google maps api
  • Paperclip, set path outside of rails root folder
  • How can I send an e-mail from a vbs script
  • Why HTML5 Canvas with a larger size stretch a drawn line?
  • Spray.io: When (not) to use non-blocking route handling?
  • Is there a amazon webstore API for customers?
  • Modifying destination and filename of gulp-svg-sprite
  • GridView Sorting works once only
  • Circular dependency while pushing http interceptor
  • Is there a mandatory requirement to switch app.yaml?
  • Angular 2 constructor injection vs direct access
  • UserPrincipal.Current returns apppool on IIS