Friday, July 26, 2013

Create a SignalR Chat Module for Kooboo CMS


Summary

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.

Pre-Requisites

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)
  {
   RouteTable.Routes.MapHubs();

   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 = $.connection.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').val("");
                $('#msg').focus();
            };

            $("#msg").on('keydown', function (event) {
                // Manually bind the enter key to submit the message
                if (event.keyCode == 13) {
                    $("#broadcast").click();
                    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.  
            $('#msg').focus();

            // 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 ...");
            });
        });
    </script>
    <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>
</div>
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

References

Kooboo CMS Module Development
SignalR Quick Start
Another SignalR Tutorial

Friday, June 14, 2013

Kooboo CMS Module Creation and Development

Summary

This is a quick introduction to Module development for Kooboo CMS. I ran into a few issues while I was trying to follow the official guide so I thought I would document the process for future reference.

Pre-Requisites

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.

Create a Module

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 as well as the usual options when starting a project and click OK. After your project is created and initialized go ahead and 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 go ahead and 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. At this point you can build and run (press F5) to see the site working and play around with it if you want to familiarize yourself with it.
Let's try to customize a Module a little to see what the process is like, 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 "KBModule" for this example, open up the Areas folder in solution explorer and rename "SampleModule" to "KBModule". Next open up the "ModuleAreaRegistration.cs" file in the newly renamed folder and replace "SampleModule" with "KBModule" (there's a variable and also a namespace reference in here). If you were following along with the original instructions on the Kooboo site at this point you should be able to build and run again, the build will succeed but running is a different story. Let's try to figure out why we get a 500 internal server error while running the code.
If you take a look at the exceptions being thrown while running it's obvious that there's still references to "SampleModule" in the code, since we've renamed it we will need to track these down and replace them with "KBModule". Let's do a Find in Files (Ctrl+Shift+F) for "SampleModule" to see which files still need to be updated. You should find 8 matches in 7 files so go ahead and replace all instances of "SampleModule" with "KBModule". I find it's always a good idea to go in and look at the code instead of simply replacing all automatically to help understand the code and also make sure you're not changing something you shouldn't. In this instance however it's safe to go ahead and just run a Replace in Files (Ctrl+Shift+H). Once you're done you should be able to build and run the code again without any problems.

Testing the Module

Let's build and run the code now, hit F5 and after the site starts up click on the LogOn link in the top right corner. Use the default credentials Username:admin Password:admin and change the Redirect to: Admin page then click Login. Click the SampleSite link in the main area to open it up so you can edit and change settings. If you open up the Articles page for editing (click the right arrow to see the menu) and check the Module it's using it should already be set to KBModule in the 2 place holders. At this point you should check all the settings for the controller (Article) and action (Categories for the menu, List for the main area) used in order to figure out where you can play around to make changes and see them on the sample site.

Breaking down the pieces

Back-end (Admin) Controllers and Views

There are two sample back-end controllers included in the project template:
"AdminController.cs", which has two methods: InitializeModule and GenerateModuleInfo.
InitializeModule is used for exactly what it sounds like, after adding the module to Kooboo if you need to do any kind of initialization before using it here's where you'll add the code. Since the module can be used on multiple sites it's advised to do the initialization here rather than during the installation process. I would also recommend writing your code to ensure it can be run multiple times without any adverse affects. An example would be creating/modifying/populating a table in a database that is used by the Module.
GenerateModuleInfo is used to generate the "module.config" file which is the ModuleInfo Class serialized.
"NewsAdminController.cs", is just a sample controller to demonstrate how to create custom data management instead of using the general content management.
The Views for each of these controllers are located under the usual Views folder in the Admin and NewsAdmin folders.

Back-end (Admin) Menu

The back-end Module menu can be integrated into the Kooboo CMS main menu, to customize it edit the "Menu.config" file. The default items are "Settings", "Initialize" and "News", it's good to note that the permission is also set in this file using the "role" attribute.

Back-end (Admin) Routing

The back-end URL routes are added to the "ModuleAreaRegistration.cs" file which is the same as MVC Areas if you're already familiar with them.

Front-end Controllers and Views

