Harnessing SignalR in SharePoint 2013 (Office 365)

Over a year ago I wrote a post on Harnessing SignalR in SharePoint. Back then, SignalR was fairly new and the amount of information out there was limited. Getting SignalR to work with SharePoint posed some challenges, all of which are outlined in that post, however eventually we got it working. Since then I’ve had little to do with the technology however the colleague I worked with on that proof of concept, Elliot Wood, has continued to keep on top of the changes to the library and the implications that may have for SharePoint integration. While i’m posting this to my blog, i’m doing so on behalf of Elliot who is responsible for all of the magic soon to be displayed.

Even though there was a fair amount of excitement in regards to SignalR, and particularly the work we did around getting it working in SharePoint, the number of subsequent posts along the same lines was fairly limited. One person who carried the torch was Maximilian Melcher – his post SignalR in SharePoint 2013 – the real-time web is coming! outlined that integrating SignalR in SharePoint 2013 wasn’t as easy as one might expect – even though we were now on the .NET 4.0 framework which should have made life much easier. Max ended up getting his solution working and subsequently posted a codeplex solution, however the post was enough to pose the challenge to Elliot to get it working as easily as possible.

The solution presented uses an autohosted App for SharePoint 2013 hosted on Office 365. With Microsoft’s direction seemingly steering away from full-trust and sandboxed solutions and straight towards the App model, this can be considered the most viable and future-proof solution to the ‘SharePointR’ dream.

