Friday, July 26, 2013

Create a SignalR Chat Module for Kooboo CMS


This is my attempt at getting the classic SignalR chat demo working inside a Kooboo CMS Module. The point of this module is a proof of concept to see how a fairly complex module is set up since the SignalR routes for the hubs need to be registered properly for the demo to work and there is no controller or easy route to set up in order to get this working.


You will need Visual Studio (2010 or 2012) installed with the most up to date version of the .NET Framework and ASP.NET MVC. If you haven't already please follow the Kooboo CMS Installation Guide to download the latest version of the code and install the templates for Visual Studio.

Getting things set up

Open Visual Studio and start a new project using the "Kooboo.CMS.ModuleArea" template you installed, you can find it under Templates->Visual C#->Web. Choose whatever name you'd like, I'm calling mine "ChatModule", as well as the usual options when starting a project and click OK. After your project is created and initialized run a build (press F6) before changing anything. When I do this I see 4 errors in the "~/Areas/SampleModule/ModuleAction.cs" file so let's open that up first to fix these. The errors are just references that can't be resolved so prefix "Sites.Models.Site site" with "Kooboo.CMS" to end up with "Kooboo.CMS.Sites.Models.Site site". Try your build again (F6) and then proceed with dealing with the same reference problems in the next file "~/Areas/Empty/ModuleAction.cs". Let's try building one more time and this time it should succeed, hopefully these errors are fixed in a future version of the template.

Adding SignalR to your project

Now that the project builds we need to add in support for SignalR. Go to Tools->Library Package Manager->Manage NuGet Packages for Solution... Search for "SignalR" and you should find "Microsoft ASP.NET SignalR" then click the install button. If you want to skip all that just open up the Package Manager Console and type in: "PM> Install-Package Microsoft.AspNet.SignalR"

Customizing your Module

Let's customize the Module a little, pick a name for your module keeping in mind once it's published and installed in the CMS it can't be changed. I will use "ChatModule" for this example, open up the Areas folder in solution explorer and rename "SampleModule" to "ChatModule". Next open up the "ModuleAreaRegistration.cs" file in the newly renamed folder and replace "SampleModule" with "ChatModule" (there's a variable and also a namespace reference in here). From past experience I already know there are a few references left in the code to "SampleModule" and that it's safe to do a simple find and replace on all of them. Run a Replace in Files (Ctrl+Shift+H) and replace all instances of "SampleModule" with "ChatModule", in my case I found and replaced 10 instances. You should be able to do a Build at this point and see that everything is still OK.

Coding the Chat Module

Server Side

To save some time I won't go through cleaning up the existing files, you can safely get rid of some of the sample Controllers, Models, Views etc. when creating your own module but you should leave the Admin related code there. If you're just getting started with Kooboo then it's probably safer to just leave the existing code as is until you're more familiar with it. We will need a class that derives from the SignalR Hub so add a new class to your ChatModule folder, I'll call mine "Chat.cs". The code itself is very simple you just need to inherit from Hub and implement a Send method:
using Microsoft.AspNet.SignalR;

namespace ChatModule.Areas.ChatModule
 public class Chat : Hub
  public void Send(string name, string message)
   Clients.All.addMessage(name, message);
If you were following along with the quick start at this point you would add the call to register the SignalR Hubs to your Global.asax, this won't work for your Kooboo Module though so you need to create a new class that will take advantage of the Dependency Injection in Kooboo so you can register the routes when the Application starts up. I'm calling my class "SignalRConfig.cs" and this is also added to the ChatModule folder:
using Kooboo.CMS.Common.Runtime;
using Kooboo.CMS.Common.Runtime.Dependency;
using Kooboo.Collections;
using Kooboo.Web.Mvc;
using System;
using System.Web.Mvc;
using System.Web.Routing;

namespace Kooboo.CMS.Web
 [Dependency(typeof(Kooboo.CMS.Common.IHttpApplicationEvents), Key = "SignalRConfig", Order = -1)]
 public class SignalRConfig : Kooboo.CMS.Common.HttpApplicationEvents
  public override void Application_Start(object sender, EventArgs e)

   base.Application_Start(sender, e);
In order to make sure the SignalR routes aren't overridden you need to add an ignore rule to the "routes.config" file in your Module:
    <add name="signalr" url="signalr/{*pathInfo}"/>
Next Add a new Empty controller in your ChatModule, I'll call mine "ChatController" with just one method for Index that returns the default View:
using System.Web.Mvc;

namespace ChatModule.Areas.ChatModule.Controllers
    public class ChatController : Controller
        // GET: /ChatModule/Chat/
        public ActionResult Index()
            return View();


Client Side

Now we need the actual View so right click on "View" in the Index ActionResult and select "Add View..." I will use the Front.cshtml layout page that's in my ChatModule's Shared views. You will get a default Index.cshtml file, I'm going to just paste in some demo code from the SignalR quick start guide with a few minor changes:
    ViewBag.Title = "Chat Demo";
    Layout = "~/Areas/ChatModule/Views/Shared/Front.cshtml";

<h2>SignalR Chat</h2>
<div id="signalr-chat">
    <script src="~/Scripts/jquery.signalR-1.1.2.min.js" type="text/javascript"></script>
    <script src="@Url.Content("~/signalr/hubs")" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            // Proxy created on the fly
            var chat = $;

            // Declare a function on the chat hub so the server can invoke it
            chat.client.addMessage = function (name, message) {
                $('#messages').append('<li><strong>' + name + '</strong>: ' + message + '</li>');

            $("#msg").on('keydown', function (event) {
                // Manually bind the enter key to submit the message
                if (event.keyCode == 13) {
                    return false;

            // Get the user name and store it to prepend to messages.
            $('#displayname').val(prompt('Enter your name:', ''));
            // Set initial focus to message input box.  

            // Start the connection
            $.connection.hub.start().done(function () {
                chat.server.send($('#displayname').val(), "Has entered the chat ...");
                $("#broadcast").click(function () {
                    // Call the chat method on the server
                    chat.server.send($('#displayname').val(), $('#msg').val());

            // Detect when the connection is stopped
            $(window).bind("beforeunload", function () {
                chat.server.send($('#displayname').val(), "Has left the chat ...");
    <input id="msg" name="msg" type="text" />
    <input id="broadcast" name="broadcast" type="button" value="Send" />
    <input id="displayname" name="displayname" type="hidden" />
    <ul id="messages"></ul>
The code is pretty straight forward, you need a reference to the SignalR jquery library for the chat to work as well as the dynamically generated hub script. Before running the code open up the Project Properties and in the Web tab change the Start Action to Specific Page and leave it blank, save that change and close the properties window. In order to see the Module on a page we need to log into the Admin section and add it to a page so run the project and wait for the site to start up. Click the Login link in the top right corner and use the default admin admin credentials to log into the admin section. Click on the SampleSite and remove all the pages, once it's cleaned up click the button to add a new page. Hover over the main place holder and select the "Add a module" option. Select the ChatModule and set the Entry Controller to "Chat" you can leave the Entry Action as "Index". Set the page name, I'm using "ChatDemo" and click the Save & publish option. At this point you can log out of the admin section and close the site. When I try to run the project the SignalR routes don't get registered properly unless I do a Rebuild All before running it. If you're seeing errors related to the signalr/hubs file not loading then try doing a Clean then a Rebuild and run the project, if you just do a Build it probably won't work properly.

Source Code

If you'd like to just grab the source code yourself and start working with it it's available on GitHub: SignalR Chat Demo Source


Kooboo CMS Module Development
SignalR Quick Start
Another SignalR Tutorial

No comments:

Post a Comment