Hopefully, you've followed the steps in Part 1 and Part 2 to create a project, get the necessary NuGet packages installed and generate the Startup.cs and SignalRHub.cs class files. If so, we're ready to create a web page that connects to the Hub.
Default.html
Let's create a web page! Right click the Project in the Solution Explorer and select Add > HTML Page. Enter the name default.html and click OK. This will add the file to the Solution Explorer and open the file in the VS Editor. Visual Studio will have added some basic structural code for you.
The Whole Nine Yards
Rather than try to step through snippets of the default.html page, the entire content is shown below.... under that will be an explanation of each piece.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<link href="Content/bootstrap.min.css" rel="stylesheet" />
<script src="Scripts/bootstrap.bundle.min.js"></script>
<script src="Scripts/jquery-1.6.4.min.js"></script>
<script src="Scripts/jquery.signalR-2.4.3.min.js"></script>
<script src="signalr/hubs"></script>
<script>
var hubConnection;
//wait until the page is fully loaded
document.addEventListener("DOMContentLoaded", function () {
initPage();
});
//listen for the page unloading
window.addEventListener("beforeunload", function (e) {
hubLeaveGroup();
});
//init the page/hub connection
function initPage() {
hubConnection = $.connection.SignalRHub;
hubConnection.client.processChatMessage = function (message) { hubProcessMessage(message) };
hubConnection.client.updateAttendance = function (userList) { hubUpdateAttendance(userList) };
//start a hub session
$.connection.hub.start()
.done(function () {
//execute the local function to join the All group
hubJoinGroup();
})
.fail(function () {
alert("hub failed to start!");
});
}
//resolved hub visible function - see above
function hubProcessMessage(message) {
//example of the hub sending an object directly... no JSON.parse required
document.getElementById("messagesFromHub").innerHTML += message.userName + " says <br/>" + message.message + "<br/><br/>";
}
//resolved hub visible function - see above
function hubUpdateAttendance(data) {
//example of the hub sending the array of objects as a serialized JSON string
//parse it first, then process it
var userList = JSON.parse(data);
document.getElementById("hubAttendance").innerHTML = "";
//roll through the list and output the logged in users
userList.forEach(user => {
var userLine = `${user.UserName}: [${user.userConnectionId}]<br/>`;
document.getElementById("hubAttendance").innerHTML += userLine;
});
}
//local function
function hubJoinGroup() {
hubConnection.server.JoinGroup("All", "Robert Crossings")
.done(function () { })
.fail(function () { });
}
//local function
function hubLeaveGroup() {
//note the event listener above... this is executed when the user navigates away from the page
//this will remove the current user from the All group
//and execute the client visible hubUpdateAttendance function above
hubConnection.server.LeaveGroup("All")
.done(function () { })
.fail(function () { });
}
//local function
function hubSendMessage() {
var msg = document.getElementById("hubMsg").value;
//this sends the message data to the hub... the hub will turn around
//and execute the client visible hubProcessMessage function above
hubConnection.server.SendMessage("All", msg, "Robert Crossings")
.done(function () { })
.fail(function () { });
}
</script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col">
<h1>My SignalR Web Site</h1>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="container-fluid">
<div class="row" style="margin-bottom:10px">
<div class="col-3">
Enter Message
</div>
<div class="col-9">
<input type="text" id="hubMsg" onchange="javascript:hubSendMessage()" style="width:100%" />
</div>
</div>
<div class="row">
<div class="col" id="messagesFromHub" style="border:1px solid darkgrey;min-height:300px"></div>
</div>
</div>
</div>
<div class="col-6">
<div class="container-fluid">
<div class="row" style="margin-bottom:10px">
<div class="col">Attendance</div>
</div>
<div class="row">
<div class="col" id="hubAttendance" style="border:1px solid darkgrey;min-height:300px"></div>
</div>
</div>
</div>
</div>
</body>
</html>
Bootstrap
I've gotten used to the simplicity of Bootstrap.... notice the references in the <head> section: 1 for the CSS and 1 for a supporting JS file (the JS file wasn't really needed for this page - creature of habit). If you want to reproduce this page, simply open the NuGet Package Manager and search for Bootstrap.
jQuery
Also in the <head> section are the 3 SignalR JS script references. Notice that for this blog, I did not update the jQuery version from 1.6.4. Normally, I do update that and change the script reference to align with the version I'm using.
signalr/hubs
There's also an odd reference to signalr/hubs. This is a reference to a virtual file that gets created on the fly by the SignalR system because of what we did in the startup.cs file.
The Script Block
I've commented this as clearly as I can. There are some ideas to note:
In the initPage function, the first thing we do is initialize the SignalRHub. The local reference to the hub is always $.connection.
Next, we declare 2 functions that are visible to the Hub. As shown, these proxy functions in turn call a local function. The Hub can only call client functions declared like this. For the purposes of this blog, we only needed 2 functions, but you can have as many as you need to provide the functionality desired.
After declaring the proxy functions, we then start the hub with $.connection.hub.start(). This is the command that gives the current user their unique Connection Context ID. Every subsequent call to the server automatically has that unique value.
Five Local Functions
hubProcessMessage: Called by the client proxy function processChatMessage. In this case, the Hub sends an object that contains userName, message and groupName. Because the Hub is sending the object directly (rather than serialized), we can process it directly - no JSON.parse required.
hubUpdateAttendance: Called by the client proxy function updateAttendance. The Hub sends an array of objects as a string - so have to JSON.parse it prior to processing.
hubJoinGroup: Called immediately after we start() the Hub in order to assure that the current user joins at least one group (in this case, the All group). On the Hub side, the user is joined to the group and added to a list of logged in users. That list is then sent back to clients joined to the All group by way of the updateAttendance client proxy function.
hubLeaveGroup: Called when the beforeunload window event is fired (when the user navigates away from the page or closes the browser). This executes the Hub's LeaveGroup method which removes the user from the All group and the userList list. The Hub then calls the updateAttendance client proxy function for any users still logged in.
hubSendMessage: Called when the user enters a message in the textbox and presses the enter key (for simplicity). This function calls the Hub's SendMessage method. SendMessage turns around and calls the client's processChatMessage proxy function which displays the message on the screen for any users joined to the All group on the Hub.
The HTML Block
Other than the implementation of Bootstrap, the HTML for this example is quite simple.
- A textbox to enter/send messages
- A div to display messages
- A div to display attendance
No comments:
Post a Comment