[Updated – 10/3/2012: An astute reader pointed out that the sample below will produce some inconsistent results based on the order of the bindings being compared. This is because of things like JIT compilation, internal caching, etc. As a quick fix, I added two lines of code to the CompareBindings method to “warm up” the binding elements that will be compared. ]
Which binding is best? That’s a question I hear and see a lot. When it’s asked of me, the answer is always – “it depends”. It’s impossible to know from that simple question which binding is going to “best” meet your application requirements. Quickly after I start probing for more information, the question narrows down to which binding is fastest? Again, the answer to that question is going to be (you guessed it) – “it depends”.
There are 4 transport schemes that WCF supports: http, net.tcp, net.pipe, and net.msmq.
If your application requires queuing, then you only have the option of using the bindings that support queuing. In other words, there’s nothing to compare. If your application will be called from other applications/services on the same machine, then you should be using the NetNamedPipeBinding for cross-process calls on the same machine. So, again, there’s really nothing to compare.
So, when comparing bindings, the transport scheme pretty much shakes out to a comparison between http and net.tcp. These are the two left that will be used when crossing machine boundaries (actually going out on the NIC). There are several bindings and endless binding configurations that potentially can use one of these two schemes. For example, does your application require security? If so, then you have several decisions to make, such as do you want to use transport or message security? What kind of credentials are you going to prompt your client for? Is Federation/SSO a requirement? Just to name a few. What about your message payload size? Is it large/small? Do you have transactional requirements for message exchanges? Are there interoperability constraints you need to account for? Will your service require sessions? And so on…. So, you can begin to see why the answer to such a question is always “it depends”. Instead, a thoughtful discussion about the application requirements is necessary to offer up sound advice on the subject. When you do compare bindings, you need to make sure you’re comparing bindings equally – that is, all the bindings meet the requirements for your application. As an example, it’s not a fair comparison to compare NetTcpBinding and BasicHttpBinding with their default values. These bindings offer different features by default.
Still, people just want to know, if “conditions xyz” exist, which binding is going to be fastest? For that, I have a little sample application I put together to help you answer that question yourself. Knowing that bindings are simply a collection of binding elements to support various features, you can start to construct bindings and binding configurations to compare against each other with little effort. Below is a brief description of the primary methods in this sample application and how you may want to customize it for your needs.
This method hosts the service (TestService), instantiates a client proxy, and calls the ProcessData method using the binding and data provided. It returns a StopWatch to the caller so the elapsed time can be observed. In this method, I have the StopWatch starting just before creating the client proxy and opening the channel. I stop it after closing the client proxy. You may want to make your test more granular and put the start and stop immediately before and after the call to ProcessData (if you don’t want the elapsed time to include creating the channel).
This method invokes the TestBinding method for an array of bindings you provide. It will generate some random data for the test using the size you specify. For each test, it will output the binding’s elements and the results from the StopWatch returned from TestBinding. Other than changing the format of the output or writing more binding configuration data to the console, you probably won’t change this.
This is where I create some bindings, add them to an array of bindings, and call the CompareBindings method. This is where you will do most of your experimenting. Create the bindings with the elements you want/need. Add them to the binding array and call CompareBindings.
This is an example of the output with the application running on my single machine. In my test, there is no network latency since everything is local. You may want to separate your tests out into a separate client and service application so you can include network latency in your test. Also, this output is not comparing equal bindings so don’t read too much into my output. I just put together a few bindings so you could see how to construct the bindings to meet your needs.
Hopefully this helps identify which bindings are going to be best for your application and also shine some light on why it’s not a quick-and-simple answer.
You can download the full application code from here.