Building Better Web Apps with Logic Apps and Signal R

In this article I would like to discuss a pattern I’ve implemented recently where we could improve the user experience in a web app through the use of Logic Apps and Signal-R. Lets imagine we have a scenario at Acme University. They have built a super Student Portal building using and Azure. The home page for this app will require some authentication probably against Azure AD and once logged in the student will be presented with a home page which is likely to contain lots of widgets with information targeted at them specifically. Its imaginable that the home page might show them things like:

  • What is my timetable today
  • How many library books do I have currently checked out
  • Are any books over due or close to over due
  • Have I got any messages
  • What is the latest news for:
    • Uni
    • My course
    • My faculty
  • Any info related to my sports at uni
  • Have I got any credit left on my student id
  • Have I got any exams
  • Have I got any results
  • Have I got any outstanding homework
  • Is there any new learning content for me

If you can imagine all of these scenarios are likely to load up on the home page and are all driven from the students logged in username. One of the challenges is that from a user perspective you want to give them a rich page with lots of good stuff in it but at the same time this page can have a lot of processing involved. If you imagine each of the above things probably integrates into different systems and some will be on premise, and some in the cloud. Decent browsers will be able to make parallel calls for some of that stuff but in general we are asking for a lot of stuff and the overall page load is going to involve a lot of calls to back end systems and a lot of processing on the web servers processing student requests for bits of data.

To try and visualise this lets imagine we have an architecture like the one below at a high level.

In this architecture the browser uses javascript to call WebAPI controllers within the Portal. For calls which go outside of its domain, the portal then calls Azure APIM which offloads the implementation of API Services into Azure Functions so that we can implement a microservices style integration API architecture. We have a similar pattern on premise too but they run as Web API inside of IIS. This gives us a lightweight easy way to integrate with all of our systems to support the needs of our Student Portal.

If we now want to look at the specific page load scenario for the home page, lets simplify the scenario so that the user needs to make 4 calls to the backend systems and each call goes to CRM. The sequence diagram of this may look something like the below.

Obviously its not as simple as that as each browser can make multiple concurrent calls from the browser to the Portal Web Servers and it can use some asynchronous processing to improve the performance somewhat, but even with this if you consider that Acme maybe a large university with lots of students concurrently using the portal then this still produces a lot of load on the web servers hosting the portal. It may not be so bad if these were just light weight Web Apps that can be scaled, but what if they were running Sitecore with licensing costs to consider and large scale servers. This load could be expensive to host.

The idea we were exploring is the opportunity to make all of these calls completely our of process from the Web App and to use Signal R to make call backs so that we could reduce the load on the servers and also improve the students perceived performance. Also there are factors to consider if some of your backend systems need load levelling requirements etc.

Transitioning the Architecture

To achieve the things we wanted to do, we modified the web app so that when the student logs in the first thing that happens from the home page is an event is raised to the API which is then submitted to a Service Bus queue. This event publishes that a student has logged in.

From here we modified all of the widgets so that they are no longer based on RPC calls to Web API’s. Instead we setup Signal-R Hub in the Web App and added some javascript to the web page so that when the page loads the javascript will register methods that will run when different messages are returned.

On the integration side of things we modified the API so that rather than running RPC style for this scenario we would instead use a Logic App to pick up the message and then go and interact with systems to grab all of the data required by the portal for that student. We could then make a call back to a Web API on the portal and that Web API would use the Signal R hub to send messages back to the appropriate clients.

The below picture shows this high level architecture.

The interesting thing with this approach was that it gave us a number of opportunities, first off when we push the message to Service Bus we can use a topic instead which allows us to publish to multiple different things that could process the message. Rather than having 1 Logic App which did everything we could split this out across multiple Logic Apps or we could use Functions in some places. The principle was the same though that they would process the message, get some data and call back to the Web API in the Portal.

To target messages back to the right browser, when the user initially calls the portal to create the event we will grab their Signal-R session Id and add this as a header which will go to the API and be added to the message as a property on the message that is submitted to service bus. You need to flow this id across all of the transactions.

The 2nd key piece was when we called the Web API on the portal we also included a message name property. This was used to dynamically call different methods on the Signal-R hub which triggers different functions in the javascript. This makes it easier for the portal developer to just have a simple function to load data into their widget. If we consider the earlier sequence diagram and how it would change, the below would be a closer representation of our new processing.

Hopefully that makes it clear how the architecture change has modified where most of the processing takes place and how dependencies have moved away from the user and their browser which will hopefully provide a better user experience.

Step by Step

The was we set this all up is described below:

Step 1 – The javascript helper for Signal -R

We used a wrapper script to make our javascript simpler, the below code snippet shows this helper script


var SignalrConnection;
var MessagingHubProxy;
var SignalRConnectionId;

