- •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
It would also be unfeasible to use backplanes in systems where it is essential to have real-time communications with a fixed frequency of updates per second, such as in a multiplayer shooter. This scenario, probably the most extreme one that we might face when developing a real-time application, can be approached in the same way: making all users involved in the action or game connect to the same server to be able to send their messages directly and without any middlemen.
Another possibility we might consider when using backplanes is trying to optimize the traffic generated in the messaging bus based on the needs of our application. For example, it would be possible to create a system to keep the subscriptions users should receive updated on every node, and implement a filtering system preventing messages that a node is not going to need from reaching that node through the backplane.
Of course, we can combine several of these techniques or devise new strategies that fit the exact needs of each application, but unlike with backplanes, we will have to implement our own solution.
Scaling on backplanes
The SignalR team has managed to make the activation of a backplane completely trivial. All that we have to do is install the specific package of the backplane using NuGet and insert a line of code to provide the basic configuration information that it needs. Now we will see how to configure and start the official backplanes available today: Windows Azure Service Bus, SQL Server, and Redis.
Windows Azure Service Bus
The Windows Azure bus is a scalable infrastructure for cloud messaging that offers various features for efficient communication of applications such as queues, topics (for publish/subscribe—pub/sub— schemes), relay, or push notifications, among other things. The backplane for SignalR uses topics to convey messages to the nodes connected to it.
This is a paid service, charged by the number of messages sent. Each call to a method of the hub enters a message into the bus, as do internal notifications of user connections or disconnections.
However, the cost is not unreasonable. At the time of writing, you can send a million messages, or even more if you opt for an annual subscription, for one dollar.
Configuring the service
The bus service is created and configured through the Windows Azure management portal by accessing Service Bus in the main menu; see Figure 8-7.
Deploying and scaling SignalR Chapter 8 |
159 |
www.it-ebooks.info
FIGURE 8-7 Accessing the Service Bus from the Azure management console.
If we have not used this feature before, a screen will appear, as shown in Figure 8-8, telling us that no namespace has been created and inviting us to create one. A namespace is a name used to identify the Service Bus when we reference it—for example, to connect from client applications.
160 Chapter 8 Deploying and scaling SignalR
www.it-ebooks.info
FIGURE 8-8 No namespaces defined.
After clicking any of the various links available to create the namespace, we will just have to fill out a short form—see Figure 8-9—and it will be ready. We need to provide the following data:
■■The name of the bus that we are creating, which will serve to compose the URL to access it. The suffix .servicebus.windows.net will be automatically added to it, and it must be unique.
■■The region where the servers that will use the bus are located. The closer they are geographically, the more efficient the communication between them will be.
After the form is completed, the system will inform us that the namespace has been created correctly, and we will be able to use it from our application. See Figure 8-10.
Deploying and scaling SignalR Chapter 8 |
161 |
www.it-ebooks.info
FIGURE 8-9 Adding a new service bus namespace.
FIGURE 8-10 Namespace successfully created.
162 Chapter 8 Deploying and scaling SignalR
www.it-ebooks.info
Notice the Connection Information link at the bottom of the figure. We can use this link to get the connection string, which we will use later on when configuring the backplane in the SignalR application.
Activating the backplane
Thanks to the pluggable architecture with which SignalR has been designed, activation of the backplane is insultingly simple, as we will see now. For any SignalR application to use Service Bus as a backplane, first we have to install the following NuGet package:
PM> Install-Package microsoft.aspnet.signalr.ServiceBus
Next we have to tell SignalR that it must use said backplane, supplying it certain configuration parameters. This code must be found at a point that is executed during application startup, such as the Startup class:
public class Startup
{
public void Configuration(IAppBuilder app)
{
var connectionString = "Endpoint=sb://jmaguilartest.servicebus.windows.net/;"
+"SharedSecretIssuer=owner;"
+"SharedSecretValue=YOURSECRETVALUEHERE>";
GlobalHost.DependencyResolver.UseServiceBus( connectionString: connectionString, topicPrefix: "Broadcaster"
);
//...
app.MapSignalR();
}
}
The first parameter of UseServiceBus() is the connection string to the server that we previously obtained from the Azure Management Tool. The second one is usually the name of the application, and it is used only to discriminate and group messages inside the bus. All SignalR nodes must use the same name so that they can share information, and it must be different than the name used by other applications that share the bus service.
This is all that we need to provide horizontal scalability to our SignalR application. From this moment on, we can run two instances of the same site on different servers and both will be communicated in a transparent way; see Figure 8-11.
Deploying and scaling SignalR Chapter 8 |
163 |
www.it-ebooks.info
FIGURE 8-11 Application running on two different nodes.
We can provide additional configuration information to the backplane through a
ServiceBusScaleoutConfiguration type object. For example, in the following code, in addition to the connection string and topic prefix, we are setting the message life span to five seconds:
var config = new ServiceBusScaleoutConfiguration( connectionString, "Broadcaster")
{
TimeToLive = TimeSpan.FromSeconds(5)
};
GlobalHost.DependencyResolver.UseServiceBus(config);
Additionally, it is worth noting that for the purpose of functional testing of web applications distributed across multiple nodes, a good way to do it is to launch additional IIS Express instances from the command line, as shown in the following example:
"c:\Program Files (x86)\IIS Express\iisexpress.exe" /port:5456 /path:d:\signalrdemos\servicebusdemo
Obviously, both the port chosen and the path to the application must be adapted to the needs in each case. This way, we can have multiple instances of the server application on the local computer, each one running on a different port.
164 Chapter 8 Deploying and scaling SignalR
www.it-ebooks.info
