During the past few days I came across some SOAP routing intermediary implementations (of course running on WCF ;)) and each of them were trying to route the WCF messages by changing the “To” WS-Addressing header in the message. In some cases this even required completely reconstructing the message by reading its body contents. This actually made me think about the basics once again. What actually happens in the real routers? For example, does Windows TDI driver for TCP/IP change the destination IP to your router’s IP after looking at the routing table? No! Instead, the transport transmits the traffic to the appropriate IP as specified in the routing table. Then the router reads the destination IP in the incoming TCP segments and forwards the traffic to the next network hop according to the routing table in the router itself. So essentially, the router is a device that simply forwards messages without tweaking them. Likewise this should be the theory behind the SOAP routers as well (of course SOAP works at a much higher level and you can divert this approach to meet your custom needs. But I’m talking about the routing in general).
So how exactly you can do this in WCF? The answer is hidden in an attribute that you might not pay too much attention in your everyday WCF adventures ;). When you configure an endpoint you can actually, specify the service address as well as the actual listening address as follows.
[ServiceEndpoint]
<endpoint address="http://localhost:8000/service/dummyendpoint.svc"
listenUri="http://localhost:8000/service/actualendpoint.svc"
contract="…"
binding="…"
bindingConfiguration="…" />
When you start your service the underlying transport actually uses the address specified in the listenUri to listen to the incoming traffic (if this is not specified, it uses the endpoint address by default). The service address on the other hand is the one which goes in the WS-Addressing “TO” header. This address is validated by service model layer to make sure that the messages that arrive at the endpoint are truly intended for this service (otherwise you’ll get the address filter mismatch error… remember that? ;)). So with these two attributes in our hands we can successfully model the aforementioned routing in the SOAP level as well. You can do it by having your router service actually listening on the endpoint address specified in the service (see below).
[Router endpoint]
<endpoint address="http://localhost:8000/service/dummyendpoint.svc"
contract="…"
binding="…"
bindingConfiguration="…" />
Then you can simply forward the messages to the actual service endpoints according your routing rules. For example, you can determine a message to the above service endpoint by looking at the action header of the incoming message and forward it to the service by making a channel to http://localhost:8000/service/actualendpoint.svc endpoint (which is the actual endpoint of our service). Also note that this way, no matter how many intermediaries the message passes through the WS-Addressing “TO” header remains consistent.
When I started writing this post I intended to provide a very rough sample that I created couple of months ago (in fact I gave up re-inventing the wheel after seeing Shy Cohen’s wonderful lossy router ;)). But then I realized that the SDK routing sample perfectly demonstrates this. So take a look at it to get a better picture on it.
Have fun!
Have you ever thought about returning a plain old XML document or some well formed HTML body snippet (for some crazy reason ;)) or your RSS feed from a WCF service? Well… I did :). In fact instead of returning the XML document itself, I wanted to stream it as the data source I was anticipating was not fast enough to provide me the complete document at once (i.e. it takes considerably more time to receive the portions of the document than the time taken for the actual transmission).
So my long (well… it's not really long) journey towards a solution started with the contract (oh! Nah! I'm not going to play that famous record once again ;)).
[OperationContract(Action = "*", ReplyAction="*")]
Message GetWeather();
My contract has only one operation. By default WCF uses SOAP action headers in the incoming/outgoing messages to properly dispatch them to the service/client. But in this case I have nothing SOAPish in my payload. Therefore, by setting Action="*" in my OperationContract I'm telling WCF that anything comes into the configured endpoint of this service must be dispatched to this method.
Moving on to my operation implementation, I have a single line of code that simply constructs a Message and return it to the runtime which takes care of transmitting it back to the client.
public Message GetWeather()
{
Message msg = Message.CreateMessage(MessageVersion.None, "*", new WeatherReport());
return msg;
}
So much of my solution lies within this line nevertheless. Let me brief you, Message is the fundamental unit of data transfer in WCF (if you have some socket background, think of it as the byte arrays in the world of sockets). You can create a message by calling one of the CreateMessage overloads in Message class. In WCF, these overloads are provided to support both push and pull mode data transfers. So in my case, I'm going for a push mode transfer and I'm doing it using an XML BodyWriter. You can create a BodyWriter by inheriting the BodyWriter abstract class. Then override the OnWriteBodyContenets, which is invoked by WCF runtime when it wants to serialize the message body. The runtime provides us a pointer to the XmlDictionaryWriter which, we can use to push the body contents. Consequently in my case I implemented my body writer in the WeatherReport class and wrote the XML document I wanted to send to the client in its OnWriteBodyContents overload.
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
writer.WriteStartElement("weatherReport");
Console.WriteLine("Sending weather report for Colombo");
writer.WriteStartElement("Colombo");
writer.WriteAttributeString("temp", "26");
writer.WriteAttributeString("wind", "SW");
writer.WriteAttributeString("humidity", "79");
writer.Flush();
Thread.Sleep(3000); // Simulate an I/O delay in the data source
Console.WriteLine("Sending weather report for Munich");
writer.WriteStartElement("Munich");
writer.WriteAttributeString("temp", "25");
writer.WriteAttributeString("wind", "NE");
writer.WriteAttributeString("humidity", "37");
writer.Flush();
Thread.Sleep(3000);
Console.WriteLine("Sending weather report for Seattle");
writer.WriteStartElement("Seattle");
writer.WriteAttributeString("temp", "15");
writer.WriteAttributeString("wind", "SW");
writer.WriteAttributeString("humidity", "80");
writer.WriteEndElement();
writer.Flush();
}
You might have already noticed that in the above code, I call writer.Flush() several times. I do this when I've written enough data that the client can understand (weather report for one city in this case) so that it will be transmitted to the client immediately. However, in order make sure that the data is sent back to the client immediately, we have to make sure that we are on the streaming mode. This has to be specified in our binding. I'm setting up my A(address),B(binding) and C(contract) imperatively in the code as follows.
CustomBinding binding = new CustomBinding();
// Encoder
TextMessageEncodingBindingElement encoder = new TextMessageEncodingBindingElement();
encoder.MessageVersion = MessageVersion.None;
binding.Elements.Add(encoder);
// Transport
HttpTransportBindingElement transport = new HttpTransportBindingElement();
transport.TransferMode = TransferMode.StreamedResponse;
transport.MaxBufferSize = 256;
binding.Elements.Add(transport);
// We will take about 10 minutes for our transmission.
binding.SendTimeout = TimeSpan.FromMinutes(10);
ServiceHost host = new ServiceHost(typeof(MyService));
host.AddServiceEndpoint(typeof(IMyService), binding,
"http://localhost:8011/myservice");
host.Open();
In this case, my binding contains only the most critical elements, the encoder and the transport we need to host a service. While setting up my encoder I set its MessageVersion property to MessageVersion.None. By doing this I'm telling the encoder that I want to get rid of all the SOAPish stuff in the message finally serialized (Tip: this is your key if you want to do non SOAP transfers). And the in the transport I set the transfer mode to StreamedResponse to stream the responses from my service (when we enable streaming in the http transport, it streams the content as specified in the chunked transfer coding in the HTTP spec). Furthermore I set the MaxBufferSize to 256 bytes since we are only sending a very small chunk at a time. This way you can optimize the memory consumption for read/write buffers used for streaming (default is 64K). Finally I create the ServiceHost and call the Open method in that to start the service.
On the client side, I setup my binding in almost the same way I did it in the service. Then I create a channel to communicate with my service endpoint and invoke the GetWeather operation. When I receive an instance of the Message class from the client side runtime, I get an XmlDictionaryReader at the body contents that I can use to read the underlying XML stream.
Message playlist = myservice.GetWeather();
XmlDictionaryReader reader = playlist.GetReaderAtBodyContents();
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
Console.WriteLine("{0} Temp:{1} Wind:{2} humidity:{3}",
reader.Name,
reader.GetAttribute("temp"),
reader.GetAttribute("wind"),
reader.GetAttribute("humidity"));
break;
case XmlNodeType.Text:
break;
case XmlNodeType.EndElement:
break;
}
}
reader.Close();
Now, it is important to note that I've also set the MaxBytesPerRead quota to 64 bytes in ReaderQuotas property of my encoder.
encoder.ReaderQuotas.MaxBytesPerRead = 64;
This value indicates how many bytes the XmlDictionaryReader should read when reading the element start tag and its attributes. Therefore, this value should essentially be large enough to read that information. If you set an unnecessarily large value here, the XmlDictionaryReader.Read() method will not return until it receives enough bytes from the underlying transport (this could be problematic if you receive very small data chunks with a considerable amount of delay as demonstrated in my code). Consequently you would not be able to read the data being streamed in timely fashion (this might even make you think that your data not actually streamed ;)).
You can download my sample code here and take a good look at it. Questions, ideas and corrections are welcomed!
Yesterday I was organizing my 7000+ photo gallery and suddenly noted something which, none of us have posted yet. It’s been a while since we did some cool modifications to thinktecture family ;). Although Ingo and Christian posted about the addition of our friends Neno and Dominick let me be the very first to post a picture of us ;).