To ensure the focus of this post remains focussed on integrating SignalR with SharePoint i’m going to avoid the specifics about SignalR and how to program with it. I’m also going to avoid specifics on how to create and deploy SharePoint Apps. We’ve come a long way with SignalR and the information out there is much better – I’d recommend reading ASP.NET SignalR Hubs API Guide – Server (C#) if you need an overview of programming with SignalR. For those that need a primer on SharePoint Apps, particularly in relation to provider-hosted Apps on Office 365 (the more ‘production-safe’ way of hosting Apps on Office 365), then head over to Chris O’Brien’s post Deploying SP2013 provider-hosted apps/Remote Event Receivers to Azure Websites (for Office 365 apps) for a quick read.

Now that you’re comfortable with the theory, it’s on to the solution. There are 2 pieces to the autohosted App puzzle – the SharePoint App and the SharePoint App Web.

SharePoint App

The purpose of this project is to define the Remote Event Receiver (RER) and also configure the Installed Event Endpoint for the App. The former essentially sets the types of events that will trigger the remote service and points the App to that service, the latter points to the service which will trigger when the App is installed.

Adding the RER is as simple as right-clicking the project and adding a new Remote Event Receiver and selecting the events you want to listen out for. Everything else will be taken care of for you including creating the Package, Feature and tying the RER to its class which will be hosted in the SharePoint App Web.

Configuring the Installed Event Endpoint requires you to edit the properties of the SharePoint App project and set the Handle App Installed property to true. Once again Visual Studio takes care of the rest.

The final step is to access the Permissions tab in the AppManifest.xml editor and add the necessary permissions to the Web and List to ensure your App has the required levels of access to your site.

That’s all there is to it.

SharePoint App Web

Setting up the SharePoint App Web project is a little more involved than the above however is still relatively simple. The first step is to add a SignalR Hub Class to the project – having this native in Visual Studio is fantastic and greatly simplifies the process of getting up and running with SignalR ensuring all necessary references are added to the solution (note that you must have installed the ASP.NET and Web Tools 2012.2 update before you can add this class natively). Alternatively you can add SignalR via the Package Manager Console.

Elliot has also decided to implement the hub using a Singleton instance for optimum performance. For this you’ll need to add another class and insert the following code:

    public class SharePointR
    {
        // Singleton instance
        private readonly static Lazy<SharePointR> _instance = new Lazy<SharePointR>(() =>
            new SharePointR(GlobalHost.ConnectionManager.GetHubContext<SharePointRHub>().Clients));

        public SharePointR(IHubConnectionContext clients)
        {
            Clients = clients;
        }

        public static SharePointR Instance
        {
            get
            {
                return _instance.Value;
            }
        }

        private IHubConnectionContext Clients
        {
            get;
            set;
        }

        public void NotifyDataChanged(string ListName, string Event)
        {
            Clients.Group(ListName).dataChanged(Event);
        }
    }

Once that’s been created we can edit the Hub we added earlier and insert:

    [HubName("SharePointRHub")]
    public class SharePointRHub : Hub
    {
        private readonly SharePointR _sharePointR;

        public SharePointRHub() : this(SharePointR.Instance) { }

        public SharePointRHub(SharePointR sharePointR)
        {
            _sharePointR = sharePointR;
        }

        public void Subscribe(string ListName)
        {
            Groups.Add(Context.ConnectionId, ListName);
        }

        public void UnSubscribe(string ListName)
        {
            Groups.Remove(Context.ConnectionId, ListName);
        }

        public void NotifyDataChanged(string ListName, string Event)
        {
            _sharePointR.NotifyDataChanged(ListName, Event);
        }
    }

One final piece to the SignalR puzzle is to add a Global.asax file which should include the following:

        protected void Application_Start(object sender, EventArgs e)
        {
            var hubConfiguration = new HubConfiguration();
            hubConfiguration.EnableCrossDomain = true;
            hubConfiguration.EnableDetailedErrors = true;
            RouteTable.Routes.MapHubs("/signalr", hubConfiguration);
        }

Now we have our SignalR plumbing we can set up our event receivers. The first cab off the rank is the AppEventReceiver which will fire when the App is installed. What we want to achieve here is to manually hook up the item event receivers to a list in the host web, for instance an Announcements list.

    public class AppEventReceiver : IRemoteEventService
    {
        private string ReceiverName = "RemoteEventReceiver";
        private List<EventReceiverType> EventType = new List<EventReceiverType>()
        {
            EventReceiverType.ItemAdded,
            EventReceiverType.ItemAdding,
            EventReceiverType.ItemUpdated,
            EventReceiverType.ItemUpdating,
            EventReceiverType.ItemDeleted,
            EventReceiverType.ItemDeleting
        };
        private string ListTitle = "Announcements";

        public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
        {
            SPRemoteEventResult result = new SPRemoteEventResult();

            using (ClientContext clientContext = TokenHelper.CreateAppEventClientContext(properties, false))
            {
                Web hostWeb = clientContext.Web;
                clientContext.Load(hostWeb);

                List docLib = clientContext.Web.Lists.GetByTitle(ListTitle);

                string opContext = OperationContext.Current.Channel.LocalAddress.Uri.AbsoluteUri.Substring(0,
                   OperationContext.Current.Channel.LocalAddress.Uri.AbsoluteUri.LastIndexOf("/"));
                string remoteUrl = string.Format("{0}/RemoteEventReceiver.svc", opContext);

                if (properties.EventType == SPRemoteEventType.AppInstalled)
                {
                    foreach (var eventType in EventType)
                    {
                        EventReceiverDefinitionCreationInformation newEventReceiver = new EventReceiverDefinitionCreationInformation()
                        {
                            EventType = eventType,
                            ReceiverAssembly = Assembly.GetExecutingAssembly().FullName,
                            ReceiverClass = "SignalRProxyService.Services.RemoteEventReceiver",
                            ReceiverName = ReceiverName + eventType.ToString(),
                            ReceiverUrl = remoteUrl,
                            SequenceNumber = 1000
                        };
                        docLib.EventReceivers.Add(newEventReceiver);
                    }
                    clientContext.ExecuteQuery();
                }
                else if (properties.EventType == SPRemoteEventType.AppUninstalling)
                {
                    IEnumerable<EventReceiverDefinition> receivers = clientContext.LoadQuery(docLib.EventReceivers
                        .Where(e => e.ReceiverName == ReceiverName));

                    foreach (var rec in receivers)
                    {
                        rec.DeleteObject();
                    }
                    clientContext.ExecuteQuery();
                }
            }
            return result;
        }

        public void ProcessOneWayEvent(SPRemoteEventProperties properties)
        {
            // This method is not used by app events
        }
    }

We then want to code up the Remote Event Receiver to handle the events triggered on the site and push a message via SignalR to our page. This is a very simplistic example that shows that the item affected in the list we’ve subscribed to is what is causing the update on the page.

    public class RemoteEventReceiver : IRemoteEventService
    {
        private SharePointRHub client = new SharePointRHub();

        public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
        {
            client.NotifyDataChanged(properties.ItemEventProperties.ListTitle, properties.EventType.ToString());
            return new SPRemoteEventResult();;
        }

        public void ProcessOneWayEvent(SPRemoteEventProperties properties)
        {
        }
    }

The final step is to code up the page. There are a number of aspects here which should be completed to get the branding right for the App – these are covered in greater detail in the how-to guide listed at the end of this post. For now i’ll highlight the main code needed to hook up SignalR on the page (note that references to scripts not yet mentioned in this post are also covered in that guide).

    <!--Script references. -->
    <script src="//ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js"></script>
    <script src="/Scripts/jquery-1.8.2.min.js"></script>
    <script src="/Scripts/json2.js"></script>
    <script src="/Scripts/chromeLoader.js"></script>
    <script src="/Scripts/jquery.signalR-1.0.0.js"></script>
    <script src="/signalr/hubs"></script>

    <!--Add script to update the page and send messages.-->
    <script type="text/javascript">
        $(function () {
            var connection = $.hubConnection();
            proxy = connection.createHubProxy('SharePointRHub')
            proxy.on('dataChanged', function (eventType) {
                $('#MainContent').append('<li>Data changed - ' + eventType + '</li>');
            });
            connection.start()
                .done(function () {
                    //Subscribe to Announcements list
                    proxy.invoke('Subscribe', "Announcements");
                    $('#MainContent').append('<span>Now connected, connection ID=' + connection.id + '</span>');
                })
                .fail(function () {
                    $('#MainContent').append('<span>Could not Connect!</span>');
                });
        });
    </script>

And that’s about it! The image below gives a sneak peak into how an event triggered via a SharePoint list can be reflected on a separate page in real time. It is far more impressive however seeing it in person, so I’d encourage you to follow the guide provided below and get ‘SharePointR’ up and running for yourself – the possibilities this technology opens up is limitless and it will be exciting to see the kinds of solutions designed which leverage SignalR within SharePoint in the near future.

PreviewDownload: Walkthrough-Deploying a SignalR autohosted App to Office 365

Harnessing Client-Side Technologies to Enhance your SharePoint Site

Yesterday I had the privilege of presenting at the Perth SharePoint User Group. The experience was sensational; the session went off without a hitch, the crowd was large, attentive and full of questions. Feedback both immediately after the session and that which filtered through later was very positive. As promised and to wrap up the event I thought it was only fitting that I posted my slides and a summary of the presentation – this is that post.

The day started off with a little milestone – something I’ve yet to see myself previously and which I expect is relatively rare for the PSPUG

100 tickets – the last one snapped up only hours before the event. I’ve been told Microsoft (who I must thank for allowing us to use their excellent facilities every month) was contacted on the day to hunt down some more chairs for the room. At best guess I’d say there was about 70-80 people who made it – evident by the few chairs left empty and the speed at which 15 family sized pizzas were demolished.

But enough with the background, onto the presentation itself. I had set it up to be roughly 30 minutes of slides and discussion and 30 minutes of demo. In the end I cut the demo’s a bit short – I figured it was more important to answer a few questions than explain the detail of what was going on for each one. I’ll fill the blanks in this post pointing off to the resources you’ll need to replicate the demos yourself. Along with posting the slides I’ll also jot down some of the main points I was trying to get across in each one.

Who am I

You may think this slide needs no explanation but I want to stress the point I made in the session again. While i’ve only recently joined twitter, the little gems of information I’ve been able to garner in that time have been extremely valuable. I avoided twitter like the plague, mostly due to an impression it was predominantly noise. It is. But if you can get past that you can get to its true value and keep in touch with what’s going on in the wider SharePoint community.

Agenda

I was tossing up between deep diving into one of the technologies or doing a broad brush overview of the lot – clearly the latter approach was taken. The goal of the session was to inform and inspire – there is plenty of information out there to read up on at a later date – some of which i’ll outline in this post.

JavaScript

Not much to say here – bit of an obligatory slide to round out the presentation as a whole. We’ll move on.

jQuery & The basics

Aside from the information, the main point I want to highlight is that jQuery really isn’t that scary. It simplifies JavaScript a great deal and the learning curve really isn’t that steep compared to the benefits you’ll gain from using it. It’s quite performant and efficient when compared to some of the .NET based AJAX libraries out there, it’s become one of my favourite technologies to use when creating public facing websites and I hope I impressed at least a few in the audience enough to give it a shot. For a primer on some of the basics and functions jQuery provides, have a read of the documentation.

Tips and Tricks

There was a fair few tips and tricks to cover in the session – rather than explain each one i’ll attempt to link off to a resource which will do the job for me.

Putting jQuery into noConflict mode

Making use of jQuery(document).ready()

Leverage callbacks

Don’t write scripts directly into the Content Editor Web Part

(Keep in mind it may not be suitable for staged environments with content deployment – converts the link to an absolute url!)

Know your options for referencing jQuery

(Although I don’t have a problem with referencing on the master page)

Enable Intellisense in Visual Studio

Know your options for debugging

(Don’t forget about the console window in Firefox! Can be very useful. Also, remember that different browsers can often end up shedding the light on your issue, so don’t discount debugging in multiple browsers)

It would be remiss of me not to give a shout out to Chris O’Brien considering the last 2 links are from his blog. In fact, all the posts of that series are worth a read so I’d definitely encourage you to do just that.

Plugins!

The true power of jQuery lies in the multitude of plugins available to be used. They can be a huge time-saver and with a bit of knowledge you can often customise them to suit your needs. There are hundreds of quality resources out there explaining which plugins are great – i’ll leave it up to you to explore!

Knockout

Knockout is fantastic. I can’t speak of it highly enough – do yourself a favour and check out the documentation and live examples to get a taste of what it is capable of. I could have done a whole presentation on Knockout itself – John Liu does a great one in his session SSPUG retrospective: Creating Knockout user experiences in SharePoint with JavaScript for those Aussies amongst us, definitely check it out if you get a chance. I hope I did it justice to peak your interest enough to dive deeper into the technology. Keep in mind that Knockout works brilliantly with both the jQuery templating libraries (jquery-tmpl or jsRender) and jQuery itself. I mentioned that while I’ve used jquery-tmpl in the past, it has been discontinued so you may want to look into jsRender instead.

SignalR

This is another topic that could have had a session to itself. In fact, Christian Heindel already did – it was nice to see myself in someone elses slides half a world away! I didn’t dive too heavily into this, it was more of a primer to spark some interest and simply let the demo do the talking.

Retrieving Data on the Client Side

To date I had only discussed the tools available to present information on the client – this slide was all about how we got that information in the first place. Rather than link to resources here (it should be really easy to search for them yourself) what I’ll do is outline my main points discussed.

Client Object Model: handy tool provided in SP2010. Need to learn the syntax which is different from the standard OM and should definitely know some CAML. Important to consider performance when writing this code.

REST services: absolutely love them. Extremely valuable with their ability to return JSON data simply by structuring the URL with query string. Their ability to return JSON makes them great to combine with Knockout or jQuery.

SPServices: extremely valuable library written by a member of the SharePoint community Mark D Anderson. Perfect for those stuck on SP2007 but also valid for SP2010. Have a read of the debate going on regarding when you should use one or the other.

HTTP Handlers: another tool at your disposal in SP2007. To be honest the main reason I have used these is because I wasn’t truely aware of the power of SPServices. The general premise is you fire off to the HTTP Handler which runs some server side code, serializes the data into JSON and returns it back via Response. Still handy if you simply MUST have JSON in SP2007.

Content Query Web Part: not strictly a client side technology, but it is so powerful out of the box that it deserved a mention. Combined with a bit of XSL it is truely one of if not the best web parts provided to us in SharePoint.

Demos!

And then it was time for the fun stuff. I considered recording all of the demo’s to place here but it wouldn’t have been as relevant without the accompanying dialogue, and I didn’t really want to record my own voice. I’ve settled for links to the inspiration behind each demo – if you have any questions feel free to ask and I will go into more detail.

Demo 1: Client Object Model & jQuery

This one came from a tweet I noticed a week before my presentation. Take a look at Using the SharePoint Client Model to populate a jQuery AutoComplete box by Douglas Leung. The delay you get before the autocomplete kicks in is because we’re waiting for SharePoint to load the relevant scripts before we bind the event.

Demo 2: SPServices & jQuery

Thankfully I dropped the right name in my presentation! It was Mark Rackley responsible for the inspiration behind An Easy to Use Content Slider. Sure his version isn’t as good as the one which featured some of the best the mighty Fremantle Dockers have to offer, but the general vibe of the slider is the same ;)

