SignalR - Web Sockets
SignalR is a cool asynchronous signaling library for ASP.NET to build real-time applications or for any push based notifications. SignalR is similar to Socket.IO or NowJS. Before the workd of web-sockets, there was Comet which was basically a long-held HTTP requests.
SignalR can be downloaded from NuGet [http://www.nuget.org] and downloading the files manually from Git [https://github.com/SignalR/SignalR]
More descriptive information on SignalR can be found at Scott Hanselman’s site [http://www.hanselman.com/blog/AsynchronousScalableWebApplicationsWithRealtimePersistentLongrunningConnectionsWithSignalR.aspx]
To get SignalR up and running following are few todo’s on server side:
Step 1 is to create a PersistentConnection class like follows
1 | <br /> using SignalR;<br /> using System.Threading.Tasks;<br /><br /> namespace Services<br /> {<br /> public class MyConnection : PersistentConnection<br /> {<br /> protected override Task OnReceivedAsync( string clientId, string data)<br /> {<br /> // Broadcast data to all clients<br /> return Connection.Broadcast(data);<br /> }<br /> }<br /> }<br /> |
Note that Connection.Broadcast would send the data to all connected clients. If you need to sent to a particular client you can use the Send method.
Send(string clientId, object value);
Note Send requires the intended clientId. If you were to be building a chat client or a custom push service, you probably would be storing clientId’s somewhere in a local object or a central repo.
Other useful functions that PersistantConnection class provides that can be overridden:
1 | <br /> public void AddToGroup( string clientId, string groupName);<br /> protected virtual void OnConnected(HttpContextBase context, string clientId);<br /> protected virtual Task OnConnectedAsync(HttpContextBase context, string clientId);<br /> protected virtual void OnDisconnect( string clientId);<br /> protected virtual Task OnDisconnectAsync( string clientId);<br /> protected virtual void OnError(Exception e);<br /> protected virtual Task OnErrorAsync(Exception e);<br /> protected virtual void OnReceived( string clientId, string data);<br /> protected virtual Task OnReceivedAsync( string clientId, string data);<br /> public void RemoveFromGroup( string clientId, string groupName);<br /> public void Send( object value);<br /> public void Send( string clientId, object value);<br /> public void SendToGroup( string groupName, object value);<br /> |
Step 2 is to add the routes if you are using MVC. This route needs to be registered in Global.asax
1 | <br /> protected void Application_Start()<br /> {<br /> Bootstrapper.Run();<br /> RouteTable.Routes.MapConnection<Services.MyConnection>( "Notification" , "Notification/{*operation}" );<br /> RegisterRoutes(RouteTable.Routes); <br /> AreaRegistration.RegisterAllAreas();<br /> }<br /> |
That’s pretty much it on the server side
Step 3, if the intended client is a web browser it’s as easy as follows:
That’s all is to SignalR setup. A chat type client would require some sort of client association on the server side to keep communication private.
But what about non-browser based apps, like a console app or a windows service. SignalR has libraries for those too, can be downloaded from NuGet.
In real world applications, no project ends up with a single instance, single class project. In real world apps, there are many class’s and class’s are initialized and disposed all the time. In this scenario opening and closing a SignalR connection or instializing a new SignalR object is a wrong approach since you want be connected to the server all time.
One way to keep the connection persistant is to create a static signalR object, in following case it’s a singleton class
1 | <br /> using SignalR.Client;<br /><br /> public sealed class PushClass<br /> {<br /> private static volatile PushClass instance;<br /> private static object syncRoot = new Object();<br /> private Connection broadcastConnection;<br /><br /> private PushClass() <br /> {<br /> broadcastConnection = new Connection( "http://localhost/Notification" );<br /> broadcastConnection.Start().Wait();<br /> }<br /><br /> public static PushClass Instance<br /> {<br /> get <br /> {<br /> if (instance == null )<br /> {<br /> lock (syncRoot)<br /> {<br /> if (instance == null )<br /> instance = new PushClass();<br /> }<br /> }<br /><br /> return instance;<br /> }<br /> }<br /><br /> public void Broadcast( string msg)<br /> {<br /> broadcastConnection.Send(msg);<br /> }<br /> }<br /> |
A calling class can get an the instance of the above PushClass
1 | <br /> var pushInstance= PushClass.Instance;<br /> pushInstance.Broadcast(“blah”);<br /> |
Another way but fancier way to achieve the same persistant effect could be like follows:
1 | <br /> public class PushClass<br />{<br /> public static void Broadcast( string data)<br />{<br /> try <br />{<br />var client = new SignalR.Client.Connection( "http://localhost/Notification" );<br />var tx = client.Start().ContinueWith(t =><br />{<br /> if (t.IsFaulted) Console.WriteLine(t.Exception.GetBaseException()); client.Send(data).ContinueWith(t2 =>{ if (t2.IsFaulted) Console.WriteLine(t2.Exception.GetBaseException());<br />});<br />});<br />tx.ContinueWith(y =>{<br /> if (y.IsFaulted || y.Exception != null )<br />Console.WriteLine(y.Exception.Message);<br />});<br />tx.Wait();<br />}<br /> catch (Exception ex)<br />{<br />Console.WriteLine(ex.Message);<br />}<br />}<br />}<br /> |
The calling class can do the following:
1 | <br /> Task asyncSignalr = Task.Factory.StartNew(() => PushClass.Broadcast( "blah" );<br /><br /> asyncSignalr.ContinueWith(t =><br /> {<br /> if (t.IsFaulted)<br /> Console.WriteLine(t.Exception.Flatten().ToString());<br /> });<br /> |
Labels: CSharp, WebSockets
<< Home