Most of us have our own style of writing code we’ve been practicing throughout our career. Using the “using” statement for deterministic resource cleanup is one of my must haves in my keywords bag. But unfortunately I cannot use this to clean up the client channels I use in WCF. For example, if I use the following piece of code I’m unwittingly opening up a place where my program would simply crash. Why?
using (IClientChannel client = (IClientChannel)cf.CreateChannel())
{
IFoo foo = (IFoo)client;
foo.Bar();
}
The above code merely means that the following line will be executed upon exiting the using block.
((IDisposable)client).Dispose()
And the answer to above “Why?” actually lies within the Dispose implementation in the IClientChannel implementation. If we reflector System.ServiceModel.Channels.ServiceChannel, one of the IClientChannel implementers in WCF, we can clearly see that its Dispose implementation calls Close method in its base class CommunicationObject. In the world of CommunicationObjects, Close does not necessarily mean that everything will be fine. Likewise, when we call Close, we are essentially telling WCF to gracefully close the client channel. However, the evil things could still happen. For example, soon after calling Close we might lose the network connectivity before the channel can successfully send the protocol level messages that are required to terminate the current session.
So the bottom line is Close() can throw. And we have to be aware of it and write our code in a way that it does not crash even if the Close throws. There can be two kinds of things that can happened if something goes wrong while communicating with the service. Namely they are timeout exceptions and communication exceptions (yes, communication exceptions can be further broken into exceptions that inherits the CommunicationException, such as FaultException). When these things happen we should call Abort() in our client channel object to bring it to Closed state and throw away. Consequently the above code can be written better using the try/catch/abort pattern as follows.
IFoo client = null;
try
{
client = cf.CreateChannel();
client.Bar();
((IClientChannel)client).Close();
}
catch (TimeoutException)
{
((IClientChannel)client).Abort();
}
catch (CommunicationException)
{
((IClientChannel)client).Abort();
}
This code is fine as far as we call client channel methods within the try block. As soon as we have something else going on, we cannot guarantee that the code will only throw exceptions of these two types. For example consider a modified version of above code snippet like this.
IFoo client = null;
try
{
client = cf.CreateChannel();
client.Bar();
int x = 0, y = 0, z = 0;
// do some math to yeild x and y
z = x / y;
((IClientChannel)client).Close();
}
catch (TimeoutException)
{
((IClientChannel)client).Abort();
}
catch (CommunicationException)
{
((IClientChannel)client).Abort();
}
What happens if Y yields 0 after the math operations? We will hit a DivideByZeroException and neither our call to Close method nor calls to Abort method gets executed. So in such cases I would still recommend using a helper method in the finalizer to shutdown the communication object as follows.
IFoo client = null;
try
{
client = cf.CreateChannel();
client.Bar();
int x = 0, y = 1, z = 0;
// do some work to figure out the x and y
z = x / y;
((IClientChannel)client).Close();
}
catch (TimeoutException)
{
((IClientChannel)client).Abort();
}
catch (CommunicationException)
{
((IClientChannel)client).Abort();
}
finally
{
TryCloseOrAbort((IClientChannel)client);
}
static void TryCloseOrAbort(IClientChannel client)
{
if (client != null)
{
// Since this is called from the finalizer we don't know where the code
// was executing just before the finalizer. Therefore we check whether
// the communication object is already closed before we progress.
if (client.State != CommunicationState.Closed)
{
try
{
client.Close();
Console.WriteLine("Channel is closed.");
}
catch
{
client.Abort();
Console.WriteLine("Channel is aborted.");
}
}
}
}