- •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
C H A P T E R 6
Persistent connections and hubs from other threads
All server implementations seen up to this point in the book have had something in common: they have always been responding to direct messages from a client. Even though they are push
systems, a client has always been initiating the procedure:
■■In a chat, when a user sends a message to the server, this message is sent to the rest of the connected users.
■■In the tracking system that we showed in Chapter 4, “Persistent connections,” a user’s mouse movement was the action that originated the notification to the other users.
■■In the shared drawing board example in Chapter 5, “Hubs,” when a user drew a point or pressed the button to erase the canvas, the action was sent to the others so that they could update their whiteboards.
Although this is what we will need in most cases, SignalR takes a step further and allows us to send messages to clients connected to a hub or a persistent connection from another thread of the same application—that is, outside the hub and without the need for a SignalR client to initiate the sequence explicitly.
Access from other threads
This approach can be very interesting in scenarios where there are unattended or automatically executed processes in the same application where SignalR services are found, and where these processes need to send information to clients who need to receive it in real time.
For example, there might be a background thread obtaining information from a data source (such as stock quotes, meter readings, and so on) and sending it to clients connected to a hub or a persistent connection. It would also be quite easy to create a system that registered the exceptions thrown in an ASP.NET application and sent an alert at exactly that point to a set of users previously connected to a service in real time. Or we could enter logic in the method treating a Web Forms event or an ASP .NET MVC action to notify clients connected to a hub or persistent connection that something important for them has occurred. Any of these cases would consist in accessing hubs or persistent connections from different threads to those where the hubs or persistent connections are running,
103
www.it-ebooks.info
but always within the same process or app domain. Certainly, the range of possibilities that unfolds thanks to this capability of SignalR is immense.
Although it is probably unnecessary to remark on this, it would also be possible to access real-time services offered by SignalR from other physically separated systems, but such a scenario would be very different: the external system could simply be another client of the services, and to access them, it would have to use client libraries provided by the framework. An example of an external system could be something as simple as a mobile application or as complex as an ERP system, which would need to exchange information with a SignalR server in real time. The structure would be the one displayed in Figure 6-1.
FIGURE 6-1 Accessing SignalR services from physically separate systems.
If we just need the external system to inform the users connected to the services about an event, we could also use more disconnected architectures and create a façade of web services in the application where SignalR resides (using Web API, MVC, WCF, and so on), as shown in Figure 6-2. The external system would notify this façade, and it would transfer the notification to the users, using the techniques that we will look at in this chapter.
Having said this, we are now going to explain how to access SignalR services from other threads of the same application. We will review the other scenarios—connection from external systems both directly and through a façade of services—in Chapter 7, “Real-time multiplatform applications,” and Chapter 9, “Advanced topics.”
104 Chapter 6 Persistent connections and hubs from other threads
www.it-ebooks.info
FIGURE 6-2 Accessing SignalR services from external systems via web services.
External access using persistent connections
To submit information to the clients connected to a persistent connection, we simply have to obtain a reference to said connection and use the methods that we normally use inside the
PersistentConnection classes.
In the following example, we see how, from a Web Forms application, we could notify connected clients that an event of interest to them has taken place:
protected void btnDeleteInvoice_Click(object sender, EventArgs e)
{
var id = invoiceId.Text; _invoiceServices.DeleteInvoice(id);
var context = GlobalHost.ConnectionManager
.GetConnectionContext<ErpNotifications>();
context.Connection.Broadcast(
"Invoice #" + id + " deleted by " + User.Identity.Name);
}
The GetConnectionContext<T>() method used in the preceding example returns a type T reference to the context of the persistent connection. The call returns an object of the IPersistentConnectionContext type, which gives access to all the functionalities normally
Persistent connections and hubs from other threads Chapter 6 |
105 |
www.it-ebooks.info
available from inside PersistentConnection: sending broadcasts directly, sending data to groups, or even actual management of groups of clients. The members available through this interface are the following:
■■Connection, which provides access to the IConnection type object (the same one that we found in the PersistentConnection base class) and, at the same time, allows using the following methods:
•Send(), to send messages to specific clients whose connectionId is known.
•Broadcast(), to send them to all the clients connected to the persistent connection.
■■Groups, of the IConnectionGroupManager type. Just like the PersistentConnection class, it offers services for managing groups and sending messages to them using the following methods:
•Add(), which we can use to add a client, identified by its clientId, to a group.
•Remove(), to withdraw a specific client from a group.
•Send(), which allows sending messages to clients that are members of specific groups.
Complete example: Monitoring connections at the server
To illustrate how to implement persistent connections from processes that are external to them, we will now give a complete example consisting of a system with which the server side “spies” the requests made to the website where this component has been installed.
The project consists of a website, implemented in just one page called default.aspx, which will change its content based on a parameter. Free browsing will be allowed, while the requests made by clients of the website will be able to be queried in real time by accessing a monitoring page called “spy.html”. We will achieve this by capturing the requests in the Application_BeginRequest event of the application global class (Global.asax) and sending a message from here to the clients connected to a persistent connection so that they can display the information. See Figure 6-3.
Note The purpose of this example is simply to show an implementation of persistent connections used from external processes. Using this system can seriously penalize performance at the server, so it is not recommended at all to use it in production.
106 Chapter 6 Persistent connections and hubs from other threads
www.it-ebooks.info