WCF - One-way or the other

WCF One-way

I have always found WCF to be a great technology for many use cases. Before I ruffle anyone’s feathers out there, I love what Web API is capable of and if I am looking at providing HTTP services or anything which is targeted over internet, I would blindly choose Web API.
I am also eagerly waiting to see WCF service framework becoming a part of .NET Core. We already have the WCF client libraries available for the .NET Core version.
Having cleared that up, let me get back to one such use case for WCF, making a fire and forget call or one-way. This is useful when the client truly does not bother about the result or when it needs to kick off a process on the server and does not want to wait for it to finish, usually long running.
WCF’s comes with great variety, power and flexibility, but to truly harness it, one needs to have a deep understanding of its internals. You can use it out of the box without much mucking around, but sometimes it’s behaviour may not be obvious.

A quick recap on WCF one-way pattern.
The default behaviour of a service is request-reply pattern and to make it one-way you simply set the OperationContract as IsOneWay.

1
2
3
4
5
6
[ServiceContract]
public interface IOneWayService
{
[OperationContract(IsOneWay = true)]
void Process(int seed);
}

A few things to keep in mind when decorating an Operation as one-way.

  • The method has to return void
  • You cannot return Faults to the client. That means you cannot decorate the operation with FaultContract(typeof(Exception)) attribute.

Even if you unintentionally did the above on an one-way operation, the service would throw an error when attempting to start it.

Your service implementation is going to be nothing different here and so would the hosting part of it. So I won’t be delving in to it. You can simulate some load in it by doing a Thread.Sleep. So, would one get fire and forget operation form your client’s? It depends.
In fact it depends on quite a few things. First let us see what we can expect with our current implementation. Let me show you my client proxy first.

1
2
3
4
5
6
7
public class OneWayProxy : ClientBase<IOneWayService>, IOneWayService
{
public void Process(int seed)
{
Channel.Process(seed);
}
}

I like to hand-code my proxy / client for the service. I’ll probably keep that for another post. I also implement my clients different to what I have shown here, but this too is better than the freebie client you get from Visual Studio.

Let us look at the code calling our client.

1
2
3
4
OneWayProxy proxy = new OneWayProxy();
proxy.Process(5);
//proxy.Process(10);
proxy.Close();

The input parameter is just to make the service look important.

Here is what we see from running this implementation.

  1. The call to the proxy would be asynchronous (at the client). You can uncomment the next call and verify that. They would not block.
  2. Closing the channel might block. If the binding used is NetTcpBinding, by default it supports transport-level sessions. Which means the channel is kept open until the server completes processing all the client’s calls. If you use transport without a session, like basicHttpBinding, then the closing of channel would not block.
  3. The calls are dispatched synchronously on the service. Meaning, your next call would only get processed after completing the previous.

So what we learn is using One-way throws up a few surprises. It is fire & forget only for the operation calls. When you are having long running processes, you might not always want to wait for the operations to complete to close the channel. And Yes! You should always close the channel so that they are returned back to the servers pool.

Since most uses of WCF within the firewall would use or prefer TCP protocol over HTTP for speed and security and I would like to close my channel after each call is made,but not have it blocked, the above implementation would not be the most useful.

So what are our options here?
To close the proxy before the operation finishes -

  • We can use a session less transport, such as BasicHttpBinding or turn on Reliable session on NetTcpBinding. TCP binding provides reliability at transport level, but you get message level reliable session by enabling explicitly at the binding. But this comes at a cost overhead since a lot more messages are exchanged between the client and server to ensure this. This would also not give the best performance due to its chatty nature. <reliableSession enabled="true" />

  • You can mark the NetTcpBinding by turning off the session support. This is done by marking the binding as ‘oneWay’. This requires you to create a custom binding which turns off session support on NetTcpBinding. This would not block the channel from closing. In the below example we have adding tcpTransport support.

    1
    2
    3
    4
    5
    6
    7
    8
    <bindings>
    <customBinding>
    <binding name="onewayBinding">
    <oneWay />
    <tcpTransport />
    </binding>
    </customBinding>
    </bindings>

Remember to use the same binding at the client also.

By default all calls from a client would be processed synchronously. If more than one call were made from a client, they would be queued up on the server. The proxy would also be blocked from closing until all the processing is completed.

To enable concurrent processing of messages at the service-

With the above custom binding, it will also ensure that messages are processed concurrently. Which means each request would be processed on a different thread. Or you could again use basicHttpBinding.
However if you are using NetTcpBinding or session shaped binding, you should mark your service concurrency mode as Multiple.