- •Contents at a Glance
- •Introduction
- •Who should read this book
- •Assumptions
- •Who should not read this book
- •Organization of this book
- •Finding your best starting point in this book
- •Conventions and features in this book
- •System requirements
- •Code samples
- •Notes on the version
- •Installing the code samples
- •Using the code samples
- •Acknowledgments
- •Errata & book support
- •We want to hear from you
- •Stay in touch
- •HTTP operations
- •Polling: The answer?
- •Push: The server takes the initiative
- •WebSockets
- •Server-Sent Events (API Event Source)
- •Push today
- •The world needs more than just push
- •What does SignalR offer?
- •Two levels of abstraction
- •Supported platforms
- •OWIN and Katana: The new kids on the block
- •Installing SignalR
- •Implementation on the server side
- •Mapping and configuring persistent connections
- •Events of a persistent connection
- •Sending messages to clients
- •Asynchronous event processing
- •Connection groups
- •The OWIN startup class
- •Implementation on the client side
- •Initiating the connection by using the JavaScript client
- •Support for older browsers
- •Support for cross-domain connections
- •Sending messages
- •Receiving messages
- •Sending additional information to the server
- •Other events available at the client
- •Transport negotiation
- •Adjusting SignalR configuration parameters
- •Complete example: Tracking visitors
- •Project creation and setup
- •Implementation on the client side
- •Implementation on the server side
- •Server implementation
- •Hub registration and configuration
- •Creating hubs
- •Receiving messages
- •Sending messages to clients
- •Sending messages to specific users
- •State maintenance
- •Accessing information about the request context
- •Notification of connections and disconnections
- •Managing groups
- •Maintaining state at the server
- •Client implementation
- •JavaScript clients
- •Generating the proxy
- •Manual generation of JavaScript proxies
- •Establishing the connection
- •Sending messages to the server
- •Sending additional information
- •Receiving messages sent from the server
- •Logging
- •State maintenance
- •Implementing the client without a proxy
- •Complete example: Shared drawing board
- •Project creation and setup
- •Implementation on the client side
- •Implementation on the server side
- •Access from other threads
- •External access using persistent connections
- •Complete example: Monitoring connections at the server
- •Project creation and setup
- •Implementing the website
- •System for tracing requests (server side)
- •System for tracing requests (client side)
- •External access using hubs
- •Complete example: Progress bar
- •Project creation and setup
- •Implementation on the client side
- •Implementation on the server side
- •Multiplatform SignalR servers
- •SignalR hosting in non-web applications
- •SignalR hosting in platforms other than Windows
- •Multiplatform SignalR clients
- •Accessing services from .NET non-web clients
- •Consumption of services from other platforms
- •Growing pains
- •Scalability in SignalR
- •Scaling on backplanes
- •Windows Azure Service Bus
- •SQL Server
- •Redis
- •Custom backplanes
- •Improving performance in SignalR services
- •Server configuration
- •Monitoring performance
- •Authorization in SignalR
- •Access control in persistent connections
- •Access control in hubs
- •Client authentication
- •An extensible framework
- •Dependency Injection
- •Manual dependency injection
- •Releasing dependencies
- •Inversion of Control containers
- •Unit testing with SignalR
- •Unit testing of hubs
- •Unit testing persistent connections
- •Intercepting messages in hubs
- •Integration with other frameworks
- •Knockout
- •AngularJS
- •Index
- •About the author
Note For these types of exceptions, the value of EnableDetailedErrors will not be taken into account. They will always be serialized and sent to the client as they are.
Sending additional information
Just as it happened in the world of persistent connections, the clients of a hub can send additional information in requests by using the mechanisms provided by web protocols. This information can be retrieved at the server with the Context property of the hub.
For example, a JavaScript client can enter information in a cookie, and its value will be available at the server side because it will travel with each request made to the server:
//Client (JavaScript) code document.cookie = "Username=phil"; $.connection.hub.start();
…
//Server code (Hub)
public Task Send(string message)
{
Cookie cookie; var username =
Context.RequestCookies.TryGetValue("Username", out cookie) ? cookie.Value
: Context.ConnectionId;
return Clients.All.Message(username + " >> " + message);
}
Another option is to enter additional values into the query string of the different requests originated at the client. For this, we can set arbitrary values in the qs (“query string”) property of the hub at the client before opening the connection, and these values will be available later at the server:
// Client code
$.connection.hub.qs = "username=phil"; // Or, alternatively:
$.connection.hub.qs = { username: "phil" };
$.connection.hub.start();
// Server code (Hub)
public Task Send(string message)
{
var username = Context.QueryString["Username"] ?? "Unknown"; return Clients.All.Message(username + " dice " + message);
}
It should be again noted that this information will travel when requests are made to the server. In a transport such as WebSockets, there will normally be only one request that will remain open, while
Hubs Chapter 5 |
89 |
www.it-ebooks.info
other transports such as long polling will open many more connections. Therefore, the value obtained at the server will be the one sent from the client at the time of the most recent request.
Receiving messages sent from the server
We have seen that when we make calls from the server to methods that exist in clients, what actually happens is that the specifications of that call are “packaged” into a data structure and sent to all its recipients using push. See Figure 5-14.
FIGURE 5-14 Calls from the server to client-side methods.
From the point of view of the client, what SignalR does is interpret the data packet received and invoke the relevant methods. That is, it processes the events received.
In the JavaScript client, methods that can be “executed” from the server must be defined in the client property of the proxy object:
var alertHub = $.connection.alertService; alertHub.client.showAlert = function (msg) {
alert(msg);
};
alertHub.client.newUser = function (userId) { alert("New user with id: " + userId);
};
It is necessary to make these specifications before the connection is opened; otherwise, they will not work. It is also important to highlight that the name of the method used at the server must match
90 Chapter 5 Hubs
www.it-ebooks.info
the name at the client exactly, except that the match is case-insensitive. The following commands at the server will execute the logic expected at the client:
public override Task OnConnected()
{
return Clients.All.NewUser(Context.ConnectionId);
}
// Is equivalent to
public override Task OnConnected()
{
return Clients.All.newuser(Context.ConnectionId);
}
However, if a nonexistent method is invoked from the server, there will be no errors on either end.
The server will send the clients the data packet with the command specification, and the clients will not execute any action upon its reception, because the name of the method received will not match any existing one.
Logging
The client component of SignalR for JavaScript allows registering a trace with the most relevant events that occur during the lifetime of the connection, which can be very helpful when debugging the applications. To activate this trace, we just have to add the following line to the initialization code:
$.connection.hub.logging = true;
From that moment on, it will be possible to query the trace in the browser’s console, as shown in Figure 5-15 and Figure 5-16. Note that, as well as the negotiation process, we can view the events thrown from the server—that is, the methods invoked on the client side.
FIGURE 5-15 Log of the JavaScript client in Google Chrome.
FIGURE 5-16 Log of the JavaScript client in Internet Explorer 11 Developer Tools.
Hubs Chapter 5 |
91 |
www.it-ebooks.info
Actually, if we need to, we can even include custom information in this log easily (see Figure 5-17):
$.connection.hub.start()
.done(function () {
$.connection.hub.log("My id: " + $.connection.hub.id);
});
FIGURE 5-17 Custom information in the SignalR trace.
Note The identifier assigned to the current client is available in the $.connection.hub.id property.
The information logged in this way will always have the prefix “SignalR:”, so it is easy to identify it in the trace.
State maintenance
We have previously seen that it is possible to define variables at the client that can be queried or modified directly from the server:
92 Chapter 5 Hubs
www.it-ebooks.info