Knowledge is power. We love to share it.

News related to Mono products, services and latest developments in our community.

pajo

Using SignalR with MonoX

12/07/2012Categories: MonoX

You have probably heard about the very cool SignalR library - if not, you can find more info on Scott’s blog. It is one of those indispensable tools for building real-time multi-user web applications. I've been working with it a lot during the last couple of months while developing a real time communication (chat) infrastructure for the next release of MonoX. It is an open source project and it may still not mature enough for every purpose, but form what we have seen so far it looks very promising. I’m going to explain how to use SignalR by building a simple module that displays notifications to all active users in real-time.

Building simple notification module with SignalR

First we need to add SignalR to our project, you can take source code from GitHub and build it yourself, or you can add it using NuGet in Visual Studio - I recommend the latter approach unless you really need to have that latest version. To install SignalR in your project using NuGet manager console just type “Install-Package -pre Microsoft.AspNet.SignalR”. You will probably need to add Microsoft.CSharp to the project references if you haven’t included it in the project. Now, we need to make some changes in the web.config. SignalR communication protocol will not work with MonoX compression module, if you’re using it you’ll need to exclude SignalR path from the compression module's reach. To do this add a single following line in the HttpCompress section

<HttpCompress turnedOn="true" defaultProvider="Deflate" useCaching="true">
    <providers>
    <clear/>
    ...
    </providers>
    <ExcludedMimeTypes>
    <clear/>
    ...
    </ExcludedMimeTypes>
    <ExcludedPaths>
    <clear/>
    <!--Example-->
    <!--<add name="WebResource" path="WebResource.axd"/>-->
    <add name="SignalR" path="/signalr/*"/>
    </ExcludedPaths>
</HttpCompress>

By default, SignalR will register a new route on “/signalr” path, used mainly for sending messages between clients and a server. Going further, dynamic compilation required for SignalR framework will not work if you have set legacyCasModel to true, and this is the default value in MonoX. Find it in web.config and set it to false. We’re now ready to build our module. For our notification server,  we’re going to use SignalR hub. Hub simplifies and abstracts away some low level details when using persistent connections for message dispatching.The code for our hub is very simple.

public class NotificationHub : Hub
{
    public void SendNotification(string message)
    {
        if (SecurityUtility.IsAdmin())
            Clients.All.notify(message);
    }
}

As you can see there is not too much code here, but there is some magic working for us. Hub class that is inherited by our notification hub is used by SignalR to find all hubs in the running assemblies and to create script for client proxies you're going to use for calling server actions from client.  You will find autogenerated script for all client proxies  in the folder “/signalr/hubs”.
Notification module will need to a script reference to the core SignalR script, and a reference script for hubs

public partial class NotificationModule : BaseAutoRegisterPart
{
    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
 
        JavascriptUtility.RegisterClientScriptInclude(this, "/Scripts/jquery.signalR-1.0.0-alpha2.min.js");
        JavascriptUtility.RegisterClientScriptInclude(this, "/signalr/hubs");
 
        plhAdminPanel.Visible = SecurityUtility.IsAdmin();
    }
 
}

Besides referencing SignalR scripts, we’re just hiding a panel for sending notification from non-admin users. The markup file holds more interesting functionality:

<asp:PlaceHolder ID="plhAdminPanel" runat="server">
<div class="admin-panel">
    <textarea class="notification-message" rows="3"></textarea>
    <div>
        <input type="button" value="Send" onclick="$.connection.notificationHub.server.sendNotification($(this).closest('.admin-panel').find('.notification-message').val())" />
    </div>
</div>
</asp:PlaceHolder>
 
<div>
    <p>Notification</p>
    <div class="notification-message">
     
    </div>
</div>
 
<script type="text/javascript">
    $(function () {
        // Proxy created on the fly         
        var hub = $.connection.notificationHub;
 
        // Declare a function on the hub so the server can invoke it         
        hub.client.notify = function (message) {
            $('.notification-message').html(message);
        };
         
        // Start the connection
        $.connection.hub.start();
    });
</script>

As you can see, we are starting a connection between hub client and server and defining client methods which server can invoke. In this case, we have defined only one client method named notify. If we go back to the server implementation of our hub, you can see SendNotification method doesn’t return any result, but there is one interesting piece of code: Clients.All.notify(message). This instructs server to call notify method on all connected clients. Notify method is not implemented in the server code, SignalR will use this method signature to find function to call on clients.
The last piece of the puzzle is contained within the onclick handler for the send button. We are calling a server method sendNotification and passing the message we're going to send to our users. As you can see, this method is named exactly like our server hub method except for the first letter which is not uppercased. This is SignalR convention that defines how server methods are exposed on the client proxy. All server-side methods are created automatically by SignalR and their implementation can be found inside hubs script.
That’s basically everything, we can now send notifications to all active users. The code is very simple and all the hard work of opening and keeping connections with clients is handled by the lovely SignalR framework.

You can pickup source code on github.

Rated 5.00, 3 vote(s).