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.

Search Engine Optimisation (SEO) for SharePoint Sites – Part 1

Search Engine Optimisation is a topic that i’ve always had a keen interest in. One of my first if not fleeting jobs fresh out of University was at an SEO company, albiet in a sales-based role. It still gave me an insight into something considered somewhere between an exact science and black magic and immediately peaked my interest. Since then i’ve read numerous articles on the subject, provided advice to friends, worked on projects both as the lead consultant and as the implementer for SEO consulting agencies’ recommendations. Not all have been for SharePoint sites, however the concepts applied are often not SharePoint specific. The information available on the web is extensive – it surprises me how SEO companies even manage to exist when the information is so freely available.

When deciding how to differentiate this article from the masses i’ve leant towards applying the concepts with a SharePoint flavour. I by no means claim to be an expert on the subject – merely a keen follower. I won’t claim that everything on here is correct. I may suggest something that has no positive effect on your search rankings whatsoever. In general though, i’ve noticed that applying the majority of these techniques have had a positive affect to the rankings of the sites, so there must be some truth to them.

Part 1 of this series will focus on what you can do in regards to the content, naming, metadata and structure of your SharePoint site. Search Engine Optimisation (SEO) for SharePoint Sites – Part 2 will delve a little deeper into how content can be manipulated to improve search rankings and other factors that can be leveraged from within SharePoint. Finally, Search Engine Optimisation (SEO) for SharePoint Sites – Part 3 will take a step outside the SharePoint box into how you can boost rankings and traffic to your SharePoint site using other methods.

Before I get started I just want to clarify one thing. This article series doesn’t touch on perhaps one of the most important factors in regards to search engine optimisation for a site – the initial research required before any of these steps are even considered. One must know the keywords and phrases that are going to be targeted before they actually can be, and this should be carefully deduced via research into the types of natural language searches your target audience are doing and the competition those terms and phrases have to optimise against. It’s something that definitely needs consideration before you start. But for now, on to the implementation.

Content is King

I love this saying. I’ve heard and read it hundreds of times. It’s a great way to describe how content is key to attracting and keeping visitors returning to your site. It’s also spawned a bunch of posts playing devils advocate such as Derek Halpern’s The ‘Content is King’ Myth Debunked. In a purely SEO sense however, the saying rings true. Content is the most critical element to improving site rankings. The more quality content that exists on the site, the more pages that will rank highly for different search terms and phrases. This isn’t exactly tailored towards SharePoint, however it is too critical to leave out. Content should be keyword and phrase rich – especially in the first and last paragraphs. Each page on your site should target something different – it is easier to optimise for one specific phrase rather than multiples which just leaves you with conflicting goals and spreads the optimisation power too thin. Take a look at the Infographic / Why Content for SEO? and read the links by Google engineer Matt Cutts and Bing’s Duane Forrester if you’re left with any doubt.

Page Titles are Important

Not only are page titles valuable from an SEO perspective, but they’re also what’s used when identifying the pages within the search engines and therefore serve a dual purpose. Not only is it important to use keyword-rich titles, but they need to be visually engaging to invite the user to want to click the link. From a strictly SEO perspective, page titles should begin and perhaps end with a key phrase, and be 6-12 words long. From a visual sense they should attract attention and interest and be no more than 67 characters to prevent Google chopping them short. Page titles should be unique and relevant to both the page content and phrase being targetted. SharePoint already contains the Title column for pages – your master page should contain a ContentPlaceHolder for the title and each page layout should render the page’s title via the SharePointWebControls:FieldValue control. It’s important to ensure the titles are set with optimisation in mind.

Set Page Description and Keywords Metadata

The general consensus is that meta keywords no longer play a part in SEO. Whether the meta description does or not seems to be debated – most sources suggest it is important, however Jill Whalen argues they may not affect your page’s ranking in The Meta Description Tag. My opinion on both is that it can’t hurt. Description is also important for other reasons – it is often the call out text used in either search results or other situations including extended site links or social media links such as when you type a link into facebook. It therefore, like the title, not only needs to be keyword or phrase rich but inviting and attracting to the target audience. The strategy i’d use here is to use the Description page column for both the meta description and keywords and use the same technique identified above for the page title (take note that the internal name of the Description column is actually Comments). It appears Office 365 makes this even easier via Add keyword meta tags to pages to improve search and it is believed SharePoint vNext will do the same. A little side note for the metadata specified above – it should be well structured in the head element of the page and appear towards the top of the page – before any other metadata, script or CSS references.

Name your Pages Appropriately

Page names are another way you can add weight to your page for a given search term or phrase. The important take-away from a SharePoint perspective here is to not rely on the default. The page name is generally auto-populated depending on the Title entered and essentially concatenates the words together. Some authors will modify this title, but do so either by using CamelCase or underscores to seperate the individual words. Neither are ideal from an SEO perspective. Search engines read both as one big word, however read hyphens as a sentence, thus it is important to name your pages accordingly. This can either be done manually or by using a feature developed by Waldek Mastykarz highlighted on Optimize Publishing Pages for search engines using the Imtech SharePoint SEO Slugs Feature.

Directory Structure and Naming Deserves Attention

