Stream Web API Transactions Using SignalR

In the new world of APIs and microservices, it is absolutely correct to say that things have started moving really quickly; .i.e., transforming an idea into a product. But with all this agility comes a lot of moving parts, which sometimes results in serious overhead and in some cases failure of the sole product.

SignalR

In the new world of APIs and microservices, it is absolutely correct to say that things have started moving really quickly;  .i.e., the process of transforming an idea into a product. But with all this agility comes a lot of moving parts, which sometimes results in serious overhead and in some cases failure of the sole product.

In order to execute an API/microservice oriented design we need to be vigilant about the performance; i.e., request/response transaction time and logs produced by these components. As for any API if the transaction time grows, the life expectancy for the API dramatically falls. If we take on an API build under any technology it's like a black box engine room -- the highest level of details about what is happening inside can only be retrieved from the log files. There are ways these log files can be machine read, such as Slack and other tools. But in most cases they are expensive if they are easy to use or too complicated to configure as with most of the open source tools.

With all the above problem statements, I started thinking of how  we can visualize/extract what is happening inside the engine room in real-time and with the least possible effort. This led to a thought about SignalR integration with Web API. I am using ASP.NET Web API for blog purposes but you can use the same technique for any  technology.

In the video below I am capturing an API request and publishing it to SignalR for display purposes.


Now if you are excited, let's do it :)

  1. Create a new project in Visual Studio

    SignalR

  2. Select Web API project

    SignalR

  3. Add SignalR Nuget Packages

    SignalR
    1. package id="Microsoft.AspNet.SignalR" version="2.2.0" targetFramework="net45"  
    2. package id="Microsoft.AspNet.SignalR.Core" version="2.2.0" targetFramework="net45"  
    3. package id="Microsoft.AspNet.SignalR.JS" version="2.2.0" targetFramework="net45"  
    4. package id="Microsoft.AspNet.SignalR.SystemWeb" version="2.2.0" targetFramework="net45"  
  4. Enable SignalR by adding to AppBuilder in Startup class
    1. public class Startup  
    2.  {  
    3.  public void Configuration(IAppBuilder app)  
    4.  {  
    5.     app.MapSignalR();  
    6.   }  
    7.  }  
    8. }  
  5. Create a Hub class. Hub class is the bridge between client side script such as Jquery and server side C# code. Hub class looks for best the possible connection mechanism to make an RPC call from server to connected clients.
    1. using Microsoft.AspNet.SignalR;  
    2. namespace SignalRLogging  
    3. {  
    4.  public class Requestlog:Hub  
    5.  {  
    6.   public static void PostToClient(string data)  
    7.    {  
    8.     try  
    9.      {  
    10.        var chat = GlobalHost.ConnectionManager.GetHubContext("Requestlog");  
    11.         if (chat != null)  
    12.         chat.Clients.All.postToClient(data);  
    13.       }  
    14.       catch  
    15.        {  
    16.        }  
    17.      }  
    18.   }  
    19.  }  
  6. Now we need to create a listener which will be available to all the API controllers. The controllers can publish the message using this listener for the hub, which then publishes the message to all the connected clients. In order to implement this we will add delegate DelLogMessage to WebApiConfig. Also bind the delegate to PostToClient method of Hub Class, so that when the listener receives a message it is automatically published to Hub PostToClient method.
    1. namespace SignalRLogging  
    2. {  
    3.  public static class WebApiConfig  
    4.  {  
    5.  public static void Register(HttpConfiguration config)  
    6.  {  
    7.  // Web API configuration and services  
    8.  // Web API routes  
    9.  config.MapHttpAttributeRoutes();  
    10. config.Routes.MapHttpRoute(  
    11.  name: "DefaultApi",  
    12.  routeTemplate: "api/{controller}/{id}",  
    13.  defaults: new { id = RouteParameter.Optional }  
    14.  );  
    15.  Global.LogMessage = Requestlog.PostToClient;  
    16.  config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));  
    17.  }  
    18.  }  
    19.  public class Global  
    20.  {  
    21.  public delegate void DelLogMessage(string data);  
    22.  public static DelLogMessage LogMessage;  
    23.  }  
    24. }  
  7. Let's publish a message to the listener from API Controller. What I am trying to portray here is how your message gets broadcast and published to all clients. This is not the ideal way to go, so a few options how it should be done in production project are:

    Created an extended DelegatingHandler, which is used to capture all incoming requests to the hosted API u
    sing OWIN where you can tap in the request pipeline, filter the required message body and publish to Hub.
    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.Linq;  
    4. using System.Net;  
    5. using System.Net.Http;  
    6. using System.Web.Http;</pre>  
    7. namespace SignalRLogging.Controllers  
    8. {  
    9.  public class ValuesController : ApiController  
    10.  {  
    11.  // GET api/values  
    12.  public IEnumerable  Get()  
    13.  {  
    14.  Global.LogMessage("Data from Controller");  
    15.  return new string[] { "value1""value2" };  
    16.  }  
    17.   
    18. // GET api/values/5  
    19.  public string Get(string id)  
    20.  {  
    21.  Global.LogMessage("Request param : " + id);  
    22.  return "value";  
    23.  }  
    24.  }  
    25. }  
  8. Lastly, let's create the client which will present Hub Messages. Add an html file to your project. In the code below we have referred SignalR.js, compatible jquery and /signalr/hubs. If you will look in the folders you will not find the hub file anywhere. Hub file is a proxy which is generated dynamically by the server once the browser request first reaches the server.
    1. <!DOCTYPE html>  
    2. <html xmlns="http://www.w3.org/1999/xhtml">  
    3. <head>  
    4.     <title>SignalR Message</title>  
    5. </head>  
    6. <body>  
    7.     <div>  
    8.         <ul id="discussion"></ul>  
    9.     </div>  
    10.     <script src="Scripts/jquery-1.6.4.min.js"></script>  
    11.     <script src="Scripts/jquery.signalR-2.0.0.js"></script>  
    12.     <script src="/signalr/hubs"></script>  
    13.     <script type="text/javascript">  
    14.         $(function () {  
    15.   
    16.             var chat = $.connection.requestlog;  
    17.             $.connection.hub.start().done(function () {  
    18.   
    19.             });  
    20.             chat.client.postToClient = function (data) {  
    21.                 $('#discussion').append('Message' + data + '<br />');  
    22.             };  
    23.         });  
    24.     </script>  
    25. </body>  
    26. </html>  
Source Code is available @Github.

Summary

This article just covers the tip of iceberg. There is wide range of avenues where SignalR can be of great help. In one of the projects I have used SignalR for notifying Window agents about the availability of new patch when user used to create a new entry for patch on portal. SignalR is great tool is used wisely and in appropriate usecase.