Sample 02 - SubProtocol
The web socket protocol has support for so-called sub-protocols. These are protocols that you yourself define and with Nugget they can be used to send "models" between the browser and the server.Typically the data you send between the server and the browser would be JSON but it could be on any format. In the app on the server you define a model factory that analyses the data coming from the browser and wraps it in an object of a specified type, this is then passed on to the socket handler.
The sample contains two files: client.html and Server.cs, they represent the client and the server respectively.
client.html
Like in sample 01 this file contains the javascript:ws = new WebSocket('ws://localhost:8181/subsample', 'post'); ws.onmessage = function (evt) { debug.innerHTML += evt.data + '<br/>'; }; ws.onopen = function () { debug.innerHTML += '.. connection open<br/>'; }; ws.onclose = function () { debug.innerHTML += '.. connection closed<br/>'; }
The file also contains some input fields, and some javascript used to send data to the server:
<inputtype="text"name="name"id="name"placeholder="name"/><br/><textareaid="message"cols="50"rows="5"placeholder="message"></textarea><br/><inputtype="button"value="Send"id="submit_button"onclick="clicks()"/>
var clicks = function () { // get the author and the message bodyvar name = document.getElementById('name').value; var msg = document.getElementById('message').value; // create a json stringvar json = JSON.stringify({ author: name, body: msg }); debug.innerHTML += "sending " + json + "<br/>"; // send it ws.send(json); }
Server.cs
Like in sample 01 we are using a handler class to handle the connection server-side:// the handler class// note that the class inherits the generic interface and uses the model as the type parameterclass PostSocket : WebSocket<Post> { // this method is called when data is comming from the client// note that the method takes a Post object instead of a stringpublicoverridevoid Incomming(Post post) { Console.WriteLine("{0} posted {1}", post.Author, post.Body); } publicoverridevoid Disconnected() { Console.WriteLine("--- disconnected ---"); } publicoverridevoid Connected(ClientHandshake handshake) { Console.WriteLine("--- connected ---"); } }
// a "model" representing a post made by someoneclass Post { publicstring Author { get; set; } publicstring Body { get; set; } publicbool IsValid() { return !String.IsNullOrEmpty(Author) && !String.IsNullOrEmpty(Body); } }
// the model factory// this class is used to convert the data coming from the client into a model objectclass PostFactory : ISubProtocolModelFactory<Post> { // create a new model// "data" is the data comming from the client// "connection" is an object representing the connection to the client, it can be used to identify the client if neededpublic Post Create(string data, WebSocketConnection connection) { // parse the data (we assume that the data string is on json format)var js = JSON.Parse(data); if (js.hasOwnProperty("author") && js.hasOwnProperty("body")) { // create a new model using the data from the client// "return" passes the model on to the handler classreturnnew Post() { Author = js.author, Body = js.body }; } returnnull; } // this method is used to define valid models// if a model is not valid, then it is not passed on to the handler class// this method is called internally in the server before the model is passed onpublicbool IsValid(Post p) { if (p == null) returnfalse; elsereturn p.IsValid(); } }
publicinterface ISubProtocolModelFactory<TModel> { TModel Create(string data, WebSocketConnection connection); bool IsValid(TModel model); }
IsValid, should return true for valid models and false for invalid models. This method is used to determine whether or not to pass the object along to the handler class. If Create, creates a model that is invalid (null in this case) the model is not passed on to the handler class.
In a sense you jam a "parser" in between the browser and the server. The model factory (the "parser") reads, validates and formats the data coming from the browser, before passing it on to the handler class.
The handler classes can have multiple Incoming methods defined, by implementing the IWebSocket<> interface.
class MyHandler : WebSocket<MyModel>, IWebSocket<MyOtherModel> { public overide Incoming(MyModel mm) { /* ... */ } public Incoming(MyOtherModel mom) { /* ... */ }
The model factory is registered with the following line:
nugget.SetSubProtocolModelFactory(new PostFactory(), "post");
Where the string specifies which sub protocol to use the factory for.