SignalR. Code, not toothpaste. (or: Using SignalR for realtime client/server communication)
Today’s users are interested in a rich experience where the terms client and server don’t mean a thing. They expect real-time action between both, no matter if the technology used is HTML5 websockets or something else. This session will cover SignalR and show you how it can be used to communicate in real time between the client and server, using HTML5 or not. Combine SignalR with ASP.NET MVC, jQuery and perhaps a sprinkle of Windows Azure and you’ll have an interesting, reliable and fast stack to build your real-time client-server and server-client communications. Join me on this journey between web, cloud and user. No toothpaste. Just code.
6. USERS WANT THE LATEST INFORMATION, NOW!
Twitter – live searches/updates
Stock streamers
Auctions
Live scores
New e-mail
Real-time notifications
Interactive games
Collaborative apps
Analytics of users
…
JANUARY 23, 2012 | SLIDE 7
7. HTTP IS AN OLD BEAST…
Never designed for real-time communications
Web is request-response
Web is stateless
But…
HTML5 WebSockets to the rescue,
right?
JANUARY 23, 2012 | SLIDE 8
8. HTML5 WEBSOCKETS
Extension to HTTP
Provide raw sockets over HTTP
Full-duplex
Traverses proxies
It’s still a draft…
Not every proxy server supports it
Not every webserver supports it
Not every browser supports it
They are raw sockets!
JANUARY 23, 2012 | SLIDE 9
9. PERIODIC POLLING Fiddler
hootsuite.com
Bottom line:
Poll from time to time using Ajax
Delay in communications due to polling interval
Wastes bandwidth & latency
JANUARY 23, 2012 | SLIDE 10
10. LONG POLLING Fiddler
facebook.com
Bottom line:
Poll but don’t respond untill there’s data
Poll again after data received or after the connection times out
Consumes server threads & connection resources
JANUARY 23, 2012 | SLIDE 11
11. WHICH LEAVES US WITH 3 OPTIONS FOR REAL-TIME
Periodic polling
Long polling
HTML5 WebSockets
JANUARY 23, 2012 | SLIDE 12
12. ARRR!
MEET SIGNALR
JANUARY 23, 2012 | SLIDE 13
13. SIGNALR?
Three-in-one!
“Persistent” client/server connection over best transport
Abstracts away the transport
Provides just one programming model
David Fowler and Damian Edwards
(two guys on the ASP.NET team)
Not an official Microsoft project (yet?)
OSS project on Github, MIT licensed
http://github.com/signalr/signalr
Simple to setup & just works
Depends on C# (not VB.NET), .NET 4+ and jQuery
JANUARY 23, 2012 | SLIDE 15
14. WHERE DO I GET IT?
*
* where else!
JANUARY 23, 2012 | SLIDE 16
16. WHAT JUST HAPPENED?
The server is broadcasting a message every few seconds
Clients are receiving messages
Code looks easy
No polling or whatsoever (at least in my code)
JANUARY 23, 2012 | SLIDE 18
18. TWO CONNECTION MODELS
PersistentConnection Hubs
Can communicate with Can communicate with
1..N clients 1..N clients
Is an IHttpHandler Abstraction over
Requires a route to be PersistentConnection
defined Route automatically
Limited to sending mapped (/signalr/hubs)
messages Can send messages and
You define the call methods
“protocol” SignalR defines the
protocol
JANUARY 23, 2012 | SLIDE 20
20. HUBS
Hub methods can be called from client
Client methods can be called from hub
Target individual client
Target all clients
Target group of clients
http://jabbr.net
JANUARY 23, 2012 | SLIDE 22
22. SO FAR WE’VE USED…
On the server side:
Host in any ASP.NET application (SignalR.Server)
On the client side:
JavaScript (SignalR.JS)
But there’s more…
JANUARY 23, 2012 | SLIDE 24
24. THAT’S A LOT MORE!
On the server side:
Host in any ASP.NET application (SignalR.Server)
Use “SelfHost”
https://github.com/SignalR/SignalR/tree/master/SignalR.SelfHost
On the client side:
JavaScript (SignalR.JS)
Any .NET client (SignalR.Client)
Any WP7 device (SignalR.Client.WP7)
iOS
Android
Is this becoming a replacement for WCF?
JANUARY 23, 2012 | SLIDE 26
25. CONCLUSION
SignalR is three-in-one!
“Persistent” client/server connection over best transport
Abstracts away the transport
Provides just one programming model
Connections & Hubs
Connect various clients
Make the web real-time!
JANUARY 23, 2012 | SLIDE 27
26. RESOURCES
My blog:
http://blog.maartenballiauw.be
SignalR on Github:
http://github.com/signalr/signalr
SignalR on NuGet:
http://www.nuget.org/packages?q=signalr
Websockets:
http://github.com/signalr/signalr.websockets
Scale-out on Windows Azure:
http://github.com/signalr/signalr.azure
Objective C client:
https://github.com/DyKnow/SignalR-ObjC
Android client (using MonoDroid):
https://github.com/SignalR/SignalR/pull/127
JANUARY 23, 2012 | SLIDE 28
That’s a lot of options, a lot of thingsto account forand a lot of different programmingmodels. Are yougoingto do this?Are youstillwriting separategetDocumentByIdandAttachEventmethodstoworkwith the DOM? WhataboutjQuery?
Open VS2010Create a new ASP.NET Empty WebsiteInstall-PackageSignalRNote server library, client script, jQuery dependencyInstall-Package SignalR.Sample and show stock ticker in two browsersNowlet’s take things easy… How does all of thiswork?----------------- without Internet connection ----------------------------Add a class:public class TimeConnection : PersistentConnection{}Add a route:RouteTable.Routes.MapConnection<TimeConnection>("time", "time/{*operation}"); Addaninfinite loop:ThreadPool.QueueUserWorkItem(_ => { var connection = Connection.GetConnection<TimeConnection>();while (true) {connection.Broadcast(DateTime.Now.ToString());Thread.Sleep(1000); } });Addsome HTML:<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title> <script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script> <script src="Scripts/jquery.signalR.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { var connection = $.connection('time');connection.received(function(data) { $('h1').text('The time is ' + data); });connection.start(); }); </script></head><body> <h1>The time is now!</h1></body></html>----------------- without Internet connection --------------------------------------------- with Internet connection ----------------------------Install-Package LinqToTwitterAdd a class:public class TweetsConnection : PersistentConnection{}Add a route:RouteTable.Routes.MapConnection<TweetsConnection>("tweets", "tweets/{*operation}"); Addaninfinite loop:ThreadPool.QueueUserWorkItem(_ => { var connection = Connection.GetConnection<TweetsConnection>();while (true) {using (TwitterContext context = new TwitterContext()) { var tweets = context.Search.Where(t => t.Type == SearchType.Search && t.Query == "#test").SingleOrDefault().Entries;connection.Broadcast(tweets.ToList()); }Thread.Sleep(5000); } });Addsome HTML:<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title> <script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script> <script src="Scripts/jquery.signalR.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { var connection = $.connection('tweets');connection.received(function (data) { $('#tweetsList').html('');for (var i = 0; i < data.length; i++) { $('#tweetsList').append($('<li>' + data[i].Content + '</li>')); } });connection.start(); }); </script></head><body> <h1>Tweets</h1> <ulid="tweetsList"></ul></body></html>----------------- with Internet connection ----------------------------Notice we are sending data TO the client?
Open the previouslycreated sampleInstall-Package jQuery.UI.CombinedAdd a class: [HubName("worker")] public class WorkerHub : Hub { public voidstartProcessing(Event e) {Caller.notify("We'vestarted processing " + e.EventName);Clients.setProgress(10);for (int i = 0; i <= 100; i++) {SignalR.Hubs.Hub.GetClients<WorkerHub>().setProgress(i);Thread.Sleep(100); } } }Addsome HTML:<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title> <link rel="stylesheet" href="Content/themes/base/jquery.ui.all.css" /> <script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script> <script src="Scripts/jquery-ui-1.8.16.min.js" type="text/javascript"></script> <script src="Scripts/jquery.signalR.js" type="text/javascript"></script> <script src="signalr/hubs" type="text/javascript"></script> <script type="text/javascript"> $(function () { var workerHub = $.connection.worker; $('#progressbar').progressbar({ value: 0 }); $('#startWorkTrigger').bind('click', function () {workerHub.startProcessing({ eventName: 'UAN12' }) .fail(function (e) { alert("An error occured: " + e); }); });workerHub.notify = function (message) { $('#notifications').html(message); };workerHub.setProgress = function (progress) { $('#progressbar').progressbar({ value: progress }); }; $.connection.hub.start(); }); </script></head><body> <div id="progressbar" style="width: 200px;"></div> <div id="notifications" style="width: 200px;"></div> <button id="startWorkTrigger">Start work</button></body></html>
Open DeckCastShow peoplearoundandtellthemabout deck.jsShow the presenter mode andclient mode on the webStart a console based viewerStart the WP7 presenter app (focus/unfocus the “sample” box toconnect, click SLOWLY)