Demo 3: Content Query Web Part + XSL + jQuery

I’ve said all I need to say about this one in my post Using the Content Query Web Part and jQuery to create a staff desk locator so if you’re interested pop over to that post and take a look at the nuts and bolts holding it together. One point I did mention in the presentation is that the solution kind of grinds to a halt in the older versions of IE due to the struggles it has with larger-scale manipulation of the DOM.

Demo 4: REST services + Knockout + TMPL + jQuery slider + jQuery validation + jqPlot

Yes, there was a lot to this one. I did create this demo specifically for the session but my post on Applying the MVVM pattern to create SharePoint list-driven interactive tools using Knockout covers the jist of it. If not, just drop me a line.

Demo 5: SignalR

Definitely a topic which gets me pretty excited. The demo I showed was the same one I posted in Harnessing SignalR in SharePoint – complete with video! So check it out if you want a look under the hood at how we made that happen.

And that pretty much covers it. There were some great questions to follow the session, enough so that all of the left over SP Saturday ‘limited edition’ USB key’s were given away. I truely appreciated the opportunity to present again at the user group and was humbled by the turnout. I hope a few people were inspired to go out and try some of the technologies presented in their own SharePoint environments.

I’ll sign off with a couple of tweets I received after the session – one in particular that made the whole session worth while!

