This message cannot support the operation because it has been copied


Has this error message happened to you? It’s because the lifetime of a message only lasts for one use. Once you’ve looked at the contents of a message, or copied the contents somewhere, you can’t read the message again. This is a common problem encountered when people are trying to write a message inspector. Since you’re expected to pass the message along after you’re done inspecting it, it’s quite likely that you’ll need to make a new copy of the message. If you don’t make a copy of the message, then the next person will have nothing to read.

This means that your message inspector code should look something like this:

public void AfterReceiveReply(ref Message reply, object correlationState)
{
MessageBuffer buffer = reply.CreateBufferedCopy(MaxMessageSize);

// Do something with the copied message reply = buffer.CreateMessage(); buffer.Close(); }
Comments (12)

  1. hah says:

    How about "Please try again in 0 seconds" Classic.

  2. Just to be clear – this is only relevant when *reading* a message, right?

    I have a MessageInspector that adds a header before sending, and I haven’t noticed any problems. Reading that header later did "burn" the message, as you’ve noted.

    If this is such a common pattern, why is it not built into the framework? If 90% of all AfterReceiveReply implementations will have to include this boilerplate code, shouldn’t the case be optimized for them, and allow NOT passing the message on through some explicit markup or command?

  3. Nicholas Allen says:

    We don’t automatically copy the message because that’s an expensive operation and we don’t like doing expensive things behind your back.  Copying the message for you might require taking up gobs of memory or silently buffering streams.  Instead of explaining why you get this error message, we’d have to explain why your performance is so bad.  That’s much harder to diagnose just from hearing the symptoms.

  4. Fair enough about the explicitness, but the current implementation – having the Message passed explicitly as ‘ref’ – just screams "you can modify the Message object and it will stick". Any way to make it more obvious from the code itself – not just the documentation – that this is what’s happening?

  5. Nicholas Allen says:

    It would have been nice to be clearer here.  The name MessageInspector is confusing because this extensibility point does a whole lot more than let you "inspect" messages, which is why we can’t do much to automate the process.  The problem is general to all users of the Message class though.  Custom channel authors have to deal with the same issue.  We might be able to create a new message implementation in the future to solve this.

  6. How about changing the the name of the incoming Message parameter from "reply" to "singleUserReplyObject", or something less atrocious but which still conveys the fact that once touched this object is dead?

  7. And another question (sorry for the harassment): I noticed that we’re copying the message into a buffer, and then recreating the message from that buffer. My question is about your " // Do something with the copied message" comment – you mean with the original message, right?

  8. Nicholas Allen says:

    "Do something with the copied message" means do something with the copy in the message buffer.  We can’t do anything further with the original message, it’s already been copied.  Unlike a message, you can use a message buffer more than once.

  9. But the buffer is just that – an untyped byte buffer. To do something with it, I have to creat a temporary Message from the buffer, right?

    I’m trying to think of a good balance here between explicitness (having the user aware of the buffer copy and the Message creation step) and being convenient/non-verbose (not requiring two distinct steps for a common operation like creating a copy of a message)

  10. I’ve mentioned that messages have a definite lifecycle without ever mentioning what the lifecycle represents….

  11. I haven’t forgotten about the goal to put together a table of contents for all of these articles. The

  12. How do I use a field in the message to answer an authorization request in ServiceAuthorizationManager?