There are two sample front-end controllers included in the project template: "ArticleController.cs", which inherits from ModuleControllerBase and "NewsController.cs", which inherits from Controller
The front-end controllers run on Kooboo CMS Page positions rather than MVC area so they cannot inherit from "AreaController", you can use either "ModuleControllerBase" or the generic "Controller". The difference between the two is "ModuleControllerBase" adds a couple flags and methods that are useful for Module development, if you're starting from scratch then inherit from this class although it's not necessary if you're trying to create a module from an existing codebase.
When you add a module to a Page Position you will have to specify the front-end controller in the entry controller and a method in the entry action. You can also specify this using the admin interface for the module after adding it to your site by changing the default settings. Another option is to specify these in the module.config that is generated from the GenerateModuleInfo method in the Admin Controller.
You can't use the regular Master layout because the module view is only rendered as a piece of the HTML page and it won't be validated. There are a couple helper methods "Html.FrontHtml()" and "Url.FrontUrl" you can use in your front-end views only if you have the necessary access and knowledge of the target site. Otherwise it's recommended to use "Html.ModuleHtml()" and "Url.ModuleUrl()". Take a look at the class "ModuleViewHelperExtension" to see the rest of the methods you can take advantage of (ModuleAjax, AjaxHelper, ModuleHtml, HtmlHelper and UrlHelper).

Front-end Routing

To add or modify the routing in the front-end open up the "routes.config" file. For anyone who's already worked with ASP.Net MVC before this should look pretty familiar. If you need more information on working with this file just use any existing samples you can find for a regular ASP.Net MVC project, there's more than enough information and samples available online.

Publishing a Module

Let's save publishing and using the module in Kooboo for it's own article.

References:

http://www.kooboo.com/docs/Kooboo-CMS/Module-development

Monday, June 3, 2013

Kooboo CMS Installation Guide

Summary

I recently started evaluating Kooboo for potential use where I work to replace our existing CMS. We do a lot of website development in MVC.Net so Kooboo seemed like a good fit for our environment and existing skill set. A lot of the documentation and examples they currently have are a little hard to follow and I found just getting the code and opening it in Visual Studio using their instructions was a bit difficult so here's the easiest way to get started.

Installing Kooboo the easy way

If you're trying to get started with Kooboo CMS here is the easiest way to download and install it with all of it's dependencies:
  1. Download and install the latest version of WebMatrix (http://www.microsoft.com/web/webmatrix/).
  2. After installation is complete open WebMatrix and select "New" -> "App Gallery".
  3. Select the CMS category on the left-hand side or just type in Kooboo in the search input at the top.
  4. Find Kooboo CMS in the list, select it, enter a site name in the input at the bottom and press Next.
  5. You'll have to agree to the EULA to start the download and install.
  6. Once it's finished you will see the source code in WebMatrix and it should start the Kooboo website in your default browser.
  7. You can now log in using the default UserName: admin and Password: admin.

Now that you have the code and a working installation of Kooboo CMS you'll probably want to open it up in Visual Studio:
  1. In WebMatrix right click on the root of the website and select "Show in File Explorer".
  2. Start Visual Studio and select "File" -> "Open Web Site..." or (Shift + Alt + O).
  3. Copy and paste the path from File Explorer or navigate to it and click the Open button.
  4. You can now build and run the website from within Visual Studio.

Note: The current version as of writing this has an error which will come up when you try to build and run from Visual Studio:

'Kooboo.CMS.Web.Areas.Sites.Models.PagePublishViewModel' does not contain a definition for 'FullName' and no extension method 'FullName' accepting a first argument of type 'Kooboo.CMS.Web.Areas.Sites.Models.PagePublishViewModel' could be found (are you missing a using directive or an assembly reference?)

You can safely delete or comment out the offending code in "~/Areas/Sites/Views/Page/Publish.cshml" and continue:

@{
    var page = new Kooboo.CMS.Sites.Models.Page(Kooboo.CMS.Sites.Models.Site.Current,Model.FullName);
}
@if (ServiceFactory.PageManager.HasDraft(page))
{
    @Html.EditorFor(m => m.PublishDraft, new { @class = "medium draft" })
}


Now you can head over the to download page on Kooboo.CodePlex.com to get the Visual Studio templates for Modules (Kooboo.CMS.ModuleArea.vsi) and Plug-Ins (Kooboo.CMS.PluginTemplate.vsi).

References

http://www.kooboo.com/docs/Kooboo-CMS/Installation-guide-1
http://kooboo.codeplex.com/
http://www.microsoft.com/web/gallery/kooboocms.aspx
http://www.iis.net/learn/develop/installingpublishing-apps-with-webmatrix/kooboo-cms-faq