WebSockets with WCF
Notification & “Duplex communication” are important scenario over the internet but firewalls and browser limitations makes them very hard to implement. In the browser world, tricks like long polling is commonly used to implement server-push requirements. For non-browser scenarios relay technologies like Azure Service Bus overcome the lack of inbound connectivity by creating a relay in the cloud where both client & server connects by making an outbound connection. Both long polling & relay works but are not optimum solutions due to latency and the complexity involved.
WebSockets is designed to address some of these limitation. With WebSockets, a client & server can upgrade an existing HTTP connection to a full-duplex TCP/IP connection or setup a new WebSockets connection using an HTTP based handshake. WebSockets uses standard HTTP ports (80, 443) so it’s just works with Firewall & the existing security infrastructure. WebSockets technology bucket has following two parts:
- WebSockets Protocol (Currently being standardized by IETF)
- WebSockets JavaScript API (Currently being standardized by W3C)
Windows “8” has native support for WebSockets protocol & there are quite a few API (native & managed) available for programing WebSockets servers & clients on windows. In addition, IE 10 supports both Web Sockets protocol & the JavaScript API.
Client:
- IE 10
- WinRT
Server:
- Native windows implementation ( >= Windows “8”)
- IIS 8.0
- System.Net.WebSockets (Managed Wrapper)
- HttpListener
- System.Web (ASP.net)
- HttpContext
- System.ServiceModel (WCF)
- NetHttpBinding
WCF supported duplex services since V1 but these required either a duplex transport binding (netTcpBinding, netNamedPipeBinding) or wsDualHttpBinding which forces a client to have a public URI accessible to service (and to the world ) running on the public internet.
wsDualHttpBinding is not really suitable for internet scenarios due to inbound connectivity issues. NetTcpBinding could also be problematic in tightly-locked down environments allowing only outbound connections to port 80/443.
With the WebSockets support in Windows, WCF introduced a new Binding NetHttpBinding which does binary SOAP messaging over WebSockets protocol and overcome the limitations of existing bindings. Below I created a basic duplex WCF service
Basic Service
[ServiceContract(CallbackContract=typeof(IPing))]
public interface IPing
{
[OperationContract(IsOneWay=true)]
void Ping(string msg);
}
class PingService : IPing
{
public void Ping(string msg)
{
Console.WriteLine("Service: {0}",msg);
var chnl = OperationContext.Current.GetCallbackChannel<IPing>();
chnl.Ping(string.Format("You said \"{0}\"?", msg));
}
}
Standard WCF hosting code with one endpoint using the new binding (line 5 & 14)
Hosting
static void Main(string[] args)
{
var sh = new ServiceHost(typeof(PingService),
new Uri("https://localhost:9090/"));
var binding = new NetHttpBinding();
sh.AddServiceEndpoint(typeof(IPing), binding, "Ping");
sh.Open();
Console.WriteLine("Service ready…");
var cf = new DuplexChannelFactory<IPing>(
new InstanceContext(new PingBack()),
binding,
new EndpointAddress("https://localhost:8080/Ping"));
var chnl = cf.CreateChannel();
chnl.Ping("Hello!");
Console.WriteLine("Finishing…");
Console.ReadLine();
}
and finally my callback handler class.
Callback handler
public class PingBack : IPing
{
public void Ping(string msg)
{
Console.WriteLine("Client: {0}",msg);
}
}
Running the project I get the expected output.
By default, WebSockets protocol is allowed on NetHttpBinding i.e. if your contract is a Duplex contract NetHttpBinding automatically upgrades to WebSockets protocol. Out of box, this binding does SOAP messaging and encodes SOAP using the WCF binary encoding. You can reuse the WebSockets transport binding element in a custom binding to support other encodings & protocols and I’ll talk about this in a future post.
Original Post by Zulfiqar Ahmed on November 23rd, 2011