WebSockets on Windows Server 2012 with WCF 4.5

Hi, today I was wandering about new features in .NET 4.5 and I try to examine in practice WebSockets feature. This feature is supported by Windows Server 2012 only. And I try to find an elegant example of running it. There was not any interesting and elegant solution on the Internet so I prepared my own for this blog entry. I used Visual Studio 2012 to implement 3 assemblies WebSocketsSandbox.Contracts with interfaces, WebSocketsSandbox.Server with service host site implementation and WebSocketsSandbox.Client with client site implementation.

My running example was created on Windows 7 and it was running on Windows Server 2012, because that is the only one possibility to run WebSockets feature. You can see running Server and Client on the following screen.

image

As you can see WebSockets are not extremely fast or maybe I did something wrong when I created this simple implementation. My example is completely programmatically without any xml configuration because I used to Information Assurance requirements where such kind of configuration cannot be used.

I implemented my example in 3 files in 3 assemblies as follows.

Contract.cs (WebSocketsSandbox.Contracts)

namespace WebSocketsSandbox.Contracts
{
  using System.ServiceModel;
  using System.Threading.Tasks;

  [ServiceContract]
  public interface IClientCallback {
    [OperationContract(IsOneWay = true)]
    Task SendValues(string code, double value);
  }

  [ServiceContract(CallbackContract = typeof(IClientCallback), SessionMode = SessionMode.Required)]
  public interface ISendValuesService {
    [OperationContract(IsOneWay = true)]
    Task StartSendingValues();
  }
}

Server.cs (WebSocketsSandbox.Server)

namespace WebSocketsSandbox.Server
{
  using System;
  using System.Configuration;
  using System.ServiceModel;
  using System.ServiceModel.Channels;
  using System.ServiceModel.Configuration;
  using System.ServiceModel.Description;
  using System.Threading.Tasks;
  using WebSocketsSandbox.Contracts;

  class Server {
    static void Main(string[] args) {
      ConfigurationManager.AppSettings
        ["aspnet:UseTaskFriendlySynchronizationContext"] = "true";

      var mapping = new System.ServiceModel.Configuration.ProtocolMappingElementCollection();
      mapping.Add(
        element: new ProtocolMappingElement(
          schemeType: "http",
          binding: "netHttpBinding",
          bindingConfiguration: "default"));
      mapping.Add(
        element: new ProtocolMappingElement(
          schemeType: "https",
          binding: "netHttpsBinding",
          bindingConfiguration: "default"));

      ServiceHost serviceHost = null;

      try {
        string addressStr = "http://localhost:27272/WebSocketsServiceValues";

        var binding = new NetHttpBinding(
          securityMode: BasicHttpSecurityMode.None,
          reliableSessionEnabled: true);

        var addressUri = new Uri(uriString: addressStr);

        serviceHost = new ServiceHost(
          serviceType: typeof(SendValuesService),
          baseAddresses: addressUri);

        var endpoint = serviceHost.AddServiceEndpoint(
          implementedContract: typeof(ISendValuesService),
          binding: binding,
          address: addressUri);

        serviceHost.Open();

        Console.WriteLine(
          "WebSocketsServiceValues service is running, press any key to close...");
        Console.ReadKey();

      }
      catch (Exception ex) {
        Console.WriteLine(ex.ToString());
      }
      finally {
        serviceHost.Close();
      }
    }
  }

  [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
  class SendValuesService : ISendValuesService {
    public async Task StartSendingValues() {
      var callback = OperationContext.Current.GetCallbackChannel<IClientCallback>();
      var random = new Random();
      var count = 0;

      while (((IChannel)callback).State == CommunicationState.Opened) {
        var value = random.NextDouble();
        await callback.SendValues("WebSocketsServiceValue", value);
        if (++count == 1000000)
          break;
      }
    }
  }
}

Client.cs (WebSocketsSandbox.Client)

namespace WebSocketsSandbox.Client
{
  using System;
  using System.Collections.Generic;
  using System.ServiceModel;
  using System.ServiceModel.Description;
  using System.Threading;
  using System.Threading.Tasks;
  using WebSocketsSandbox.Contracts;

  class Client {
    static void Main(string[] args) {
      var context = new InstanceContext(
        implementation: new CallbackHandler());

      var binding = new NetHttpBinding(
        securityMode: BasicHttpSecurityMode.None,
        reliableSessionEnabled: true);

      var address = new EndpointAddress(
         uri: "http://localhost:27272/WebSocketsServiceValues");

      var channelFactory = new DuplexChannelFactory<ISendValuesService>(
        callbackInstance: context,
        binding: binding,
        remoteAddress: address);

      var client = channelFactory.CreateChannel(address: address);

      client.StartSendingValues();

      Console.WriteLine(
        "WebSocketsServiceValues client is running, press any key to close...");
      Console.ReadKey();
    }
  }

  class CallbackHandler : IClientCallback {
    int count = 0;

    public async Task SendValues(string code, double value) {
      Interlocked.Increment(ref count);
      if (count % 1000 == 0)
        Console.WriteLine("{0}, {1}",
          DateTime.UtcNow.ToString("HH:mm:ss.ffff"),
          count);
    }
  }
}

As you can see WebSockets with that implementation are very slow, it works much better without all async, await keywords and with void return type for services methods instead of Task return types. But, I try to show you exact way for full asynchronically WebSockets.

You may wonder about resource usage on that machine? There is something like follows.

image

Today I am not trying tune this solution up. I try to only show you a proper and nice way to create both Server and Client site implementations with extra assembly Contracts for both of them. I think that is the best patter and as you can see I did not create any service reference an such that not elegant things. I try to do everything simple and elegant. Performance of the solution is poor but you can simply play with this example and tune it up by treating this example as an exercise. I hope you enjoy this short example.

P ;).

One Reply to “WebSockets on Windows Server 2012 with WCF 4.5”

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.