- •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
instance could even be active throughout the whole time the user is connected), and if we create dependencies that use valuable resources, these might be unavailable for other uses. In these cases, it is better to opt for a close control of the lifetime of such dependencies—for example, by obtaining them through the Service Locator and delimiting their use with a using block to ensure their release when they are no longer needed.
Releasing dependencies
Sometimes dependencies use external resources that have to be released. For example, a hub could use an Entity Framework data context to persist information in the database, and we should always ensure that both it and (hence) the underlying connection it uses have been closed and released.
Currently, SignalR provides no mechanism to automatically release dependencies (or, for example, those that implement IDisposable), so developers are responsible for ensuring that this happens. Generally, a good place to do this is in the implementation of the Dispose() method of hubs:
public class CustomerHub : Hub
{
...
protected override void Dispose(bool disposing)
{
if (disposing)
{
_customerRepository.Dispose(); _mailManager.Dispose();
}
}
}
It would be necessary to do this at least with direct dependencies of the hub that implement IDisposable. If these depend in turn on other components, the latter could be released here or from their respective Dispose() methods. In any case, it is also a task that must be performed with extreme caution, because there might be components shared between instances whose early release could cause problems.
Inversion of Control containers
With the techniques seen before, we now know how to inject dependencies in hubs by simply changing the content of the Dependency Resolver register, although this task can be really laborious if we have complex dependency graphs. For example, if our hub depends on an instance that implements the IService interface, the specific class to be used needs an instance of IRepository, and in turn this instance requires an IDataStore object. We can find ourselves with quite convoluted registers, because we have to manage these relationships ourselves:
GlobalHost.DependencyResolver.Register(
typeof (MyHub),
200 Chapter 9 Advanced topics
www.it-ebooks.info
() => new MyHub(new MyService(new MyRepository(new MyDataStore())))
);
A concept that frequently appears hand-in-hand with Dependency Injection is that of Inversion of Control containers (IoC containers). These are components specializing in managing instances, life cycles, and dependencies between objects, something like Dependency Resolvers on steroids. Not only can they act as powerful Service Locators, but they also tend to be much more flexible when registering services, specifying instantiation modes (for example, deciding which objects will be created as singletons and which will be instantiated upon request), and solving dependencies between components automatically.
Going back to our previous example, where we had a dependency graph, if we were to request an instance of MyHub from the IoC container, the latter would be able to analyze its constructor and
determine that it needs an instance of IService. Thanks to its register, it would know that IService must be resolved to the MyService class, but also that the latter, in turn, requires an IRepository object in its constructor, so it would check its register again to see what class would satisfy the dependency, and so on until completing the dependency graph.
Obviously, this way of managing dependencies is much more convenient and productive than doing it manually.
There are many IoC containers on the market, although we could point out Unity, Ninject, Autofac, StructureMap, or Windsor Castle, and others, for their great popularity. Virtually all are open source products, basically very similar in concept and operation, and even quite similar to the operation of the Dependency Resolver that we have previously seen:
■■Application startup is used to register in the container associations between requested types and returned types, the way they are obtained, and other aspects.
■■At run time, when an instance of some type is needed by the application, the container is called to obtain it.
IoC containers are normally integrated with SignalR through the standard mechanism of dependency resolution, because this is the point already established for obtaining component instances. Usually, the default Dependency Resolver is replaced with a custom one, which uses an IoC container in the backstage to obtain the dependencies making use of the latter’s power.
Now we will see how to use dependency injection with two of these containers: Unity and Ninject. The dependency graph that we will use is the following:
Broadcaster <requires> IMessageFormatter
MessageFormatter <implements> IMessageFormatter <requires> IClock
The Broadcaster hub requires in its constructor an instance of IMessageFormatter, which materializes in the MessageFormatter class and whose constructor, in turn, requires an instance of
IClock. In all cases, the interfaces are a true reflection of the signature of the classes, so we will omit their code for the sake of brevity.
public class Broadcaster: Hub
{
Advanced topics Chapter 9 |
201 |
www.it-ebooks.info
private IMessageFormatter _formatter;
public Broadcaster(IMessageFormatter formatter)
{
_formatter = formatter;
}
public Task Broadcast(string message)
{
var formattedMsg = _formatter.Format(message); return Clients.All.Message(formattedMsg);
}
}
public class MessageFormatter : IMessageFormatter
{
private IClock _clock;
public MessageFormatter(IClock clock)
{
_clock = clock;
}
public string Format(string message)
{
return _clock.GetCurrentDateTime() + " > " + message;
}
}
public class Clock : IClock
{
public string GetCurrentDateTime()
{
return DateTime.Now.ToString("F");
}
}
SignalR with Unity
Unity3 is a powerful IoC container promoted by Microsoft Patterns & Practices. Like others, it can be installed very easily on our SignalR application via NuGet:
PM> Install-package Unity
Now we will create a Dependency Resolver inheriting from the class that SignalR provides: DefaultDependencyResolver. We take control in the methods used to obtain instances (GetService and GetServices), and we enter logic to search first in the IoC container and then, if appropriate, in the default register:
public class UnityDependencyResolver : DefaultDependencyResolver
{
private UnityContainer _container;
public UnityDependencyResolver(UnityContainer container)
{
3 http://unity.codeplex.com
202 Chapter 9 Advanced topics
www.it-ebooks.info
_container = container;
}
public override object GetService(Type serviceType)
{
if (_container.IsRegistered(serviceType))
{
return _container.Resolve(serviceType);
}
return base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
return _container.ResolveAll(serviceType)
.Concat(base.GetServices(serviceType));
}
}
We can now set this component as a dependency resolution mechanism for the application, sending an instance in the initial configuration object. Note that to instantiate it we need to have created a Unity container, which we will also use to register the components that the IoC container will be in charge of creating:
public void Configuration(IAppBuilder app)
{
var container = new UnityContainer(); container.RegisterType<IClock, Clock>(); container.RegisterType<IMessageFormatter, MessageFormatter>(); container.RegisterType<Broadcaster>();
app.MapSignalR(new HubConfiguration()
{
Resolver = new UnityDependencyResolver(container)
});
}
Note Although in this example we are including the container configuration code directly on the Configuration() method, it would be much more appropriate to move all operations relating to the IoC to an independent class and, for example, enter them into an IocConfig.Setup() method, which would be invoked from this point.
In this case, the instances that will be created for all components through Unity will be single-use. Whenever a component is requested, a new instance of it will be created. If for any reason, such as performance, we want a specific component to be managed in singleton mode, we can specify this at the moment of registration. For example, the instances of IClock in our previous example could be the same for the entire application, so the register could be as follows:
container.RegisterType<IClock, Clock>(
new ContainerControlledLifetimeManager()
);
Advanced topics Chapter 9 |
203 |
www.it-ebooks.info
Thus, all calls made to the container requesting IClock type components will be answered with the same instance of Clock.
For more information about using Unity, you can review the official product documentation available at http://msdn.microsoft.com/en-us/library/dn170416.aspx.
SignalR with Ninject
Besides having a great name, Ninject is a powerful open source IoC container, created with simplicity and ease of use in mind from the beginning. Installation on a project, as usual, can be performed through NuGet:
PM> Install-package Ninject
As we did before with Unity, the next step is to create our Dependency Resolver to replace the one provided by SignalR by default:
public class NinjectDependencyResolver : DefaultDependencyResolver
{
private IKernel _kernel;
public NinjectDependencyResolver(IKernel kernel)
{
_kernel = kernel;
}
public override object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType)
?? base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
return _kernel.GetAll(serviceType)
.Concat(base.GetServices(serviceType));
}
}
As you can see, it is almost identical to the one we had with Unity, the main difference perhaps being that in Ninject dialect the container is called a “kernel.” The creation and initialization of the kernel is also done during application startup:
public void Configuration(IAppBuilder app)
{
var kernel = new StandardKernel();
kernel.Bind<IClock>().To<Clock>().InSingletonScope(); kernel.Bind<IMessageFormatter>().To<MessageFormatter>();
app.MapSignalR(new HubConfiguration()
{
Resolver = new NinjectDependencyResolver(kernel)
});
}
204 Chapter 9 Advanced topics
www.it-ebooks.info