Welcome to Windows Communication Foundation (WCF)
Top Tasks :

WCF Team Bloggers

Browse by Tags

All Tags » Messages and Encodings   (RSS)

  • Correlating Message Identifiers

    I'm trying to send a correlated exchange of messages using the MessageId to perform the correlation. The MessageId appears on the first message but it looks like I have to copy it around manually because it's not on the reply messages. Why isn't this working? Let's look at a simple message exchange using MessageId to see what is happening here. I'll use the WSHttpBinding to trigger the addition of a MessageId and a simple service contract with one operation. The operation has a request-reply exchange pattern over HTTP so we expect simple correlation between the request and reply messages. [ServiceContract] public interface Service { [OperationContract] string Operation( string parameter); } Inside the implementation for my operation, I'll print out the MessageId that's in OperationContext.Current.IncomingMessageHeaders. On the client side, I'll construct an OperationContextScope so that I get access to that same header on the return message. using ( new OperationContextScope((IContextChannel)client.InnerChannel)) { client.Operation(parameter); Console.WriteLine( "id: " + OperationContext.Current.IncomingMessageHeaders.MessageId); } As the questioner described, I get a MessageId header on the server that looks like urn:uuid:67a1b220-aaf2-4cbb-9273-92fb2af1d035 but I don't get any MessageId back in the response. The MessageId header only applies to the first message in the sequence. Subsequent messages are sent to the ReplyTo address of the endpoint and with the RelatesTo header set to the original MessageId. Let's put a second debug statement on the client and server. Console.WriteLine( "re: " + OperationContext.Current.IncomingMessageHeaders.RelatesTo); We see that on the first message, the RelatesTo header is not set. On the response message, the RelatesTo header is set to my original MessageId. The solution to the question is that the automatic handling works by linking the MessageId header to RelatesTo in successive messages. You should be looking at the RelatesTo header for your correlation. Next time: Which Client Credential Does TransportWithMessageCredential Use? Read More...
  • You Must Understand This

    WCF allows you to customize the collection of message headers sent with a request, including defining your own custom headers. Message receivers tend to be very loose about the messages that they accept and they typically will silently ignore any headers that they don't understand. However, this is a bad thing to have happen when your custom message header is intended to change the semantics of an operation. The solution to this problem in SOAP is the mustUnderstand attribute. The mustUnderstand attribute is a qualifying tag to the message header stating that the receiver must either successfully process the message header or fail the operation. Use of the mustUnderstand attribute can help you when versioning your service. After a version upgrade, there is a potential for miscommunication between clients and servers that have different versions. If you add new headers to your messages, such that calls will still complete for an older version but the meaning of those calls has changed, then marking the relevant message headers as mustUnderstand will change this soft failure to a hard failure. Making the call fail makes it much easier to detect the problem than if the result is silent data corruption. You can control the mustUnderstand attribute for your messages through the MessageHeader attribute in your MessageContract on the client. The contract shown here is based on one automatically generated by svcutil.exe. [DebuggerStepThrough()] [GeneratedCode( "System.ServiceModel" , "3.0.0.0" )] [MessageContract(WrapperName = "MyMessageContract" )] public partial class MyMessageContract { [MessageHeader(Namespace = "http://tempuri.org/" , MustUnderstand = true )] public string importantHeader; [MessageBodyMember(Namespace = "http://tempuri.org/" , Order = 0)] public string body; public MyMessageContract() { } public MyMessageContract( string importantHeader, string body) { this .importantHeader = importantHeader; this .body = body; } } This causes the generated message to have the mustUnderstand attribute be set. < s:Envelope xmlns:s ="http://schemas.xmlsoap.org/soap/envelope/" > < s:Header > < h:importantHeader s:mustUnderstand ="1" xmlns:h ="http://tempuri.org/" > header </ h:importantHeader > </ s:Header > < s:Body > < MyMessageContract xmlns ="http://tempuri.org/" > < body > body </ body > </ MyMessageContract > </ s:Body > </ s:Envelope > Next time: Stream Upgrades, Part 1 Read More...
  • Making One-Way HTTP Requests, Part 3

    We’ve been looking at the mystery of why one-way messages stop working when you turn on the POX message encoder . The clues to solving this mystery are that: The service does not change its behavior at all when the message encoder is changed. The failure happens with the POX message encoder but not the text message encoder. The exception we get is that the OneWay channel unexpectedly got a message back. The solution to this mystery is back in the original description of why we added the POX message encoder in the first place . One of the properties of the standard message encoders is that they only surface up messages that have a non-empty message body. In the POX case, you sometimes want to process messages based solely on the contents of the HTTP headers and you don’t actually care at all about the message body. The POX message encoder replaces the original HttpMappingMode feature that controls whether we turn empty HTTP message into null SOAP messages or empty SOAP messages. The standard text message encoder returns a null SOAP message. The POX message encoder returns an empty SOAP message so that you can still look at the HTTP headers that were included. Of course, now a failure is inevitable because the OneWay channel is looking for a null SOAP message to come back. When you’re using the POX message encoder, it gets back an empty SOAP message rather than a null SOAP message and assumes that something has gone wrong with the one-way protocol. Fixing this is a little tricky. You need to somehow cause the SOAP message to disappear before it hits the OneWay channel. However, you should only eat the response when the message was successfully handed off because you want to report back any server errors. My idea is to key this off of the status code in the HTTP response. If a message comes back and it has the 202 Accepted status code, pretend like it was really a null SOAP message. Otherwise, pass the message along unchanged. If you're interested in supporting this scenario, you might want to do some other variation depending on how your server behaves. Message FilterMessage(Message reply) { if (reply == null ) { return null ; } HttpResponseMessageProperty properties = (HttpResponseMessageProperty)reply.Properties[HttpResponseMessageProperty.Name]; if (properties != null && properties.StatusCode == HttpStatusCode.Accepted) { return null ; } return reply; } I’ll write up a channel for Monday that you can stick in your channel stack to apply this filter. Read More...
  • Making One-Way HTTP Requests, Part 2

    The article yesterday left off by stating that while the test program works fine with the messaging defaults, things break when we switch to the POX message encoder. Today and tomorrow, we'll look at what goes wrong, why, and how to fix it. To switch to the POX message encoder, I'm going to change the MessageVersion setting of the normal text message encoder that is already in my binding. You can do this by adding the following line to the test client after creating the custom binding. binding.Elements.Find<MessageEncodingBindingElement>().MessageVersion = MessageVersion.None; Now, when I run the test program, I see the correct and expected output on the server. HTTP/1.1 POST http://localhost:8000/ ::1:1147 --> ::1:8000 [Headers] Connection: Keep-Alive Content-Length: 126 Content-Type: application/xml; charset=utf-8 Expect: 100-continue Host: localhost:8000 [Request] < Ping xmlns ="http://tempuri.org/" > < clientInfo > my info </ clientInfo > < lastSeen > 2006-08-15T00:22:36.528375-07:00 </ lastSeen > </ Ping > All of the SOAP goo is gone from the request. Compared to the request we saw yesterday, the only thing left in the request is what was formerly the contents of the body tag. However, on the client side, there's an exception being thrown after the message gets sent. Unhandled Exception: System.ServiceModel.ProtocolException: A response was received from a one-way send over the underlying IRequestChannel. Make sure the remote endpoint has a compatible binding at its endpoint (one that contains OneWayBindingElement). Server stack trace: at System.ServiceModel.Channels.RequestOneWayChannelFactory.RequestOutputChannel.ValidateResponse(Message response) at System.ServiceModel.Channels.RequestOneWayChannelFactory.RequestOutputChannel.OnSend(Message message, TimeSpan timeout) at System.ServiceModel.Channels.OutputChannel.Send(Message message, TimeSpan timeout) It's fairly easy to figure out what happened from the message and stack trace although it may not be obvious why. Inside the OneWay channel, there is validation that the system is truly acting in a one-way fashion. If you look at the code for the ValidateResponse method, you would see that it is essentially checking that the response message is null. In this case, we got a reply back from the server even though we were not expecting it to send anything back. Remember, the server knows nothing about WCF and behaves exactly the same for every request regardless Read More...
  • Introducing MessageState

    I've mentioned that messages have a definite lifecycle without ever mentioning what the lifecycle represents. The MessageState enumeration reflects the different stages that a message goes through. public enum MessageState { Created = 0, Read = 1, Written = 2, Copied = 3, Closed = 4, } Messages initially start off in the Created state. The simplest way of thinking about this is that Created messages are the only type of messages that are valid to use. Messages are restricted to a single use so that we can support the programming model of operating on transient, streaming content. Every other message state reflects how the message lived its life. By calling GetReaderAtBodyContents, you move the message to the Read state. This reflects a message that has been killed by consuming its contents using an XmlReader. By calling either WriteBodyContents or WriteMessage, you move the message to the Written state. This reflects a message that has been killed by consuming its contents using an XmlWriter. By calling CreateBufferedCopy, you move the message to the Copied state. This reflects a message that has been killed by consuming its contents using a MessageBuffer. Copying the message to a buffer is the easiest way of using the contents of a message more than once . Unlike a transient message, buffers are something that can survive repeated use. A message in the Closed state has been cleaned up by calling Close or the equivalent Dispose. An implementation may have other methods that in turn invoke one of these five deadly message poisons. Messages are lightweight objects that are not thread-safe. If you call multiple methods that affect the message state at the same time, then you'll very likely screw up your program. Don't do that. Next time: Net.Tcp Port Sharing Sample, Part 1 Read More...
  • 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(); } Read More...
  • Some Changes for Channels and Transports in the June CTP, Part 3

    Today's look at recent changes covers two cool new features. #1: Better support out-of-the-box for building applications in the POX/REST style. Back in March, I talked about the POX support we added for the February CTP and a bug we found in our implementation of HttpMappingMode . There were two problems in that release. The first problem was the unfortunate functional bug that made it far too easy to shoot yourself in the foot when building an application. The second problem was that the multi-state mapping mode setting was a confusing and clunky way of enabling this architectural style. It was better than having to install an unsupported POX encoder sample on your production machine, but it still was not good. In June, you can now see our new approach to solving this problem. Support for POX is built into the normal text encoder. Fundamentally, using the POX style means that you want our messaging layer to not add the SOAP and addressing goop that it normally sticks into every outgoing message for you and not require that goop on every incoming message. We already had knobs for controlling how to format the goop in the encoder. Our solution was to add a "none of the above" option to these knobs. Setting MessageVersion to None means taking the "none of the above" option for every part of the message, or equivalently, it means "no goop please". #2: Better support for using packet routers. The two major kinds of routers are circuit-based routers and packet-based routers. A circuit-based router affinitizes the incoming and outgoing connections. This makes the router almost transparent to the way we think about connectivity (the router is still not transparent to the way we think about message passing though, for instance transport security is point-to-point). A packet-based router treats everything like a datagram and doesn't care about connections. Packet routers work well with fire-and-forget messaging. Transports that are inherently request-reply, such as HTTP, don't work so well with packet routers when they need to send back failure notifications. When an HTTP message arrives at a packet router, the router needs to make the reply immediately. Once the message moves on to the next hop, the router forgets everything about the reply connection so there's only one opportunity to send the reply message. Typically, the router just sends back an acknowledgment that the packet was received. However, if an error occurs several hops later, there's no way to route Read More...
  • Framing Size Limits for the Tcp and Named Pipe Transports

    I've talked about the framing that goes on in the network stack before, but today's topic is a case where the framing actually affects what your application can do. Inside the WCF transport, essentially the uppermost level of the WCF network stack that actually has a byte stream, we need to make a decision about how that stream of bytes will get pushed onto the wire. A WCF message has an almost unlimited size . You can of course constrain the size of messages that you’ll deign to receive, but in theory it's possible to create really, really big messages and there might be someone actually willing to receive a message that big. Network messages almost never have an unlimited size. Some network transports (the layer below WCF transports) cap out at hundreds of bytes , while others cap out at millions of bytes (queues, but I haven't talked about those yet), but nearly all have a cap that is less than the quadrillions or quintillions of bytes you can stuff into a WCF message. How is it possible to actually send a WCF message over a size-constrained network transport? The solution is message framing. Surrounding each message is contextual information that allows the receiver to reassemble fragments into the original WCF message. Each transport is responsible for splitting the byte stream, applying its own framing format, and performing the reassembly. At the beginning of the message are two pieces that could conceivably be quite large, the via for message delivery and the content type of the message. Now, these pieces are constrained by your maximum message size, but you have to know where the message is going before you can do things like perform user authentication. This is a sticky point because while you might be ok with authorized users sending you millions of bytes, you probably don't want unauthorized users to do the same. This was a somewhat long digression to motivate a problem you might encounter with our TCP and named pipe transports. The framing format for these transports specifies that the receiver may, if they want to, cap the maximum size of the message via and content type. That's the Via property on your IOutputChannel and the ContentType property on your MessageEncoder . We do in fact want to do this. There are even specific faults to send back in the event that the limits are reached. What you probably want to know though is: what are those limits? 2048 bytes for the message via and 256 bytes for the content type. Next time: Mapping Channels Read More...
  • Versioning for Addresses, Envelopes, and Messages

    The versioning of a message in WCF is a combination of the versioning of the envelope format and the addressing format. In Beta 2, the versioning story is a little out-of-date from where it's going to be for the final release. That's simply due to the lag time of producing an official release. I'm going to talk about the Beta 2 versioning story in this post because that's what you can write code against at this time. Everything here is still going to be important in the future. The addressing format is a transport-neutral mechanism for talking about the location or destination of services and messages. The mechanism for addressing in WCF is Web Services Addressing. There's two version of the WS-Addressing standard to worry about. The first version is the original August 2004 release . The second version, which is what you should really be thinking about, is the final WS-Addressing 1.0 release that came out earlier this month. This version has been tracked by WCF during development. public sealed class AddressingVersion { public static AddressingVersion WSAddressing10 { get; } public static AddressingVersion WSAddressingAugust2004 { get; } public override bool Equals( object obj); public override int GetHashCode(); public override string ToString(); } The envelope format describes the contents of a message and how to process it. The standard envelope format for WCF is the Simple Object Access Protocol (SOAP). SOAP is an XML-based packaging format for data. By itself, SOAP doesn't really do much. SOAP relies on other web service standards to plug in and provide functionality that people want, like security, reliability, and transactions. SOAP comes in both a 1.1 flavor from May 2000 and a 1.2 flavor from June 2003 . SOAP 1.2 fixes a lot of crufty bits from the earlier specification. public sealed class EnvelopeVersion { public string NextDestinationActorValue { get; } public static EnvelopeVersion Soap11 { get; } public static EnvelopeVersion Soap12 { get; } public override int GetHashCode(); public string [] GetUltimateDestinationActorValues(); public override string ToString(); } The message version is just a pairwise combination of the addressing and envelope formats. By default, you get the latest and greatest version of each specification. If you supply an envelope format without an addressing format, you'll get WS-Addressing 1.0. If you don't supply anything, you'll get WS-Addressing 1.0 with SOAP 1.2. public sealed class MessageVersion { public AddressingVersion Read More...
  • Choosing a Transport

    This is the last planned article in a documentation series covering various aspects of Windows Communication Foundation transports. Today's topic covers how to choose a transport and associated encoder. Choosing a Transport The Windows Communication Foundation (WCF) programming model separates the behavior of endpoint operations from the transport mechanism that connects two endpoints. This gives you flexibility when deciding how your services should be exposed to the network. Transports and message encoders are pieces of WCF that sit below a service to provide connectivity. This document discusses some of the characteristics you need to evaluate when choosing a transport and message encoding. In scenarios where you must connect to a preexisting client or server, you may not have a choice about using a particular transport and message encoding. However, WCF services can be made accessible through multiple endpoints, each with a different transport or message encoding. When a single selection does not cover the entire intended audience for your service, you should consider exposing your service over multiple endpoints. Client applications can then choose the endpoint that is most favorable for them. Using multiple endpoints allows you to combine the advantages of different transports and message encoders. Transports and Message Encoders In WCF, the transfer of data across a network requires the joint cooperation of a transport and message encoder. A message encoder converts a System.ServiceModel.Channels.Message to a serialized form. This document covers the Text, Binary, and MTOM message encoders that are included in WCF. The text message encoder supports both a plain XML encoding as well as SOAP encodings. The plain XML encoding mode of the text message encoder is called the POX encoder to distinguish it from the text-based SOAP encoding. A transport sends the serialized form of the message to another application. This document covers the HTTP, TCP, and named pipe transports that are included in WCF. WCF provides several standard bindings that combine a transport, message encoder, and other options. For instance, the BasicHttpBinding binding combines the HTTP transport with a text message encoder. Similarly, the NetTcpBinding binding combines the TCP transports with a binary message encoder. You are not limited to choosing a preset combination given by a standard binding. Decision Points for Choosing a Transport The following table describes several decision Read More...
  • Using the BufferManager

    A BufferManager recycles the byte buffers used when reading and writing buffered messages . There's some allocation overhead creating these frequently used buffers, making buffer recycling a net win in high-throughput scenarios. As you move to larger message sizes though, buffer recycling becomes less of a factor and then eventually a net loss. All of this is encoded in the BufferManager class so that you don't have to think about it. When you create a BufferManager, you specify the size of the heap to draw from. Once the total concurrent allocations exceed this heap size, the buffer manager begins returning non-recyclable buffers. The second tunable parameter of a BufferManager is the maximum size of a recyclable buffer. Again, if an allocation exceeds this maximum size, then the buffer manager simply returns a non-recyclable buffer. This limit prevents the buffer manager from holding blocks of memory for large messages, which tends to be inefficient. public abstract class BufferManager { protected BufferManager(); public abstract void Clear(); public static BufferManager CreateBufferManager( long maxBufferPoolSize, int maxBufferSize); public abstract void ReturnBuffer( byte [] buffer); public abstract byte [] TakeBuffer( int bufferSize); } The basic functionality of a buffer manager is very similar to a heap with explicit malloc and free. You grab a buffer using TakeBuffer and later give it back using ReturnBuffer. You cannot return someone else's memory using ReturnBuffer. The most common source of this is if you allocate your own byte array or pull from another buffer manager, and then give that memory to a message encoder. This will fail after the encoder is done with the buffer. Here's what that failure exception tends to look like: Unhandled Exception: System.ArgumentException: This buffer can not be returned to the buffer manager because it is the wrong size. Parameter name: buffer at System.ServiceModel.Channels.BufferManager.PooledBufferManager.ReturnBuffer(Byte[] buffer) at System.ServiceModel.Channels.BufferedMessageData.DoClose() at System.ServiceModel.Channels.BufferedMessageData.Close() at System.ServiceModel.Channels.BufferedMessage.OnClose() at System.ServiceModel.Channels.Message.Close() at System.ServiceModel.Channels.Message.System.IDisposable.Dispose() The final method in the BufferManager class is Clear, which allows you to flush the cache. You might call Clear when your server goes idle after handling enough messages to have touched a Read More...

Copyright © 2006 Microsoft Corporation. All Rights Reserved. | Terms of Use | Privacy Statement | Contact Us