The first thing developers starting to implement Windows Communication Foundation (WCF) should know is the difference between the BasicHttpBinding and the WSHttpBinding.
This is very important as the BasicHttpBinding has some major drawbacks compared to the WSHttpBinding. From the functional view it makes no difference, it's just a client invoking an operation on a service, but there is a world of difference concerning the low level exchange of SOAP packets to achieve this.
BasicHttpBinding is there only to support the old .ASMX style of working (based on WS-BasicProfile 1.1) and aimed for clients which do not have .NET 3.0 installed. As lots of Windows 2000, which cannot run .NET 3.0, are still out there this is the only way to work with WCF. So the BasicHttpBinding it's there mainly for compatibility reasons.
But you have to be familiar with the idea that this basic profile binding is out-of-date and that the protocol does not have enough quality on board to support the requirements of enterprise oriented services, which can have a high SLA.
ASMX does not support secure messaging (I mean by default, without the WS enhancements). When a client calls an operation on a service, all data in the payload is send as a plain XML, human readable, SOAP packet. Scary? Isn’t? It also does not support reliability and ordered delivery. When a call is lost somewhere, the client is not informed and just waits for a timeout and can not know for sure if the call has arrived at the server and if the logic behind it got executed. Also lacking in the basic profile is ordered delivery. This means when a client fires multiple calls to the service it's not guaranteed that they arrive in the same order. Maybe somewhere a router could drop a packet allowing the second call to arrive earlier than the retransmission of the first. This can lead to disasters, which cannot be allowed in enterprise solutions.
In a sentence: do not use basicHttpBinding binding.
The WSHttpBinding fully supports these requirements on security, reliability and ordered delivery. Some of them as default, others have to be configured. But remember this tuning does not influence the functional development; it's all done under the covers!
So there is no excuse to not use the WSHttpBinding.
WSHttpBinding uses (as the name implies) the WS-* protocols. This results in having some additional handshake messaging and other ping-pong exercises (you got it, I got it, you got it, I got it ... as Juval Lowy would say this) to accomplish this. This means that not only SOAP requests are sent for the operation calls but also to have the client and service agree on some context and to inform each other on the success of the calls.
To fully understand when these extra messages are send and what they are carrying, we can have a closer look at the SOAP messages by using a tool like HTTP Analyzer. This great tool allows you to capture the HTTP traffic and dive into the SOAP packets on the wire.
You can download a demo version of HTTP Analyzer at http://www.ieinspector.com/httpanalyzer/index.html
To experiment on these issues I created an application, which has some scenarios to demonstrate the differences on these bindings. You can download this VS2005 solution here.
I created 3 proxy-service scenarios, all of them exposing the same ServiceOperation and using the same really simple implementation.
[ServiceContract]
interface ITestServiceContract
{
[OperationContract]
int DoSomethingInTheService(int aNumber, string aString);
[OperationContract]
string DoAnotherThingInTheService(int aNumber, string aString);
}
class TheService : ITestServiceContract
{
public int DoSomethingInTheService(int aNumber, string aString)
{
return aNumber * 10;
}
public string DoAnotherThingInTheService(int aNumber, string aString)
{
return string.Format("I got {0}", aString);
}
}
1. Using BasicHttpBinding (the ASMX style)
Code to start the service (I’m not using any config here, the service is running self hosted in a executable and configuration of binding and endpoint is done programmatically).
* The ServiceHost
ServiceHostBasic = new ServiceHost(typeof(TheService));
BasicHttpBinding binding;
binding = new BasicHttpBinding();
ServiceHostBasic.AddServiceEndpoint(typeof(ITestServiceContract), binding, "http://localhost:9000/ServiceHostBasic");
* The client creates a proxy
EndpointAddress endpointAddress;
endpointAddress = new EndpointAddress(new Uri("http://localhost:9000/ServiceHostBasic"));
BasicHttpBinding binding;
binding = new BasicHttpBinding();
ProxyBasic = new TheProxy(binding,endpointAddress);
* The client calls the operations
int a;
a = ProxyBasic.DoSomethingInTheService(100, "test");
string s;
s = ProxyBasic.DoAnotherThingInTheService(100, "test");
* The client closes the proxy.
ProxyBasic.Close();
Lets examine this scenario in detail. Doing all of this results in 2 messages traveling over the wire. One for the first call (DoSomethingInTheService) another for the second one (DoAnotherThingInTheService).
Both messages transport the call and the needed data to the service.
Content of the request for the second message (as an example, this is comparable to the first message) :
Content of the response for the second message:
Hmm, no security, not encrypted. The client cannot know whether the call arrived at the service, as this is a kind of fire and forget situation. No acknowledgement of the arrival of the call back to the client.
2. Using default WSHttpBinding.
* The ServiceHost
ServiceHostWS = new ServiceHost(typeof(TheService));
WSHttpBinding binding;
binding = new WSHttpBinding();
ServiceHostWS.AddServiceEndpoint(typeof(ITestServiceContract), binding, "http://localhost:9000/ServiceHostWS");
ServiceHostWS.Open();
* The client creates a proxy
EndpointAddress endpointAddress;
endpointAddress = new EndpointAddress(new Uri("http://localhost:9000/ServiceHostWS"));
WSHttpBinding binding;
binding = new WSHttpBinding();
ProxyWS = new TheProxy(binding, endpointAddress);
The rest of the code is the same. What has gone over the wire now? This results in 6 messages and their answers.
Message 1,2 and 3 is a handshake sequence to establish the security context. This handshake is using the Web Service Secure Conversation Languages build on the WS-Security and WS-Trust protocols.
In this part of a message 1 you can see the client asks for a security token.
The answer for this is a RequestSecurityTokenResponse.
The 2 following SOAP messages (message 2 en 3) complete this handshake.
Message 4 and 5 are the operation calls, but the data is now encrypted in a way the service infrastructure (=WCF) can decrypt this before sending it in the operation.
Message 6 is again related to the securitycontext. But important to notice that message 6 is sent when closing the proxy. So the service can release the securitycontext.
As said, this behavior comes for free by using WCF, the developer does not have to know how this is done. Compared the ASMX this is a huge step forward. It would be hard to develop this yourself without WCF and if you would succeed in this is, it would be influencing the functional code.
This is the default behavior of the WSHttpBinding. But what about the reliability and ordered delivery?
3. Using default WSHttpBinding with the reliableSessionEnabled flag on.
When instantiating the WSHttpBinding you can set the reliableSessionEnabled flag to true. This instructs the WCF client to have the messages sent in a reliable session. This means that the client gets informed when the message arrives so there is no doubt whether the serviceoperation has done it’s job.
* The ServiceHost
ServiceHostWSReliable = new ServiceHost(typeof(TheService));
WSHttpBinding binding;
binding = new WSHttpBinding(SecurityMode.Message, true);
ServiceHostWSReliable.AddServiceEndpoint(typeof(ITestServiceContract), binding, "http://localhost:9000/ServiceHostWSReliable");
ServiceHostWSReliable.Open();
* The client creates a proxy
EndpointAddress endpointAddress;
endpointAddress = new EndpointAddress(new Uri("http://localhost:9000/ServiceHostWSReliable"));
WSHttpBinding binding;
binding = new WSHttpBinding(SecurityMode.Message, true);
ProxyWSReliabable = new TheProxy(binding, endpointAddress);
The only difference is this code compared to scenario 2 is in providing the parameters to the constructor of the binding. This at the client side and the service side.
This results in 9 messages and their answers, of which only 2 messages are the actual calls to the operations.
Message 1 to 3: Again this is the security context handshake like in the previous scenario.
Message 4: This message asks the service to create the sequence, so it knows it can expect multiple messages that are part of the same sequence.
And the answer on this:
Message 5 and 6 are again the encrypted calls to the operations. But notice that each message is carrying a sequence number.
The first operation:
The second operation:
Message 7 is the client asking to the service to acknowledge the 2 messages it just has send it.
This message (and the subsequent messages) is send when the proxy is closed. So remember its necessary to close your proxy always!
On which the service reacts by sending its acknowledgement:
Message 8 is again the client telling to the service it got its confirmation so both part can be sure the messages are delivered. This is what reliability is about.
Message 9 is as in the previous scenario to release the securitycontext at the service.
Summary (considering 2 calls to an ServiceOperation)
1. BasicHttpBinding (2 messages)
2. Default WSHttpBinding (6 messages)
3. Default WSHttpBinding with Reliable Session Enabled (9 messages)
Some remark: Although you can set the securityMode when creating the BasicHttpBinding for the service, you cannot use this without having either SSL on the IIS to implement for transort level security or implement the WS-enhancement stack on the client yourself. So out-of-the box ASMX services have this basic non-secure behavior. With WCF this comes all for free with the WSHttpBinding.
cu (happy coding)