This is the 11th post in the WCF 4.5 series. The previous post was about the new UDP transport support, and this new post is also about new transports – the WebSocket transport.
This post is part 1 of 2. This post will be about the WebSocket support between .NET apps using WCF (SOAP-based), and the next post will be about using WebSockets between browsers and WCF (non-SOAP).
Previous Posts
- What’s new in WCF 4.5? Let’s start with WCF configuration
- What’s new in WCF 4.5? A single WSDL file
- What’s new in WCF 4.5? Configuration tooltips and intellisense in config files
- What’s new in WCF 4.5? Configuration validations
- What’s new in WCF 4.5? Multiple authentication support on a single endpoint in IIS
- What’s new in WCF 4.5? Automatic HTTPS endpoint for IIS
- What’s new in WCF 4.5? BasicHttpsBinding
- What’s new in WCF 4.5? Changed default for ASP.NET compatibility mode
- What’s new in WCF 4.5? Improved streaming in IIS hosting
- What’s new in WCF 4.5? UDP transport support
A (very) short introduction to WebSockets – WebSocket is a bi-directional (two-way), full-duplex channel. WebSocket channels start as normal HTTP channels, and then use handshakes to upgrade the channel to WebSocket, allowing two-way TCP communication between client and server, thus overcoming several limitations enforced by firewalls. In order not to repeat all that is already written about WebSockets, I suggest you check the following websites:
Note: This post was written according to the WebSocket support of WCF 4.5 with .NET 4.5 Beta and Visual Studio 11 Beta. If you are still using the Developer Preview version, you might see some different configuration sections and different behavior of the “Add Service Reference” feature.
The support of WebSocket in WCF 4.5 is achieved through the new NetHttpBinding
. The NetHttpBinding
was first introduced in the WCF 4 samples as a custom binding that uses binary-encoded SOAP messages over HTTP(S). The NetHttpBinding
in WCF 4.5 is an improved binding that uses binary-encoded SOAP messages over HTTP(S) or WebSocket transports. The NetHttpBinding
can be used in any of the following ways:
- Request-Response over HTTP. This mode does not use WebSockets, but rather a simple HTTP/HTTPS channel with binary-encoded SOAP messages.
This mode is the default mode when using the binding without a duplex contract. - Duplex over WebSocket. This mode uses WebSockets, and allows two-way communication between client and service.
This mode is automatically used when you declare your service contract with a callback contract (duplex). - Request-Response over WebSocket. This mode uses WebSockets, but it does not take advantage of the two-way communication support of the channel (since we still use the request-response pattern).
This mode is used when doing one of the following:
- Changing the SessionMode of the contract to
Required
. The binding will upgrade automatically from HTTP to WebSocket, since HTTP is not sessionful and WebSocket is. - Manually forcing WebSocket by changing the binding configuration and setting the WebSocket transport usage to
Always
.
Since WebSocket is sessionful, you automatically get session support in your service, if you haven’t changed the instance context mode from the default PerSession
setting. If you’ve ever needed a sessionful HTTP channel and had to use WsHttpBinding
with WS-ReliableMessaging
, you now have another option which doesn’t require passing extra WS-RM messages.
NetHttpBinding
with WebSocket can in fact replace the use of WsDualHttpBinding
, since WebSocket provides a duplex channel which also supports sessions – this is better than WsDualHttpBinding
which uses two channels, and requires the use of WS-ReliableMessaging
for session management.
All three modes of the binding are non-interoperable, because they use binary-encoded SOAP messages which is a proprietary Microsoft encoding technique. If you want to learn more about binary encoding, I suggest you read Nicholas Allen’s posts on the subject. However, this does not mean we cannot use WebSockets as an interoperable transport with text-based SOAP messages – we can change the binding configuration to use text instead of binary, thus making in interoperable, as shown later on.
To demonstrate the usage of NetHttpBinding
, I’ve created a simple duplex contract:
[ServiceContract(CallbackContract=typeof(IDuplexCallbackContract))]
public interface IDuplexContract
{
[OperationContract]
string SayHelloDuplex(string name);
}
[ServiceContract]
public interface IDuplexCallbackContract
{
[OperationContract]
void SayingHello(string message);
}
And a service that implements the contract:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class WebSocketSampleService : IRegularContract, IDuplexContract
{
public string SayHelloDuplex(string name)
{
OperationContext.Current.
GetCallbackChannel<IDuplexCallbackContract>().
SayingHello("Hello " + name + " by WebSockets");
return "Hello " + name;
}
}
The endpoint configuration is quite simple:
<endpoint address="http://localhost:8083"
binding="netHttpBinding"
contract="Contracts.IDuplexContract"/>
Note: It appear that the WCF Service Configuration Editor doesn’t recognize the NetHttpBinding
’s WebSocket configuration, so you’ll need to use Visual Studio’s XML editor (the binding configuration is supported from VS11 Beta).
And as for the client-side code, just add a service reference and call the service:
Services.IDuplexContract duplexProxy;
Console.WriteLine("Press enter when service is ready");
Console.ReadLine();
duplexProxy = new Services.DuplexContractClient(
callbackContext,
"DuplexContract");
Console.WriteLine("Calling the duplex contract:");
Console.WriteLine(duplexProxy.SayHelloDuplex("ido"));
DuplexChannelFactory<Services.IDuplexContract> dchf =
new DuplexChannelFactory<Services.IDuplexContract>(
callbackContext,
new NetHttpBinding(),<br />
new EndpointAddress("http://localhost:8083/"));
duplexProxy = dchf.CreateChannel();
Console.WriteLine("Calling the duplex contract using text encoded messages:");
Console.WriteLine(duplexProxy.SayHelloDuplex("ido"));
Note: When specifying the endpoint address in the service, you need to use the http:// scheme, but on the client-side, you can use either http:// or ws://. When generating a service reference, the client configuration will use the ws:// scheme.
Note: If your service endpoint uses NetHttpBinding
but your contract is a non-duplex service contract (without a callback contract), you can still use NetHttpBinding
, but the channel will be HTTP and not WebSockets – in this case, the generated client configuration will create a custom binding instead of NetHttpBinding
. The custom binding is a perfect match of the NetHttpBinding
so things will still work, but it may be a bit confusing the first time you see it. I hope this will be resolved in the RTM version of VS 11.
When you add a service reference to the service, the client side configuration will be generated with a custom binding instead of the NetHttpBinding
- you can either leave it as-is, or remove the custom binding and rewrite the configuration to use the NetHttpBinding
(of course, you might need to do it again when you update the service reference).
It is also quite easy to define a new service endpoint which uses the NetHttpBinding
with text-based SOAP messages instead of binary:
<service name="Host.WebSocketSampleService">
<endpoint address="http://localhost:8084"
binding="netHttpBinding"
bindingConfiguration="TextOverWebSockets"
contract="Contracts.IDuplexContract"/>
</service>
<bindings>
<netHttpBinding>
<binding name="TextOverWebSockets" messageEncoding="Text"/>
</netHttpBinding>
</bindings>
So as you can see, we have the ability to use both binary and text, but how can we be sure it actually passes text instead of binary? For that, we need a network sniffer that can show us the WebSocket messages. You can use Wireshark or any other TCP sniffer to check that, however I always found those sniffers to be a bit hard to manage, especially for localhost communication. Luckily for us, we can use Fiddler, the famous HTTP sniffer, which now supports WebSocket messages (although only for watching).
This is how the binary message looks like when sent over WebSockets:
And this is how the text message looks like:
And this is the HTTP connection upgrade request:
(Notice the GET
request for WebSocket upgrade, and the corresponding HTTP 101 – Switching Protocols response.)
If you want to use WebSockets for a simple Request-Response contract, you can also do that, but you’ll need to set the binding configuration of your endpoint to require WebSocket communication:
<bindings>
<netHttpBinding>
<binding name="ReqResWithWebSockets">
<webSocketSettings transportUsage="Always"/>
</binding>
</netHttpBinding>
</bindings>
You can download the sample code from my SkyDrive which demonstrates all of the above including duplex, request-response, sessions, forcing WebSockets, and text encoded messages.
When considering the use of WebSocket via NetHttpBinding
for duplex communication vs. WsDualHttpBinding
and NetTcpBinding
, the benefits of NetHttpBindings
are:
- Like NetTcp, it requires one channel instead of two, as in the case of
WsDualHttp
. - Like NetTcp, it has a sessionful channel, unlike
WsDualHttp
which requires the use of WS-ReliableMessaging
. - Like NetTcp, it uses binary encoding which reduces the message size, unlike the text encoding of
WsDualHttp
. - Unlike NetTcp, it can overcome some firewall restrictions that prohibit TCP communication.
As we’ve seen so far, the WebSocket support in WCF 4.5 uses SOAP-based messages. In the next post, I will cover how to use WebSockets in WCF 4.5 to communicate with non-SOAP clients, such as web browsers, using simple text over WebSockets.