Connected SharePoint app parts with SignalR

One of the classic questions related on the SharePoint app parts is their capability to connect between each other. This has been classic scenario with web parts since the dawn of the SharePoint, so question is pretty understandable. Since app parts are essentially IFrames in steroids, they don't  natively support similar connectivity models as the classic web parts, but we can solve the requirement using alternative approach.

We have basically two different options for the connectivity with the app parts:

  • Client side route
  • Server side route

Client side route is the model where app parts will communicate between each other, using client side messaging using JavaScript. This process is well explained in Richard diZerega’s blog post. This pattern works nicely, but does however require changes on the SharePoint side, since the page where the app parts are placed, have to act as a message broker and this requires few lines of JavaScript to be added.

High level architecture for server side model

Following picture defines the high level process on setting things to work with server side pattern. This means that our provider hosted application server side code has to act as the broker for the app parts. Essentially any operation what we want to communicate to other app parts are exposed to app parts using JavaScript and the routing between the app parts happens outside of the SharePoint.

image

  1. Actual app part instances on the pages with the operations to communicate to server side code
  2. SignalR Hub proxy, which works as the message broaker between client side code and server side code
  3. Actual hub for routing messages is in the provider hosted app server side code. Each app part registeres to the hub and after that you can do real time communications between them

Server side connectivity with App parts

In the example, provided as a downloadable code, we are using SignalR for providing real time connectivity between the clients (app parts) and the server side services. Actual communication is managed in the app part using JavaScript. Operations are then routed to the server side code, which is publishing needed actions for other registered “clients”. When we use SignalR, actual implementation is surprisingly easy and provides interesting scenarios.

Following video demonstrates the key areas of the code and how the server side communication works cross app parts.

Actual implementation for SP app

SignalR code part was directly borrowed from the SignalR getting started guidance, which explains how to setup things and how the code actually works. All I did was take the code and created two app parts, which will talk between each other. To be precise, each web part instance could actually also talk between other instances, but this is up to the design.

Here’s how the app parts are shown on the page when we have two web parts, which are communicating between each other.

clip_image001

Actual communication from the app part is done using SignalR JavaScript, which is then calling the provider hosted server side code. Here’s the core implementation for the JavaScript, where we have two main functionalities: broadcastMessage and Send. For both of these JavaScript operations there’s a corresponding server side implementation, meaning that the information from JavaScript is passed through to server side and again back to JavaScript in different app part instances.

 <!--Add script to update the page and send messages.--> 
 <script type="text/javascript">
     $(function () {
         // Declare a proxy to reference the hub. 
         var chat = $.connection.chatHub;
         // Create a function that the hub can call to broadcast messages.
         chat.client.broadcastMessage = function (name, message) {
             // Html encode display name and message. 
             var encodedName = $('<div />').text(name).html();
             var encodedMsg = $('<div />').text(message).html();
             // Add the message to the page. 
             $('#discussion').append('<li><strong>' + encodedName
                 + '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>');
         };
         // Set initial focus to message input box.  
         $('#message').focus();
         // Start the connection.
         $.connection.hub.start().done(function () {
             $('#sendmessage').click(function () {
                 // Call the Send method on the hub. 
                 chat.server.send($('#displayname').val(), $('#message').val());
                 // Clear text box and reset focus for next comment. 
                 $('#message').val('').focus();
             });
         });
     });
 </script>

Here’s the server side implementations for those functions in the Hub implementation. This hub is as simple as it gets. Name and message information sent from client side is simply broadcasted to all connected clients without any filtering or modifications. You could just as well filter or route the messages only to specific clients, which in this case would be then different app parts.

 public class ChatHub : Hub
 {
     public void Send(string name, string message)
     {
         // Call the broadcastMessage method to update clients.
         Clients.All.broadcastMessage(name, message);
     }
 }

Since communication happens on server side, you can actually make this work cross processes, browsers, computers or end users. This is also important thing to remember during the implementation. Provided example actually shows all the messages for all the browsers which are accessing the page at the same time. This opens up pretty interesting other opportunities, but if you want to use SignalR just for isolated session based communications, you’ll need to filter the traffic between the app parts based on the session. This could be done in the server side hub by using the information we get from the call.

Here’s a picture of a situation where we have two different pages in the site, which are having two different web parts accessed by two separate browser processes. If we want, we can make the communication to work in this kind of scenario as well, but then we are talking slightly different pattern or objective than just having connected app parts.

clip_image001[5]

References

Few useful links and resources related on this blog post.