El pasado viernes 14 de marzo estuvimos hablando, vía hangout, Juan Quijano y un servidor sobre SignalR y Web API. A nosotros se unieron también Jorge Serrano, Gorka Madariaga, Luis Fraile y David Salgado entre otros, y otros tantos que nos observaron a través de Youtube.
Comenzamos con una breve introducción, una pequeña comparación con socket.io, una tecnología similar que funciona sobre node.js, y que pude emplear para otro proyecto anteriormente.
A continuación vimos cómo gestionar errores en signalR, ya que, por seguridad, todos los detalles de un error se ocultan, y debemos usar las siguientes líneas:
var hubConfiguration = new HubConfiguration(); hubConfiguration.EnableDetailedErrors = true; app.MapSignalR(hubConfiguration); ... $.connection.hub.logging = true; $.connection.hub.start(); ... var connection = $.hubConnection(); connection.error(function (error) { console.log('SignalR error: ' + error); });
Vista la gestión de errores, el siguiente paso estaba relacionado con inyección de dependencias mediante el uso de Ninject. Asumiendo que lo hemos instalado vía Nuget y lo hemos agregado a nuestro proyecto, en primer paso es agregar la dependencia al constructor:
public class Poll : Hub { IQuestionRepository _repository; public Poll(IQuestionRepository repository) { _repository = repository; } }
Si intentamos ejecutar el proyecto en este estado, tendremos un error, ya que no detecta un constructor vacío (Inténtalo!).
El segundo paso es definir nuestro Dependency Resolver que usará SignalR para detectar dependencias:
public class NinjectSignalRDependencyResolver : DefaultDependencyResolver { private readonly IResolutionRoot _resolutionRoot; public NinjectSignalRDependencyResolver(IResolutionRoot kernel) { _resolutionRoot = kernel; } public override object GetService(Type serviceType) { return _resolutionRoot.TryGet(serviceType) ?? base.GetService(serviceType); } public override IEnumerable<object> GetServices(Type serviceType) { return _resolutionRoot.GetAll(serviceType).Concat(base.GetServices(serviceType)); } }
El tercer paso, es construir nuestro kernel, que será el encargado de hacer los mappings entre interfaz y clase.
public class CurrentKernel { public static IKernel Init() { IKernel current = new StandardKernel(); current.Bind<IQuestionRepository>().To<DBQuestionRepository>(); return current; } }
En mi caso, el kernel estaba fuera del dependency resolver, ya que, como comenté en un artículo anterior, signalR y ASP.net MVC usan diferentes Dependency Resolvers, con lo cual tenía que hacer dos clases diferentes, pero que podían compartir kernel.
Finalmente vimos cómo combinarlo todo en la configuración:
var dependencyResolver = new NinjectSignalRDependencyResolver(CurrentKernel.Init()); app.MapSignalR(new HubConfiguration() { Resolver = dependencyResolver });
Como último detalle, estuvimos viendo cómo cargar ensamblados externos, ya que SignalR descubre los hubs en tiempo de ejecución, y si están en un ensamblado externo, no se ven. La solución es cargar el ensamblado justo antes de inicializar signalR, como se ve a continuación:
public class ChatHub : Hub { public void Send(string name, string message) { // Call the broadcastMessage method to update clients. Clients.All.broadcastMessage(name, message); } } AppDomain.CurrentDomain.Load(typeof(Namespace.ChatHub).Assembly.FullName); ... //Inicializamos signalR
Como invitado especial (y caso de uso real) estuvo el Web Workspace, un proyecto de VS Anywhere que lleva unos meses usando signalR para colaboración en tiempo real usando el navegador.
Después de la parte de SignalR, ya el el apartado relacionado con Web API, estuvimos comentando los diferentes tipos de APIs REST, la necesidad de un estándar, así como los problemas a los que nos podíamos enfrentar al diseñarlas, o al consumirlas.
Un ejemplo muy interesante estuvo relacionado con la gestión de los errores, ya que si el código HTTP corresponde con el, tipo de error, bibliotecas como jQuery o el propio WebClient de .NET son capaces de gestionarlo, y, de otra manera, hemos de ser nosotros quienes analicen la respuesta en busca del código de error.
Para concluir, estuvimos echando un vistazo a mi pequeño proyecto, RealPoll y repasando sus peculiaridades, como la inyección de dependencias y/o el uso de la biblioteca Razor para generar e-mails.
Finalmente, dejamos una biografía recomendada:
- Para Web API: Apigee – Web API design
- Para SignalR Signalr Programming in ASP.net
El resultado, en vídeo:
Información adicional
- Portal ASP.net How to handle errors in signalR
- Ninject