Applications SignalR can build:
- Chat
- customer support
- Gaming
- Live Scoring
- Live Trending (stock pricing, air flights, rates, exchange rates, survey)
- and many more…
Where is the Finished Product?
Screen Shots
Let us take a look at the LiveScore Application that we will be building.
The Admin Panel | The Viewer Panel |
- Visual Studio 2012/2013 (I used VS 2012 here but your can use VS 2013)
- Microsoft.AspNet.SignalR (the version uses here is 2.1.0)
- Asp.Net Empty Web Application
- BootStrap.css
- BootStrap.js
- Glyphicons font
- jQuery
- CSS
- Html
Go to Package Manager Console and type Install-Package Microsoft.AspNet.SignalR or go to Package Manager (Manage Nuget Package) and select Microsoft ASP.NET SignalR.
SignalR Version
The version we will using here is Microsoft.AspNet.SignalR 2.1.0.
How Do We Build It?
1. First, created new project, use C#, ASP.NET Empty Web Application.
2. Install the Microsoft.AspNet.SignalR.
3. Start coding.
The Server Side
Create the Startup.cs
This class will simply start the SignalR api.
Startup.cs
Create the Proxy Hub
This is the class that client sides call upon whenever it pushes data. The server(ScoreHub.cs) can also call and pushes data on the client side by invoking the Clients class.
Note: When calling Client methods in c#, it should be in camel case.
eg: Clients.Caller.getScore(_score);
ScoreHub.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNet.SignalR; | |
using LiveScore.Model; | |
namespace LiveScore | |
{ | |
public class ScoreHub : Hub | |
{ | |
static Score _score = new Score(); | |
public void Connect() | |
{ | |
Clients.Caller.getScore(_score); | |
} | |
public void GameConfigure(Score Score) | |
{ | |
_score.TeamName1 = Score.TeamName1; | |
_score.TeamName2 = Score.TeamName2; | |
_score.Team1Score = 0; | |
_score.Team2Score = 0; | |
SendScore(); | |
} | |
public void UpdateScore(Score Score) | |
{ | |
_score.TeamName1 = Score.TeamName1; | |
_score.Team1Score = Score.Team1Score; | |
_score.TeamName2 = Score.TeamName2; | |
_score.Team2Score = Score.Team2Score; | |
SendScore(); | |
} | |
public void SendScore() | |
{ | |
Clients.All.getScore(_score); | |
} | |
} | |
} | |
The Score.cs
This is a model where the score data will be stored.
Score.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace LiveScore.Model | |
{ | |
public class Score | |
{ | |
public string TeamName1 { get; set; } | |
public int Team1Score { get; set; } | |
public string TeamName2 { get; set; } | |
public int Team2Score { get; set; } | |
} | |
} |
The Client Side
We need 2 Html files and 1 JavaScript file.
- index.html = Viewers page
- admin.html = Admin page
- site.js = Use in index.hml. It is use to communicate with the server(Hub Proxy) and vice versia.
- admin.js = Use in admin.html. It is use to to communicate with the server(Hub Proxy) and vice versia.
index.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1" /> | |
<title>LiveScore</title> | |
<link rel="stylesheet" href="/Css/JQueryUI/themes/base/jquery.ui.all.css" /> | |
<link href="Css/bootstrap.min.css" rel="stylesheet" /> | |
<link href="Css/amelia-bootstrap.min.css" rel="stylesheet" /> | |
<link href="Css/footerBottom.css" rel="stylesheet" /> | |
<link href="Css/Site.css" rel="stylesheet" /> | |
<script src="/Scripts/jquery-1.8.2.min.js"></script> | |
<script src="Scripts/jquery.signalR-2.1.0.min.js"></script> | |
<!--Reference the autogenerated SignalR hub script. --> | |
<script src="/signalr/hubs"></script> | |
</head> | |
<body> | |
<div id="wrapper"> | |
<header> | |
<div class="navbar navbar-default" role="navigation"> | |
<div class="container"> | |
<div class="navbar-header"> | |
<button class="btn btn-success navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> | |
<span class="glyphicon glyphicon-chevron-down"></span> | |
</button> | |
<a class="navbar-brand" href="#">Live Score</a> | |
</div> | |
<div class="navbar-collapse collapse"> | |
<ul class="nav navbar-nav navbar-right"> | |
<li class="nav active"><a href=".">Home</a> | |
</li> | |
<li class="nav"><a href="Admin.html">Admin</a> | |
</li> | |
<li class="nav"><a href="About.html">About</a> | |
</li> | |
</ul> | |
</div> | |
</div> | |
</div> | |
</header> | |
<div class="content container"> | |
<div id ="boxScore"> | |
<div class="form-horizontal col-md-6 col-sm-5 scoreBox box-shadow"> | |
<div id="alertMsg" class="alert alert-warning collapse"> | |
No Games today !!! Try refreshing later. | |
</div> | |
<div id="objectToAnimate"> | |
<div class="form-group"> | |
<div class="col-md-4 col-sm-3" id="Team1"> | |
</div> | |
<div class="col-md-1 col-sm-3 col-xs-3" id="Score1"> | |
</div> | |
</div> | |
<div class="form-group"> | |
<div class="col-md-4 col-sm-3" id="Team2"> | |
</div> | |
<div class="col-md-1 col-sm-3 col-xs-3" id="Score2"> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<footer> | |
<div class="container float-left"> | |
<p>© Copyright CodexSquare</p> | |
</div> | |
</footer> | |
</div> | |
<script src="Scripts/bootstrap.min.js"></script> | |
<script src="Scripts/Site.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1" /> | |
<title>LiveScore Admin</title> | |
<link href="Css/bootstrap.min.css" rel="stylesheet" /> | |
<link href="Css/amelia-bootstrap.min.css" rel="stylesheet" /> | |
<link href="Css/footerBottom.css" rel="stylesheet" /> | |
<script src="/Scripts/jquery-1.8.2.min.js"></script> | |
<script src="Scripts/jquery.signalR-2.1.0.min.js"></script> | |
<script src="/signalr/hubs"></script> | |
</head> | |
<body> | |
<div id="wrapper"> | |
<header> | |
<div class="navbar navbar-default" role="navigation"> | |
<div class="container"> | |
<div class="navbar-header"> | |
<button class="btn btn-success navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> | |
<span class="glyphicon glyphicon-chevron-down"></span> | |
</button> | |
<a class="navbar-brand" href="#">Live Score</a> | |
</div> | |
<div class="navbar-collapse collapse"> | |
<ul class="nav navbar-nav navbar-right"> | |
<li class="nav"><a href=".">Home</a> | |
</li> | |
<li class="nav active"><a href="Admin.html">Admin</a> | |
</li> | |
<li class="nav"><a href="About.html">About</a> | |
</li> | |
</ul> | |
</div> | |
</div> | |
</div> | |
</header> | |
<div class="content container"> | |
<div id="alertMsg" class="alert alert-warning collapse"> | |
</div> | |
<ul class="nav nav-tabs" id="LiveTabs"> | |
<li><a href="#scoreBoardTab" data-toggle="tab">Scoreboard</a> | |
</li> | |
<li class="active"><a href="#settingsTab" data-toggle="tab">Settings</a> | |
</li> | |
</ul> | |
<div class="tab-content"> | |
<div class="well tab-pane" id="scoreBoardTab"> | |
<div class="form-horizontal"> | |
<div class="form-group"> | |
<div class="col-md-2" id="Team1NameScoreBoard"> | |
<label for="Team1Score" class="control-label">Not set</label> | |
</div> | |
<div class="col-md-1 col-sm-4 col-xs-4"> | |
<input type="number" id="Team1ScoreBoardScore" name="Team1ScoreBoardScore" class="form-control" /> | |
</div> | |
</div> | |
<div class="form-group"> | |
<div class="col-md-2" id="Team2NameScoreBoard"> | |
<label for="Team2Score" class="control-label">Not set</label> | |
</div> | |
<div class="col-md-1 col-sm-4 col-xs-4"> | |
<input type="number" id="Team2ScoreBoardScore" name="Team2ScoreBoardScore" class="form-control" /> | |
</div> | |
</div> | |
</div> | |
<hr /> | |
<div> | |
<input type="button" class="btn btn-success" id="SendScore" value="Send Score" /> | |
</div> | |
</div> | |
<div class="well tab-pane active" id="settingsTab"> | |
<div class="form-horizontal"> | |
<div class="form-group"> | |
<label for="TeamNameSet1" class="control-label col-md-2">Team</label> | |
<div class="col-md-3 col-sm-3"> | |
<input type="text" id="TeamNameSet1" name="TeamNameSet1" class="form-control" required="required" /> | |
</div> | |
</div> | |
<div class="form-group"> | |
<div class="col-md-3 col-xs-3 col-md-offset-2" > | |
vs | |
</div> | |
</div> | |
<div class="form-group"> | |
<label for="TeamNameSet2" class="control-label col-md-2">Team</label> | |
<div class="col-md-3 col-sm-3"> | |
<input type="text" id="TeamNameSet2" name="TeamNameSet2" class="form-control" required="required" /> | |
</div> | |
</div> | |
<div class="form-group"> | |
<div class="col-md-3 col-md-offset-2" > | |
<input type="button" class="btn btn-success" id="ConfigBoard" value="Start" /> | |
</div> | |
</div> | |
</div> | |
<hr /> | |
</div> | |
</div> | |
</div> | |
<footer> | |
<div class="container float-left"> | |
<p>© Copyright CodexSquare</p> | |
</div> | |
</footer> | |
</div> | |
<script src="Scripts/bootstrap.min.js"></script> | |
<script src="Scripts/admin.js"></script> | |
</body> | |
</html> |
There is only one client method that the server can call (but you can add more) :
scoreHub.client.getScore
and there are 2 server methods that the site.js can call:
- Connect
- GameConfigure
- UpdateScore
- SendScore
eg: scoreHub.server.connect();
site.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function () { | |
"use strict"; | |
var scoreHub; | |
var $alertMsg; | |
var alertHtmlClose = '<a href="#" data-dismiss="alert" class="close">×</a>'; | |
var alertHtml; | |
$(function () { | |
$.ajaxSetup({ | |
cache: false | |
}); | |
scoreHub = $.connection.scoreHub; | |
configListeners(); | |
// Start Hub | |
$.connection.hub.start({ transport: ['webSockets', 'serverSentEvents', 'longPolling'] }) | |
.done(function () { | |
scoreHub.server.connect(); | |
}); | |
}); | |
function configListeners() { | |
scoreHub.client.getScore = function (liveScore) { | |
$alertMsg.hide(); | |
if (liveScore.TeamName1 == null) { | |
if (!$("#Team1").length) { | |
return false; | |
} | |
$("#objectToAnimate").hide(); | |
$alertMsg.show(); | |
return false; | |
} | |
$("#Team1").html(liveScore.TeamName1); | |
$("#Team2").html(liveScore.TeamName2); | |
$("#Score1").html(liveScore.Team1Score); | |
$("#Score2").html(liveScore.Team2Score); | |
$("#objectToAnimate").fadeOut(500); | |
$("#objectToAnimate").fadeIn(500); | |
}; | |
$alertMsg = $("#alertMsg"); | |
$alertMsg.hide(); | |
$alertMsg.on("close.bs.alert", function () { | |
$alertMsg.hide(); | |
return false; | |
}); | |
} | |
})(); | |
The admin.js
The admin use to configure game and send scores to viewers. There are 4 server methods that the admin.js can call:
- Connect
- GameConfigure
- UpdateScore
- SendScore
admin.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function () { | |
"use strict"; | |
var scoreHub; | |
var liveScore = {"TeamName1": "", "Team1Score": 0, "TeamName2": "", "Team2Score": 0}; | |
var TeamNameSet1; | |
var TeamNameSet2; | |
var $alertMsg; | |
var alertHtmlClose = '<a href="#" data-dismiss="alert" class="close">×</a>'; | |
var alertHtml; | |
var $Team1Name = $("#TeamNameSet1"); | |
var $Team2Name = $("#TeamNameSet2"); | |
//For Admin | |
var $Team1NameScoreBoard = $("#Team1NameScoreBoard"); | |
var $Team2NameScoreBoard = $("#Team2NameScoreBoard"); | |
var $Team1ScoreBoardScore = $("#Team1ScoreBoardScore"); | |
var $Team2ScoreBoardScore = $("#Team2ScoreBoardScore"); | |
$(function () { | |
$.ajaxSetup({ | |
cache: false | |
}); | |
scoreHub = $.connection.scoreHub; | |
configListeners(); | |
// Start Hub | |
$.connection.hub.start({ transport: ['webSockets', 'serverSentEvents', 'longPolling'] }) | |
.done(function () { | |
scoreHub.server.connect(); | |
}); | |
}); | |
function configListeners() { | |
scoreHub.client.getScore = function (_liveScore) { | |
$alertMsg.hide(); | |
//Avoid empty data when switching pages | |
if (_liveScore.TeamName1 != null) { | |
//For the config | |
$Team1Name.val(_liveScore.TeamName1); | |
$Team2Name.val(_liveScore.TeamName2); | |
//For the Scoreboard | |
$Team1NameScoreBoard.html(_liveScore.TeamName1); | |
$Team2NameScoreBoard.html(_liveScore.TeamName2); | |
$Team1ScoreBoardScore.val(_liveScore.Team1Score); | |
$Team2ScoreBoardScore.val(_liveScore.Team2Score); | |
liveScore = _liveScore; | |
} | |
}; | |
$("#SendScore").click(function () { | |
sendScore(); | |
}); | |
$("#ConfigBoard").click(function () { | |
conFigBoard(); | |
}); | |
$alertMsg = $("#alertMsg"); | |
$alertMsg.hide(); | |
$alertMsg.on("close.bs.alert", function () { | |
$alertMsg.hide(); | |
return false; | |
}); | |
} | |
function conFigBoard() { | |
TeamNameSet1 = $Team1Name.val(); | |
TeamNameSet2 = $Team2Name.val(); | |
if ((TeamNameSet1 == "") || (TeamNameSet2 == "")) { | |
alertHtml = alertHtmlClose; | |
alertHtml = alertHtml.concat('Team Names are empty. Please supply.'); | |
$alertMsg.show(); | |
$alertMsg.html(alertHtml); | |
return false; | |
} | |
$alertMsg.hide(); | |
$Team1NameScoreBoard.html(TeamNameSet1); | |
$Team2NameScoreBoard.html(TeamNameSet2); | |
liveScore.TeamName1 = TeamNameSet1; | |
liveScore.Team1Score = 0; | |
liveScore.TeamName2 = TeamNameSet2; | |
liveScore.Team2Score = 0; | |
scoreHub.server.gameConfigure(liveScore); | |
$('#LiveTabs a[href="#scoreBoardTab"]').tab('show'); | |
} | |
function sendScore() { | |
var isDefinedTeam1 = $Team2NameScoreBoard.html().toLowerCase().indexOf("not set"); | |
var isDefinedTeam2 = $Team2NameScoreBoard.html().toLowerCase().indexOf("not set"); | |
if ((isDefinedTeam1 >= 0) || (isDefinedTeam2 >= 0)) { | |
alertHtml = alertHtmlClose; | |
alertHtml = alertHtml.concat('Cannot send score. No teams has been defined.'); | |
$alertMsg.show(); | |
$alertMsg.html(alertHtml); | |
return false; | |
} | |
$alertMsg.hide(); | |
var Team1Score = $Team1ScoreBoardScore.val(); | |
var Team2Score = $Team2ScoreBoardScore.val(); | |
liveScore.Team1Score = Team1Score; | |
liveScore.Team2Score = Team2Score; | |
scoreHub.server.updateScore(liveScore); | |
} | |
})(); |
Thank you! Hope this will help you make your web application "real time". Share it with friends...
3 comments
Great Explanation.
Replyhtml5 training in chennai |
html5 training institute in chennai | Online AngularJS Training
Hi! How i can add more games?
ReplyThank For Sharing Your Information The Information Shared Is Very Valuable Please Keep Updating Us Time Went On Just Reading The Article Python Online Course
Reply