Harnessing SignalR in SharePoint

Note: For those interested in the implementation of SignalR in SharePoint 2013, view the latest post Harnessing SignalR in SharePoint 2013 (Office 365)

On the 1st of April Bil Simser wrote an article Introducing SharePointR. I happened to read it on the 3rd and as such it wasn’t until I got to the ‘quote’ by David Fowler that I tweaked to what was going on. It was a clever April Fools post and likely got a lot of people excited. For me, it piqued my interest. I’d heard of SignalR in passing but had yet to delve into it. Once I had, I have to say I got pretty excited myself. It’s super cool. I, along with one of my extremely talented colleagues Elliot Wood, went about getting SignalR up and running in a SharePoint environment.

SignalR is relatively new and as such the information available isn’t extensive, but what is out there is pretty good. There are a few examples you should check out right off the bat: Scott Hanselman’s Asynchronous scalable web applications with real-time persistent long-running connections with SignalR and Justin Schwartzenberger’s Learn how to use SignalR and Knockout in an ASP.NET MVC 3 web application to handle real-time UX updates were the two I found to start with. Both link off to a number of other valuable examples.

So what is SignalR? Essentially, it’s real-time client-server communication on the web. Without having to constantly poll or perform any refreshes, data on the page will ‘magically’ update in front of your eyes. The library is maintained on Github which gives you access to the latest code, issues and documentation at a central source. I’m not going to go too far into what it is, because with the excitement that’s being generated around this, plenty of other people are doing a far better job of it than what I could. I’ll skip straight to the fun stuff.

