In previous blog posts I wrote about using Server-Sent Events so send data from the server to the browser. This works but has the drawback that it is a one way messaging from the server to the browser. There is nothing preventing you from doing ajax style calls back to the server but basically you are using 2 connection. The big plus for Server-Sent Events is that is use standard HTTP connections so the infrastructure is no problem.
WebSockets
Sometimes you want more flexibility of duplex communication and this is where WebSockets come in. Opening a connection from the browser is simply a question of instantiating a WebSocket object and passing in the required URL. The difference is this time we are not using HTTP but the WS scheme so the connection URL looks something like ws://api.myserver.com/chatService. Sounds simple enough but as WebSockets are relatively new you do run a very real risk that some of the infrastructure that works fine with HTTP request will not work with WS requests. But for a demo on a local machine that is no problem
The client code
The code on the client is actually quite simple. First we new up the WebSocket and we start listening for onmessage events. There are a few more events that are interesting:
- The onopen event fires when the connection is opened
- The onclose event fires when the connection is closed
- The onerror event that fires when something goes wrong.
To send data you use the send() method that takes a single string to send to the server. Hint: Use JSON.stringify() to turn you rich object into a string.
I wrote a very simple chat client to demonstrate how to work with WebSockets.
The complete JavaScript in the page is as follows:
1: function displayMessage(msg) {
2: $('<li>').text(msg).appendTo('#messages');
3: }
4:
5: var WebSocket = WebSocket || MozWebSocket;
6: var myWebSocket = new WebSocket("ws://localhost:8181");
7: myWebSocket.onopen = function (evt) {
8: $('#btn, #name, #msg').attr('disabled', '');
9:
10: };
11: myWebSocket.onmessage = function (evt) {
12: var data = JSON.parse(evt.data);
13: if (data.name === $('#name').val()) {
14: displayMessage('(me): ' + data.msg);
15: }
16: else {
17: displayMessage(data.name + ': ' + data.msg);
18: }
19: };
20: myWebSocket.onclose = function (evt) {
21: displayMessage("Connection closed.");
22: $('#btn, #name, #msg').attr('disabled', 'disabled');
23: };
24:
25: $('#btn').click(function (e) {
26: e.preventDefault();
27: myWebSocket.send(JSON.stringify({
28: name: $('#name').val(),
29: msg: $('#msg').val()
30: }));
31: $('#msg').val('')
32: });
Not bad right
One thing to note is the way I create the WebSocket object:
1: var WebSocket = WebSocket || MozWebSocket;
2: var myWebSocket = new WebSocket("ws://localhost:8181");
I am using the expression WebSocket || MozWebSocket because support for WebSockets is still very experimental and FireFox still uses the Moz prefix. See CanIUse.com for more details about browser support.
The server part.
With Server-Sent Events the server part was easy and standard web stuff because we are just using HTTP. With WebSockets this is no longer the case as we are using a socket style connection using the WS scheme. So we need some extra support on the server. As I am doing .NET I want a .NET 4 solution on the server, there are several other non .NET solutions as well. If we search NuGet we see there are thee different WebSocket packages. One is part of WCF 4.5 and an other, SignalR.WebSockets, that is build on top of it. Now SignalR is an awesome product but as this requires .NET 4.5 and this isn’t released yet I am going with the third option, Fleck, which does run on .NET 4 as is.
Fleck is pretty easy to use, just new up an WebSocketServer with the URL to start listening and it has pretty much the same interface as the WebSocket on the client. Whenever a client connects the OnOpen is called and when a message is received the OnMessage callback fires. My ASP.NET MVC home controller looks like this:
1: public class HomeController : Controller
2: {
3: private static List<IWebSocketConnection> allSockets = new List<IWebSocketConnection>();
4:
5: static HomeController()
6: {
7: var server = new WebSocketServer("ws://localhost:8181");
8: server.Start(socket =>
9: {
10: socket.OnOpen = () =>
11: {
12: allSockets.Add(socket);
13: };
14: socket.OnClose = () =>
15: {
16: allSockets.Remove(socket);
17: };
18:
19: socket.OnMessage = message =>
20: {
21: allSockets.ToList().ForEach(s => s.Send(message));
22: };
23: });
24: }
25:
26: public ActionResult Index()
27: {
28: return View();
29: }
30: }
Again pretty simple to use
Of course real life isn’t quite as simple as this demo. For one you are now using a direct connection between the browser and one of your servers so any form of load balancing is out of the question here. And as this is real new its quite likely that you will run into routers, proxy severs or the like that don’t support WebSockets. If you really need this functionality now looking at a package as SignalR which makes all of this a lot more reliable makes sense. And the standard SignalR package will work just fine on existing .NET 4
Enjoy!
[f1]
[f2]
Hey Maurice!
That looks awesome!
I’ve been doin Websocket stuff on node.js and socket.io lately but I’d like to try that on .NET myself.
Unfortunately my C# skills are kinda limited…
I’m wonderin if you could lend me a hand on setting up Fleck and the according C#-project?
I just need to know how to include Fleck and what kind of project to create in VS…
Thanks a ton in advance!
My email: jm053 (at) hdm-stuttgart.de
Greets
Jan