WebSockets are bidirectional, full-duplex channels that start as HTTP channels and use handshakes to upgrade the channels to WebSockets, with real, two-way TCP communication between the client and the server. The added benefit is that all of this can happen through port 80 and that they are router friendly.
In this recipe, we will see how to create and consume a WebSockets service.
In order to use this recipe, you should have Windows 8 with Visual Studio 2012 installed. WebSockets are only supported natively on Windows 8; see http://msdn.microsoft.com/en-us/library/hh159285.aspx.
Here, we are going to set up our system in order to support WebSockets and implement a basic WebSocket.
WebSocketsWcf
and click on the OK button.WebSocketsService.svc
and click on the Add button.IWebSocketsService.cs
file and replace the code with the following:[ServiceContract(CallbackContract = typeof(IWebSocketsServiceCallback))] public interface IWebSocketsService { [OperationContract(IsOneWay = true)] Task StartSendingData(); }
System.Threading.Tasks
to add support for asynchronous operations and types.IWebSocketsServiceCallback
exception, which we will solve on the next step.IWebSocketsServiceCallback.cs
class and add the following code:[ServiceContract] public interface IWebSocketsServiceCallback { [OperationContract(IsOneWay = true)] Task SendData(string data); }
usings
clause for System.Threading.Tasks
and for the System.ServiceModel
namespaces.WebSocketsService.svc.cs
file and substitute the following for the code:public class WebSocketsService : IWebSocketsService { public async Task StartSendingData() { Var callbackFunction = OperationContext.Current.GetCallbackChannel<IWebSocketsServiceCallback>(); while ((callbackFunction as IChannel).State == CommunicationState.Opened) { await callbackFunction.SendData("Hi, the time is : " + DateTime.Now.ToLongTimeString()); await Task.Delay(5000); } } }
System.Threading.Tasks
and System.ServiceModel.Channnels
.Web.Config
file and substitute the following for the code:<?xml version="1.0"?> <configuration> <appSettings> <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" /> </appSettings> <system.web> <compilation debug="true" targetFramework="4.5" /> <httpRuntimetargetFramework="4.5" /> </system.web> <system.serviceModel> <protocolMapping> <add scheme="http" binding="netHttpBinding" /> <add scheme="https" binding="netHttpsBinding" /> </protocolMapping> <behaviors> <serviceBehaviors> <behavior name=""> <serviceMetadatahttpGetEnabled="true" httpsGetEnabled="true" /> <serviceDebugincludeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors> <serviceHostingEnvironmentaspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> </system.serviceModel> </configuration>
WebSocketsConsoleClient
and press the OK button.WebSocketsServiceReference
and press the OK button.class WebSocketsCallBackHandler : WebSocketsServiceReference.IWebSocketsServiceCallback { public void SendData(string data) { Console.WriteLine("Received data from the WebSockets service: " + data); } }
Program.cs
file and substituting the main method with the following code:static void Main(string[] args) { try { Var InstanceCtx = new InstanceContext(new WebSocketsCallBackHandler()); Var WebSocketsClient = new WebSocketsServiceReference.WebSocketsServiceClient(InstanceCtx); WebSocketsClient.StartSendingData(); Console.ReadLine(); } catch (Exception ex) { throw; } }
using
clause for the System.ServiceModel
namespace.App.config
file that was autogenerated when we added the service reference, and validate that the endpoint definition has its binding set to netHttpBinding.First, we configured our Windows 8 operating system to support WebSockets, ASP.NET 4.5, and HTTP activation features. It is necessary to have .NET 4.5 on the operating system, either by installing it automatically when performing the installation of Visual Studio 2012 or by installing it as a standalone.
Note that WebSockets will not run on previous operating systems that don't have IIS8 installed, so this feature is unsupported natively on Windows 7.
We created an ASP.NET web app to host our web service and added the following attribute to it:
[ServiceContract(CallbackContract = typeof(IWebSocketsServiceCallback))]
Essentially, we are defining ServiceContract
and setting up IWebSocketsServiceCallback
as the callback context.
Then on the interface, we added just one method, StartSendingData()
, with the attribute:
[OperationContract(IsOneWay = true)]
This indicates that this method will only move in one direction, that is, from the client to the server. We are going to use it as a handshake that will set up the communication between the client and the server.
Note that we are using tasks, so this will comply with the async
/await
model that .NET 4.5 can be proud of.
Next we have created IWebSocketsServiceCallback
, which is also a service contract, where we defined the SendData()
method task that we set to follow a one-way route. We will obviously use this to send data which the clients usually updates. Note that we need to implement this on the client too, for this to work properly.
To continue, we need to implement the interfaces we just defined. For WebSocketsService
, we set up the
StartSendingData()
method that gets the current callback channel. While the channel is open, we keep on executing asynchronous calls to the callback method.
In order to finish the server part, we use configuredWeb.Config
where we have added a protocol mapping for HTTP and HTTPS to netHttpBinding
/netHttpBindings
, which we will use for our WCF endpoints.
We built the project and added a console application that will be the client of our service. In the console application, we had to add a service reference to our recently created web service.
We created a class called WebSocketsCallBackHandler
to hold our implementation of the callback method. The received data is redirected to the console with a WriteLine
command.
In our main method, we'll create an instance of this class with the callback handler class as its parameter, thus generating a client for our web service. From the following instance, we just call the handshake method that will trigger the server to start sending data.
Var InstanceCtx = new InstanceContext(new WebSocketsCallBackHandler()); Var WebSocketsClient = new WebSocketsServiceReference.WebSocketsServiceClient(InstanceCtx); WebSocketsClient.StartSendingData();
And that's all there is to it! Notice how, despite its power, the solution is extremely simple.