So if the examples are already out there, why can’t we just plug this straight into SharePoint?

The majority of examples which currently exist tend to host the hub and the client in the same project, and hence are hosted on the same domain. This works great, you can spin up your .NET 4.0 web application and everything will work smoothly. Only problem being SharePoint runs on the .NET 2.0 framework – you won’t be able to add the SignalR DLLs to your SharePoint project.

This however is not a deal-breaker. As long as your hub is hosted on a .NET 4.0 web application you can leverage SignalR in a simple HTML file with JavaScript, so surely that would be easy enough to plug into a SharePoint web part?

Firstly; it’s not exactly simple. It requires something called Cross-Domain Calling which I’ve since found out is a bit of a pain to get working across different browsers. This is where the information fell down a little, or at least was scattered around. I’ve read more StackExchange and Github Issues than I care to dig back up and link to for this article so excuse my lack of referencing here. One page I did come across which got me most of the way there was Thomas Krause’s Making Cross-Domain Calls in SignalR which summed it up pretty nicely, but still didn’t work in all browsers for me. But more on this later.

Secondly; even with all those issues resolved we still want a way to trigger SignalR to broadcast an update from SharePoint, and unless you’re doing that purely with client interaction in the UI, chances are that’s going to mean handling create, update and delete events via event receivers. Which brings us back to our first issue – these will be on the .NET 2.0 framework and won’t be able to reference the SignalR DLLs. So how do we get around this?

