It Doesn't Always have to Be Complex

Warning from author: It seems that most people around me know more about WCF than I do. That is fine with me. Just keep in mind that what I write here, then, may or may not give you much. It serves me as an additional way to understand what I have seen and how the code works. If you already know this, consider yourself happy that this is not some printed manual that you have paid top dollar for only to find it useless. If you are at my level, hey, maybe we can share ideas?

Sometimes, using the raw power that is underneath you as you are using WCF is an advantage over using the harnessed, typed interfaces that you would normally do. For instance, if you are trying to create some sort of intermediary, you most likely will want the raw message, fresh and hot off the wire. One example of such an intermediary is the Intermediary Router SDK sample. The crux of this sample, if you ask me, the following definitions*:

[ServiceContract(SessionMode = SessionMode.Allowed)]

public interface ISimplexDatagramRouter

{

[OperationContract(IsOneWay = true, Action = "*")]

void ProcessMessage(Message message);

}

[ServiceContract(SessionMode = SessionMode.Allowed)]

public interface IRequestReplyDatagramRouter

{

[OperationContract(IsOneWay = false, Action = "*", ReplyAction = "*")]

Message ProcessMessage(Message message);

}

[ServiceContract(SessionMode = SessionMode.Required)]

public interface ISimplexSessionRouter

{

[OperationContract(IsOneWay = true, Action = "*")]

void ProcessMessage(Message message);

}

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ISimplexSessionRouter))]

public interface IDuplexSessionRouter

{

[OperationContract(IsOneWay = true, Action = "*")]

void ProcessMessage(Message message);

}

It took me a while understand what was going on, but it is not all that bad: Essentially, there is, with one exception, a contract for each of the MEPs. The simplest one is the datagram contract. This is basically a one-way fire and forget. Note that this MEP will not cause the service to even give a response (which non-one-way operations will do even if the return type of the operation is void: The response will just be empty). The Action parameter with the asteriks is just a "catch-all" for all incomming messages such that any action can be serviced by this operation. Internally, this causes an address filter that matches all incoming messages to be put in place instead of a filter that check if the Action header on the incoming message can be serviced by the given service.

Understanding things this far makes the next one pretty easy to understand by transposing the logic: It is a contract for a request/reply MEP. The request comes in the usual shape (the message parameter passed to ProcessMessage) and the reply is the Message return type. Note here that we are no longer talking about a one-way fire and forget operation (as indicated by the IsOneWay attribute parameter).

Finally, the last two contracts. Note first that they are marked as session required. Ok, now, the first session demanding contract, ISimplexSessionRouter, is basically a fire-and-forget operation that takes place within the scope of a session. Not that much magic here. But, now the beauty starts to shine: The duplex session aware operation needs some means of calling back to the client... Wait... Got it... The ISimplexSessionRouter! Isn't it sweet?

I am not going to go over the actual implementation of the router sample. I think the code is pretty self-explanatory given a little time and a cup of coffee. As I said, sometimes, the it doesn't have to be complex at all. Using untyped contracts solves the problem here.

* As I was revisiting the SDK sample, by accident I ended up in the C++ folder. Man, I must say that C++/CLI has come a long way from MC++, but it is still ugly. Very. My eyes are happy that I am a C# dev.