Practical .NET

Building a Simpler WebSockets Service

Peter pays a final visit to the WCF 4.5 WebSockets implementation to take advantage of the WebSocketService class and build a service in six lines of code (not counting configuration and client-side code, of course).

Over my last three columns, I've been exploring how to build a WebSockets service and a JavaScript client that can access the service (for why you'd want to do this, see my first column.)

I've built the service by configuring a duplex WCF service using the new bytestream encoding format included with WCF 4.5, and the standard WCF structure that uses an interface and SVC file with a code-behind file. While it all works and is compatible with the way other WCF services are built, the implementation required you to deal with byte arrays and a variety of low level issues.

WCF 4.5 has an alternative way of implementing a WebSocket Service that allows you to create a "Hello, World" WebSocket service in six lines of code (though, of course, you're free to add ore code to create more complex services). You don't need an interface file and you don't need an SVC file. To use this simpler alternative you do, however, still need Windows 8 configured as  described in my first column. And your first steps are still to create a Web application and use NuGet to add the Microsoft.WebSockets package to your project. You'll also need to add references to the both the System.ServiceModel.Activation and System.ServiceModel libraries, if they aren't already present.

With your project configured, you create your service by adding an ordinary class file to your application and have it inherit from Microsoft.ServiceModel.WebSockets.WebSocketService. You can then override the methods in this class that you want to use. To handle communication with the client, you can add code to the following methods:

  • OnOpen: called when the client first contacts the service
  • OnClose: called when the client closes its connection
  • OnError: called when an error occurs
  • OnMessage: called when the service receives a message from the service. There are two versions of this method: one that's called when the client sends an array of bytes, and one that's called when the client sends a simple string

To send a message to the client, you use the class' Send method. Like OnMessage, there are two versions of the Send method: one that sends a byte array, and one that sends a string value. These six lines override the string version of the OnMessage method, to send the message received from the client back to the client with the word "Hello" tacked on the front:

Public Class SimpleWS
  Inherits Microsoft.ServiceModel.WebSockets.WebSocketService
    
  Public Overrides Sub OnMessage(message As String)
        Me.Send("Hello, " & message)
  End Sub

End Class

As with the WebSockets implementation from previous columns, you can access any querystring parameters passed in the URL that the client uses to open the service -- just use the class' QueryParameters collection. Using the class' WebSocketContext object you can also retrieve any cookies that the client passes, look at the URL the client used to contact the service, and access other useful information. This example checks the querystring to see if a value was provided for the name "city" and if the URL used to call the service contains the string localhost:

If Me.QueryParameters("City") = "Regina" AndAlso
   Me.WebSocketContext.RequestUri.
          AbsolutePath.Contains("localhost") Then
          
Supporting the Service
While the service class is simple, you do need to add two additional pieces of support to your site. You must add a class to your site that inherits from ServiceHostFactory and override its CreateServiceHost method to add a WebSocket endpoint to your site (this eliminates the need for any configuration elements in your config file). In the the CreateServiceHost method, instantiate a WebSocketHost from the parameters passed to the method, call the host's AddWebSocketEndpoint method, and return the host:
Public Class PHVHostFactory
  Inherits System.ServiceModel.Activation.ServiceHostFactory

  Protected Overrides Function CreateServiceHost(
          serviceType As Type, baseAddresses() As Uri) 
              As ServiceModel.ServiceHost

    Dim host = New Microsoft.ServiceModel.WebSockets.
                 WebSocketHost(serviceType, baseAddresses)
    host.AddWebSocketEndpoint()
    Return host

  End Function

End Class

You also need to add a ServiceRoute to your site's RoutingTable in the Application Start event of your site's Global.asax file. The ServiceRoute ties the URL for your service to an instance of your factory class and the type of your service class. This example creates a URL for the service that includes the string SimpleOrderStatus (e.g., if the site's URL is http:www.localhost.com/MySite, this routing will create a URL for the service of ws:www.localhost.co/MySite/SimpleOrderStatus):

Sub Application_Start(
  ByVal sender As Object, ByVal e As EventArgs)

  Dim phvhf As New PHVHostFactory()
  Dim sr As New ServiceModel.Activation.ServiceRoute(
              "SimpleOrderStatus",
              phvhf,
              GetType(SimpleWS))
  Routing.RouteTable.Routes.Add(sr)

End Sub

Thanks to the ServiceHostFactory, the only system.serviceModel settings you need in your Web.config file are the ones to ensure that aspNetCompatibilityEnabled is turned on so that you can use routing:

<system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
</system.serviceModel>
Calling the Service
The JavaScript to call this service is identical to the code I used in my last column to call the more complicated SVC-and-interface WebSocket implementation. You create a WebSocket, passing the URL for your service (this example includes a querystring with a value for the name "city" that can be retrieved in the service's OnOpen method using the QueryParameters collection):

<script>
  $(document).ready(function () 
  {
    wss = new WebSocket(
     "ws://localhost/SimpleWebSockets/SimpleOrderStatus?city=Regina");

Once the WebSocket object is created, you need to register a function to execute whenever the service sends you a message, by attaching the function to the WebSockets onmessage event. This example catches the message and uses jQuery to append the message to an element with an id of orderStatusInfo somewhere in the page:

    wss.onmessage = function (status) 
    {
      $("#orderStatusInfo").append(status.data + "<br/>");
    };
 });
</script>

Once the socket's successfully opened, you can start sending messages to the service. This example ties a function to a button's onclick event that sends the string "Peter" to the service:

<input id="Button1" type="button" 
       value="button" onclick="callservice();"/>

<script type="text/javascript">
function callservice() 
{
  if (wss.readyState === wss.OPEN)
  {
    wss.send("Peter");
  }
  else
  {
    alert("Unable to contact service");
  }            
}
</script>

When the service sends a response message, the onmessage function will catch the message and insert it into the page.

As I said in my first column, I think that WebSockets is a critical technology for any SOA. My only regret about WCF 4.5's implementation of WebSockets? That it's only currently available on Windows 8. Hopefully, that will change.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus

Featured

  • Microsoft Highlights Visual Studio Live! Event Lineup and Longtime Developer Community Role

    A Microsoft MVP Blog post on Visual Studio Live!'s longevity arrives as the 2026 conference series continues with upcoming stops at Microsoft HQ, San Diego and Orlando.

  • Using Local AI to Cut Copilot Usage-Based Billing Shock

    After being gobsmacked by the new billing plan using almost all my monthly credits in one or two days, I tried pushing some Copilot-style coding work onto local models in VS Code. What I found was less "free AI" and more "pick your pain": cloud charges on one side, heavy local resource use and long waits on the other.

  • .NET 11 Preview 5 Focuses on Performance, Productivity and Safer Code

    .NET 11 Preview 5 focuses on under-the-hood runtime performance gains, streamlined APIs and language features that reduce boilerplate, plus built‑in security checks and incremental ASP.NET Core and EF Core improvements aimed at everyday developer productivity.

  • VS Code 1.124 Focuses on Agent Autonomy and Parallel Sessions

    Microsoft's June 2026 VS Code update turns on Autopilot by default and adds background sending for agent sessions.

Subscribe on YouTube