Essentially what is required is a bridge between SharePoint’s .NET 2.0 environment and a .NET 4.0 one. I liked the way Elliot termed this better: breaking the .NET barrier. My initial thoughts were hosting a WCF service and passing the information from the event receiver to that service to be broadcast by SignalR, and I still think that would be the ideal solution. Elliot however beat me to the implementation by making the leap via HTTP and posting to a handler sending the information via Query String, and for the purposes of the proof of concept (minimal data being transfered) this did the trick nicely.

With all the pieces of the puzzle in place, it’s time to implement our SignalR in SharePoint proof of concept. The idea is pretty simple – consider it a mini task-tracking system. Tasks will get added to the pile and others will be completed. The service quality manager will have a dashboard on their monitor open all day receiving live information on whether performance targets are being hit on a day-to-day basis. Let this be a glimpse into the power of what SignalR can achieve and let your imagination run wild on possible real-world implementations.

Step 1: Create the Hub

The Hub needs to be a .NET 4.0 web application. The majority of examples on the net state the first step of implementing any SignalR application is to use nuget to retrieve the SignalR DLLs and scripts. This is fine in theory, but while we were investigating our cross-browser issues (non-performance in Firefox and Chrome) Elliot noticed that the nuget version of SignalR is not the latest, therefore downloading the latest ZIP and re-referencing the DLLs is the way to go. In fact the ‘latest’ version from Github at the time of writing included another required DLL that the nuget version didn’t bring across – SignalR.Hosting.Common.dll. Others that you’ll want the updated version for (or at least the ones we used) include SignalR.dll, SignalR.Hosting.AspNet.dll and Newtonsoft.Json.dll.

The next step is to add an entry into the web.config file to allow the cross-domain calls. This requires adding the following snippet to the system.webServer node

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
  </customHeaders>
</httpProtocol>

The final step is to add a class to your project to house the Hub

using SignalR.Hubs;

namespace SignalRHub
{
  public class SharePointHub : Hub
  {
    public void Send(string message)
    {
      // Call the addMessage method on all clients
      Clients.addMessage(message);
    }
  }
}

At this point all the extraneous components of the project can be removed so you’re left with the class, the web.config and packages.config. Just a note – the Send implementation is somewhat redundant as we’ll be calling the client script from the handler below rather than the hub itself – but it’s useful for testing.