function messageNotificationClientConnect() {    
    SignalrConnection = $.hubConnection();        

    MessagingHubProxy = SignalrConnection.createHubProxy('MessagingHub');
    //This will be called by signalr    
    MessagingHubProxy.on("SendMessageNotification", function (messageType, body) {
        AddMessageToUI(messageType, body);

    //connecting the client to the signalr hub   
    SignalrConnection.start().done(function () {
        alert("Connected to Signalr Server");

        SignalRConnectionId =;
        alert("Signal R Connection ID = " + SignalRConnectionId);
    .fail(function (a, b, c) {
       alert("failed in connecting to the signalr server");


Step 2 – Registering call back Functions

In the javascript for the home page we would register some call back functions with the Signal-R hub for directing messages to allow us to display the message.

$(document).ready(function () {

        MessagingHubProxy.on("GetTimetableResponse", function (body) {

        MessagingHubProxy.on("GetMyLibraryBooksResponse", function (body) {


Step 3 – Create Javascript Functions for the Call Backs

Next up we needed to create the call back functions in javascript to handle the messages returning to the browser. In this case below with the timetable data I am simply parsing the json that is returned and adding it to a collection and then using Knockout to bind a table to this. Im sure that much better javascript developers than me will have plenty of cooler new ways to do this but this isn’t the point of the article and I am not a javascript web developer so for this sample we will use Knockout.

    var timetableData;
    var timetableCollection = ko.observableArray();
    function HandleGetTimetableResponse(body) {
        timetableData = JSON.parse(body);       

Step 4 – Portal Web API to Start the Process

Next up we need to add the Web API in the Portal for the browser to call to start the process. In the below snippet I have simplified things somewhat rather than using the queue I am just calling the Logic App which responds immediately with a success response and then goes and processes in the background. The code for the Web API is

public class StudentLogonController : ApiController
        private static HttpClient client = new HttpClient();

        // POST: api/StudentLogon
        public void LoggedOn(Models.Student student)
            Debug.WriteLine($"Message received - {student.SignalRConnectionId}");

            var jsonText = JsonConvert.SerializeObject(invoiceRequest);
            var content = new StringContent(jsonText, UTF8Encoding.UTF8, "application/json");
            var response = client.PostAsync("https://<replaced><replaced>/triggers/manual/paths/invoke?api-version=2016-10-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=<replaced>", 

Step 5 – The button Click

In the javascript we also need a function on the button click to call the Portals Web API to indicate the student has logged on. Now this is only for the proof of concept and in the real world we would probably trigger this in a much different place but for the purposes of a sample its easier to be able to trigger the asynchronous gathering of data from the button click. Below is the java script behind the button.

function button_Click() {

        var request = {            
            StudentId: studentId,
            SignalRConnectionId : SignalRConnectionId
        var jsonRequest = JSON.stringify(request);

                type: "POST",
                url: "/api/StudentLogon",
                data: jsonRequest,
                dataType: "json",
                contentType: "application/json; charset=utf-8",
                success: function (result)
                    console.log("Message submitted to api");
                error: function (req, status, error)
                    window.alert("Error: " + error);


Step 6 – Signal-R Hub

In the Web App I need to add a class which will be the Signal-R hub. The interesting thing in this implementation wrapping the Signal-R hub is that I am using the message type parameter to dynamically trigger a function in the javascript which is why the js developer can just register for the message types they want to process.

The below code shows this.

using Microsoft.AspNet.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading.Tasks;
using System.Diagnostics;

namespace Acme.StudentPortal.Notifications
    public class MessagingHub : Hub
        private static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<MessagingHub>();

        public void SendMessage(string clientId, string messageType, string body)
            //Using the client id targets a specific browser
            Clients.Client(Context.ConnectionId).SendMessageNotification(messageType, body);

        public override Task OnConnected()
            Debug.WriteLine($"OnConnected: {Context.ConnectionId}");
            //Log app insights
            return base.OnConnected();

        public override Task OnDisconnected(bool stopCalled)
            Debug.WriteLine($"OnDisconnected: {Context.ConnectionId}");
            //Log app insights
            return base.OnDisconnected(stopCalled);

        public override Task OnReconnected()
            Debug.WriteLine($"OnReconnected: {Context.ConnectionId}");
            //Log app insights
            return base.OnReconnected();

        public static void SendMessageToHub(string connectionId, string messageType, string body)
            var client = hubContext.Clients.Client(connectionId);
            //client.SendMessageNotification(messageType, body);
            //This dynamic invoke uses the message type to target a function in the javascript
            client.Invoke(messageType, body);

Step 7 – Add Callback API

In the portal I also need to have a call back method which the Logic App will call back to with data to make it get pushed back to the browser via the hub. The logic app will return the payload of the message, the message type and the client id to send the message back to. Note that in this call back in the real world you will need to implement some kind of API security approach between the logic app and the portal.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace Acme.StudentPortal.Controllers
    public class MessagingCallbackController : ApiController
        // POST: api/MessagingCallback
        public HttpResponseMessage Post(HttpRequestMessage inputMessage)
            var messageBody = inputMessage.Content.ReadAsStringAsync().Result;
            var clientId = inputMessage.Headers.SingleOrDefault(x => x.Key.ToLower() == "ClientId".ToLower()).Value.FirstOrDefault();
            var messageType = inputMessage.Headers.SingleOrDefault(x => x.Key.ToLower() == "MessageType".ToLower()).Value.FirstOrDefault();

            Notifications.MessagingHub.SendMessageToHub(clientId, messageType, messageBody);

            return inputMessage.CreateResponse(HttpStatusCode.Accepted);


At this point we have made all of the desired changes to the portal.

Next up we need to implement the Logic App.

Logic App

As I mentioned previously its possible to have many Logic Apps process different things from the login event, you can also add them as a plug and play model. In this case below you can see the example getting any invoices for the Student. It will look up the details of invoices in CRM and use the HTTP action to make a call back to the portal for each one.


Hopefully by the end of this article you can see that it wasn’t that difficult to modify the web app from using the typical RPC approach to instead using Signal-R to implement call backs to data gathering can be done out of process. This is a great approach in scenarios where you have hybrid integration or complex data get requirements. It means rather than clogging up your web front end servers with waiting requests you can off load processing onto Azure’s serverless compute platform which will make your scaling much more effective.

You May Also Like

About the Author: michaelstephensonuk