Directory structure can assist as an optimisation tool. Take a look at Stoney deGeyter’s How to Create a Directory Structure Search Engines Rock To. In my opinion, having a solid structure driven by information architecture requirements is more important than the potential SEO benefits that could be gained – however if it’s possible to consider both then it’s worth doing. One thing to keep in mind is that the further down the chain a page is, the less weighting it will have in a search sense and the harder it will be to find. Keeping SharePoint in mind, there are 2 things to consider here. Firstly, it’s too easy to just spawn multiple sub-site chains when trying to seperate content – this may be done for no logical structural reasons, rather to seperate lists or functionality into different sub-sites – this should be avoided. The other issue from a SharePoint perspective is the frustrating ‘Pages’ directory. This obviously serves no SEO benefit, it in fact acts as a hinderance. There are potential ways around this – Waldek’s Semantic URL’s in MOSS 2007 is one of them, others involve virtual directories and redirects, URL-rewriting components or HTTP handlers. Waldek also has a solution for IIS7 in his Friendly URLs for SharePoint post however it is unsupported and only works in particular scenarios. To be honest, I don’t really like any of the options and for now would just cop the hit. I’m hopeful that SharePoint vNext makes this easier to get around, perhaps leveraging off the URL Routing in ASP.NET 4 functionality. It is believed that SharePoint vNext will provide some form of friendly URLs which would be a welcomed addition.

Your Domain Name Counts

Domain names are an essential component of optimising a site. Often these are forgotten due to the desire of a lot of companies or organisations to use their brand name as their domain name. Unfortunately, this isn’t hugely desirable when trying to optimise a site. It’s no coincidence that when you search for a number of search terms, many of the top results will have included it in their domain name. Many would assume that it’s a trade off, either use the brand name or choose a search-optimised domain name, however as Ian McNeice identifies in his book Step by Step SEO: Search Engine Optimisation for SharePoint Internet Sites (a read I highly recommend) this doesn’t need to be the case. This isn’t entirely in my realm of expertise so I won’t try and explain in detail how to achieve it, but SharePoint does provide Alternate Access Mappings to handle that side of multiple addresses so that would play a part in the process. Another little-considered factor in choosing a domain name for SEO purposes is the domain extension. It’s widely believed that the main domain extensions such as .com, .net etc carry more weight. I also believe however that if you are targetting a particular country for your audience then you’re better off using the domain extension for that country, for example .com.au for Australia.

In Search Engine Optimisation (SEO) for SharePoint Sites – Part 2 of this series I’ll delve a little deeper into how content can be manipulated to improve search rankings and other factors that can be leveraged from within SharePoint.

301 vs 302 Redirects in SharePoint

Recently I was faced with the request to implement some permanent 301 redirects for a publically facing SharePoint website. It was more of an investigative request rather than a call for action and as yet there has been no resolution, so rather than presenting a solution to the issue, this post will serve more as a discussion around it.

Rather than focus the article on the differences between a 301 and 302 redirect I’d rather point you in the direction of some existing resources that explain the details better than I could myself. The article Redirects: Permanent 301 vs. Temporary 302 does a good job in doing so.

The main concern around the 301 vs 302 redirect in SharePoint is 2-fold. Predominantly, there is a lot of information floating around the net in regards to the SEO implications of the 2 redirect techniques. To cut a long story short, 301 redirects are generally preferred from an SEO standpoint to 302 redirects. The problem being, SharePoint uses 302 redirects for its ‘Redirect Page’ layout. You can get a more in depth explanation of this in Jeff Cate’s post MOSS for Internet and 301 Redirects.

Those wanting to implement 301 redirects rather than the default 302 redirects are left with 2 main options. Firstly, IIS can be used to re-write the URLS (which serves as a 301 redirect). This can be done natively via an add-on in IIS7 and with a 3rd party add-on in IIS6. Secondly, the option exists to write a custom HttpModule to perform the 301 redirect as per Waldek Mastykarz’s post on Using 301 instead of 302 redirects. Waldek’s post is focussing more on another MOSS 302 redirect phenomenon rather than the Redirect Page layout but the concepts are still applicable.

I have a bit of an issue with both solutions. I should be attracted to the custom code option being a developer by trade, but from a complexity and maintainability point of view it doesn’t really appeal to me. It may be possible to architect a solution whereby the redirects are maintained in a SharePoint list improving the functions extensibility, and that’s probably the angle I would have looked into had time allowed, but it still seems like a bit of an overkill considering the IIS solution existed. The problem with the IIS solution however is (aside from it not being native in IIS6 which was being used in my instance) that maintenance would need to be conducted on the server by IT rather than the site owners.

Jeff posed the question in his post ‘Will it be in SharePoint 2010?’ – unfortunately, the answer is no. Waldek points out in a follow up post Using 301 instead of 302 (without code!) that they can be handled in IIS7 (required for SharePoint 2010) natively, which is true and how Jeremy Thake at NothingButSharePoint implemented their 301 Redirects in IIS7.5, but doesn’t solve the issue of giving access to site owners to perform the function. You really don’t want this administrative overhead placed on IT.

To be honest in my opinion we seem to be left with no ideal option. It would be nice (but still not ideal) if 301 redirects could be set and maintained via Central Administration (at least ensuring server access would not be necessary). It would be even better if they could be set and maintained in the Site Settings of the relevant site. Better still, an option on the redirect page to indicate whether it should be a 301 or 302 redirect would be perfect.

For now we’re left with the options presented. Having a personal interest in SEO myself it would be nice to see future versions of SharePoint tailored towards this goal in anyway possible, and making it easier to perform 301 redirects out of the box would be one way of getting there. Assuming SharePoint vNext is based on .NET 4.0 we should be a lot more likely to have this feature considering the 301 Redirects in .NET 4.0.

If it so happens that this piece of work is given the green light i’ll post a follow up on how the solution was achieved.

Follow

Get every new post delivered to your Inbox.