Step 2: Create the HTTP Handler

The handler can exist in the same project created above and will essentially be the tool to receive the Query String data from SharePoint and broadcast it via SignalR to the clients. All credit here goes to Elliot for the concept, I’ve adapted it to match my SignalR implementation (I used a Hub, he used a Persistent Connection).

One major thing to point out is that the documentation currently offers this as the method of broadcasting over a Hub from outside of a Hub

using SignalR.Infrastructure;

IConnectionManager connectionManager = AspNetHost.DependencyResolver.Resolve<IConnectionManager>();
dynamic clients = connectionManager.GetClients<MyHub>();

This documentation however is only valid for the 0.4.0 build of SignalR you would get from nuget – the latest version establishes the IConnectionManager from another means

IConnectionManager connectionManager = Global.Connections;

The resulting code for the ProcessRequest is as follows

public void ProcessRequest(HttpContext context)
{
    context.Response.ContentType = "text/plain";

    IConnectionManager connectionManager = Global.Connections;
    dynamic clients = connectionManager.GetClients<SharePointHub>();

    var payload = new
    {
        TasksOpenedToday = context.Request.Params["TasksOpenedToday"],
        TasksCompletedToday = context.Request.Params["TasksCompletedToday"],
        LightStatus = context.Request.Params["LightStatus"]
    };

    JavaScriptSerializer jss = new JavaScriptSerializer();
    var payloadJSON = jss.Serialize(payload);
    clients.addMessage(payloadJSON);
}

Step 3: Create the Event Receiver

There’s nothing particularly fancy going on here aside from posting to our HTTP handler we created in step 2. The rest of the code is just a simple event receiver bound to a task list. If you need help at this step then take a look at Walkthrough: Deploying a Project Task List Definition. We’ll need to override the ItemAdded, ItemUpdated and ItemDeleted events and add the following code

Broadcast(getPayload(properties));

private string getPayload(SPItemEventProperties properties)
{
    SPList list = properties.List;
    SPQuery query = new SPQuery();
    query.Query = "<Where><Eq><FieldRef Name='Created' /><Value Type='DateTime'><Today /></Value></Eq></Where>";
    SPListItemCollection items = list.GetItems(query);
    double tasksOpenedToday = items.Count;

    double tasksCompletedToday = 0;
    foreach (SPListItem item in items)
    {
        if (item["Status"].ToString() == "Completed") tasksCompletedToday++;
    }

    string colour = "RED";
    int percentage = (int)Math.Floor(tasksCompletedToday / tasksOpenedToday * 100);
    if (percentage >= 70) colour = "GREEN";
    else if (percentage >= 50) colour = "ORANGE";

    return string.Format("?TasksOpenedToday={0}&TasksCompletedToday={1}&LightStatus={2}",
        tasksOpenedToday.ToString(),
        tasksCompletedToday.ToString(),
        colour);
}

private void Broadcast(string Payload)
{
    WebRequest request = HttpWebRequest.Create(string.Concat("http://server:port/SharePointRProxyHandler.ashx",Payload));
    WebResponse response = request.GetResponse();
}

Step 4: Create the Web Part

We’re on the home stretch. We’ve got an event receiver posting data to an HTTP handler, which is in turn broadcasting that via SignalR. The only thing left to do is create the client to listen out for that broadcast. This can essentially be HTML and JavaScript and as such doesn’t really need to be a web part at all, but I’ll be creating a visual one in the interests of effective deployment.

It’s here that we need to think back to when we retrieved the latest files from Github for SignalR. You’ll now need to grab the latest JavaScript files from that package and store them in SharePoint so we can reference them in our web part. You’ll also need to grab and store Knockout.

There’s a few differences you’ll need to consider compared to the generic example provided for implementing the SignalR client for hub communication. Firstly, instead of referencing /signalr/hubs in your script src, you’ll need to reference it in the location in which it exists

<script src="http://server:port/signalr/hubs" type="text/javascript"></script>

Secondly, you’ll need to force jQuery to support cross-site scripting

jQuery.support.cors = true; //force cross-site scripting

Third, your hub URL will also need to point to the relevant location

$.connection.hub.url = 'http://server:port/signalr';

Your Hub name will need to be in camel-case (which isn’t clear in the example seeing it’s all lower case)

var sharePointHub = $.connection.sharePointHub;

Your client handler will need to parse the JSON sent in seeing it’s not a simple string

sharePointHub.addMessage = function(json) {
var data = JSON.parse(json);
};

And finally you’ll need to pass a couple of options into the call to start the connection to your Hub

$.connection.hub.start({ transport: 'longPolling', xdomain: true });

That pretty much covers it. Add in some initial population of the viewModel server side and the necessary Knockout bindings and the web part is ready to be deployed. You can see the final web part (minus the basic server side population of variables) below

<style type="text/css">
    .dashboard-item { margin-bottom: 10px; }
    .dashboard-label { font-weight: bold; }
    #LightStatus { width: 50px; height: 50px; }
    .RED { background-color: Red; }
    .ORANGE { background-color: Orange; }
    .GREEN { background-color: Green; }
</style>

<script src="/SiteAssets/jquery-1.7.min.js" type="text/javascript"></script>
<script src="/SiteAssets/json2.min.js" type="text/javascript"></script>
<script src="/SiteAssets/jquery.signalR.min.js" type="text/javascript"></script>
<script src="/SiteAssets/knockout-2.0.0.js" type="text/javascript"></script>
<script src="http://server:port/signalr/hubs" type="text/javascript"></script>

<div class="dashboard-item"><span class="dashboard-label">Tasks Opened Today: </span><span data-bind="text:tasksOpenedToday"></span></div>
<div class="dashboard-item"><span class="dashboard-label">Tasks Completed Today: </span><span data-bind="text: tasksCompletedToday"></span></div>
<div id="LightStatus" data-bind="attr: { class: lightStatus }"></div>

<script type="text/javascript">
    var viewModel = {
        tasksOpenedToday: ko.observable(),
        tasksCompletedToday: ko.observable(),
        lightStatus: ko.observable()
    };

    $(document).ready(function () {
        jQuery.support.cors = true; //force cross-site scripting

        $.connection.hub.url = 'http://server:port/signalr';

        // Proxy created on the fly
        var sharePointHub = $.connection.sharePointHub;

        // Declare a function on the chat hub so the server can invoke it
        sharePointHub.addMessage = function (json) {
            // Update viewModel values here
            var data = JSON.parse(json);
            viewModel.tasksOpenedToday(data.TasksOpenedToday);
            viewModel.tasksCompletedToday(data.TasksCompletedToday);
            viewModel.lightStatus(data.LightStatus);
        };

        //Populate viewModel via ASP.NET and bind to Knockout
        viewModel.tasksOpenedToday("<%= InitialTasksOpenedToday %>");
        viewModel.tasksCompletedToday("<%= InitialTasksCompletedToday %>");
        viewModel.lightStatus("<%= InitialColour %>");
        ko.applyBindings(viewModel);

        // Start the connection
        $.connection.hub.start({ transport: 'longPolling', xdomain: true });
    });
</script>

So how does it look in the end? You be the judge..

So there you have it. I’d be surprised if there’s anyone out there that didn’t think this was pretty awesome. With any luck this will inspire you to go forth and make your own SharePoint implementations with SignalR – I’m looking forward to seeing what will be achieved with this excellent technology. Already Elliot has taken up the challenge to bring Bil’s ‘April Fools’ concept to life, it’s the kind of inspiring functionality that makes you want to go out and experiment. Just one last note – for anyone fearful of how this somewhat new technology would go in an enterprise environment, take a look at the video C#5, ASP.NET MVC 4, and asynchronous Web applications.

Follow

Get every new post delivered to your Inbox.