Live search for Umbraco frontend – using AngularJs and json content api

Standard

Everyone loves instant / live search, where a preview of the contents show up instantly as you write, right?

I wrote about an approach to create such a search quite a while ago using Examine. Now I like to write about an experimental, but working, approach that is faster than Examine and at the same time use a little bit of AngularJs.

Now – how is it even possible to be faster than Examine? Okay I cheat, I move the search to the client side, and get rid of the server call for each keypress / set of keypresses. Bad choice for sites with a fair amount of content? Well, if we take the Umbraco4 documentation as an example, last time I checked it was about 700kBs of data (in 236 markdown files). When we gzip compress that amount of text we should get about 175kBs. Which is similar in size as an ordinary – decently sized – image, and takes less than a second to download on a slow internet connection. For 236 pages of text. Let’s load that data on the initial page load, and perform the search with simple javascript functions.

For the actual search I’m going to use Umbraco 6 with the MVC CWS Starter kit , a little bit of AngularJs on the front end and a small json content api I call Tapas.

Install the mentioned packages. Then create a partial view called clientSideSearch.cshtml. Add the following code:

@inherits Umbraco.Web.Mvc.UmbracoTemplatePage

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script>
<script src="/scripts/clientsearch.js"></script><!-- scripts placed in partialview for simplicity -->

<div ng-app="liveSearchModule" ng-controller="SearchCtrl">

    <h1>Live search</h1>
    <input id="searchText" type="search" placeholder="live search..." ng-model="searchText" />

    <ul ng-if="searchText">
        <li ng-repeat="child in children | filter:searchText | limitTo: 10">
            <a href="{{child.NiceUrl}}">{{child.Name}}</a>
            <div ng-bind-html-unsafe="child.Properties.bodyText"></div>
        </li>
    </ul>
</div>

A few notes about the code. The Angular module and controller sets the scope in our html view. Then we use Angular built in directives ng-if and ng-repeat to filter the search results. Lastly we use Angular templating and the scoped objects to display the content, name, url and bodytext. The ng-bind-html-unsafe directive tells Angular to render the content as is, without encoding the html (as Html.Raw in Razor).

The “children” objects are returned by Tapas with a straight forward format shown in the docs for Tapas.

Add the render instruction inside your search view, “CWS-Search.cshtml” for example:

@Html.Partial("clientSideSearch")

Next create the /scripts/clientsearch.js script:

angular.module('liveSearchModule', [])
  .controller('SearchCtrl', function ($scope,$http) {
      $scope.children = $http.get('/umbraco/publishedcontent/nodes/getchildren?path=/'); // get all children from the root document
  });

This controller makes an ajax request (similar to $.getJSON / $.ajax) initially to get content from the content api, in this example all immediate children under root (path=”/”). The request returns a “promise” = an async result. Angular handles that automatically, and we do not need to figure out a way to render the content after the async is finished. The controller does not have any other functionality than to get data on initialization, later on the actual search is performed on the data in $scope.children.

And thats it!

livesearch

Enter one or more letters in the search box to see the articles with bodytext below. If you like to format the document differently simply change the template. Limit number of search items if you wish. If you like to extend this with pager and change to a server side based service it’s fairly easy aswell. Also we might want to search through the entire tree. If there’s interest I’ll write a follow up later on.

The right amount of separation of concerns in Umbraco Razor?

Standard

We hear it’s a good thing to separate view code from logic, and also to separate code into controller, model and view files. What does that actually mean? And why is that a good thing? Also does this mean we need to create model and controller class files for all our Umbraco Razor scripts?

Consider a plain read-only, HTML rendering razor script with a good amount of HTML, over a page long. Nothing unusual and it works perfectly fine as it is:

The code in this post is for Umbraco MVC (4.10+), but it’s concepts apply to all versions of Umbraco.

<...lots of tags above this point...>
<div class="widget">
    <h4>Recent Posts</h4>
    <ul>
        @foreach (var blogPost in Umbraco.TypedContent(1068)
            .Children().Where(t=>t.IsVisible()).OrderByDescending(t => t.CreateDate).Take(10))
        {
            <li><a href="@blogPost.Url">@blogPost.Name</a>
            @foreach (var item in blogPost.GetPropertyValue<string>("categories").Split(','))
                { <span>@item</span> } </li>
        }

    </ul>
</div>
<...lots of tags beneath this point...>

A few things that can be made better here as I see it:
– The recent blog posts widget can be separated from the rest of the view into a reusable partial.
– Intentions are not clear, what exactly are we trying to do with the chained methods?
– Hard coded node number 1068, what if we change that one later?
– Lot of C# mixed inside HTML makes both the HTML and the C# harder to read and problems harder to find.

I suggest:
– Separate the code into a partial / separate razor script, give it a name and or a location that both describes the type of HTML it renders aswell as the content, for example “Widgets/RecentBlogPosts.cshtml”.
– Move all C# code, but a bare minimum to the beginning of the script.
– Specify the intent with the code being used by using good names, close to what it is described as on the actual site, or in the specification to the customer.
– Stay away from hard coded node numbers.
– Use C# Linq with Lambdas together with typed content. It’s a great syntax to express Umbraco content queries.
– Use the .Select method, together with anonymous object to return exactly what you need, i.e. arrays and objects with only simple types. This will help you make clear what you need and will show you possible problems early.

Main cshtml:

<...lots of tags above this point...>
@Html.Partial("Widgets/RecentBlogPosts")
<...lots of tags beneath this point...>

Partials/Widgets/RecentBlogPosts.cshtml:

@{
  var blogPostsRootNode = Model.Content.AncestorOrSelf(1);
  var recentBlogPosts = blogPostsRootNode.Children
    .Where(t=>t.IsVisible())
    .OrderByDescending(t => t.CreateDate)
    .Take(10)
    .Select(p => new
    {
      p.Url, 
      p.Name, 
      Categories = 
        (p.GetPropertyValue<string>("categories") ?? "")
          .Split(',')
    });
}
<div class="widget">
    <h4>Recent Posts</h4>
    <ul>
        @foreach (var blogPost in recentBlogPosts)
        {                                                            
            <li><a href="@blogPost.Url">@blogPost.Name</a>
            @foreach (var category in blogPost.Categories)
            { <span>@category</span> } </li>
        }
    </ul>
</div>

What about separate model, view and controller classes?
The C# part of the script is building a ViewModel and, as such, could be placed in a C# model file, which in turn could be instantiated from the controller file firing up the view file.

We certainly could. And we could create a strongly typed view, and unit test the controller and the model. But would it really help us for this kinds of scripts that only show content – and does not deal with posted data?

I don’t think so. I found the approach described in this blog post be good amount of separation of concerns for views like this, I would very much like to hear experiences / opinions / examples from you, dear reader!

Happy coding

Nice and simple Razor templates with the help of RenderPage and some dynamic sugar

Standard

Besides saving global helpers in App_Code we have the option to use RenderPage (or Html.Partial) in Razor to reuse code globally.

Both ways helps in making the HTML code DRY and well structured. But an important difference is a RenderPage file can be wherever we want, and changes are fluent (no app restarts). We do loose strongly typed parameters but I think that is a small price to pay when we are doing Html functions. We can still send a typed viewmodel to the rendered page. What about performance? As far as I understand we will get a performance hit the first time we call the page after a save (generally much quicker than a app restart tho). But after that it’s on par with a global helper. Correct me if I’m wrong.

This is the basic syntax :

@RenderPage("/path/to/SomeTypedView.cshtml",someObject)

And in the SomeTypedView.cshtml :

@{var viewModel = (SomeType)PageData[0]; // mimic strongly typed view}
<div="phew">@viewModel.Name</div>

But the RenderPage-code is rather ugly. Let’s make a small global helper to make the syntax nicer:
/App_Code/Tmpl.cshtml:

@helper Display(object value, string templateName="") {
    if (templateName=="") {
        templateName = value.GetType().Name;
    }
    @PageContext.Page.RenderPage("~/Shared/DisplayTemplates/" + templateName + ".cshtml",value)    
}

It’s using a defined path. And it also checks the type name if we do not specify it. So the two following instructions makes the same result:

@{var myObj = new MyType();}
@Tmpl.Display(myObj,"MyType")
@Tmpl.Display(myObj)

They both renders /Shared/DisplayTemplates/MyType.cshtml

Introducing RazorTemplates

Can we extend this further, using dynamics to write:

@tmpl.MyTemplateName(someModel)

…as a way to render the /DisplayTemplates/MyTemplateName.cshtml with someModel ?

Yes we can, check out DynamicHtmlTemplates in this gist, [Update: or the Umbraco RazorTemplates package which is basically the same, but evolved a little bit to an Umbraco context - also automatically picking up NodeTypeAlias to render file according to document type.]

Put DynamicHtmlTemplates in your App_Code and you can use:

DynamicRender

Cool eh?

@using DynamicHtmlTemplates
@{
 var myobj = new MyClass{Name="Someone", Value="123"};   
 dynamic tmpl = new Templates();
 // or dynamic tmpl = new Templates("~/Path/ToTemplates/");
 // or dynamic tmpl = new Templates("SubPathToTemplates");
}
        
Rendering /DisplayTemplates/MyClass.cshtml (sending myobj to PageData[0])
@tmpl.Display(myobj)

Rendering /DisplayTemplates/MyClassAlternative.cshtml  (sending myobj to PageData[0])
@tmpl.Display(myobj, "MyClassAlternative")
        
... or let it use Dynamic to figure out the template name:
Rendering /DisplayTemplates/MyClassAlternative.cshtml  (sending myobj to PageData[0])
@tmpl.MyClass(myobj)

Rendering /DisplayTemplates/MyClassAlternative.cshtml  (sending myobj to PageData[0])
@tmpl.MyClassAlternative(myobj)
        
Rendering /DisplayTemplates/Possible.cshtml (sending inline razor item template to PageData[0] and list to PageData[1])
@tmpl.Possible(Templates.ItemTemplate(@<text>this is @item</text>),new List<string>{"one","two"})

Contents of /DisplayTemlpate/Possible.cshtml:        
<div>
    @foreach(var item in PageData[1]) {
        @PageData[0](item)
    }
</div>

So with this, a bootstrap form can be created in a much more DRY way:
bootstrap

Tested in Umbraco 4.71 and Umbraco 6.02 as well as a vanilla WebPages site

Fun stuff : node.js in an Umbraco site

Standard

Did you ever want to run node.js within your umbraco site, and edit the server side javascript from within your Umbraco backend? Not? Well, it’s still a fun thing to do, don’t you think?

Update 1: I actually think nodejs makes some sense within Umbraco. Why? Well, for example it makes it possible for js-peeps to stay js. And node has a _lot_ of nice plugins (as for example jade and express).

Update 2: I made a first version of a sample of Umbraco running with ExpressJs and Jade, it uses Tapas that serves published content for requested url.

The setup only takes a few minutes to do:

  1. Install NodeJs and IISNode on your computer / server
  2. Install an Umbraco site or use an existing, using WebMatrix
  3. Add the NPM plugin from WebMatrix Gallery
  4. Add the folders iisnode and node_modules for the NPM plugin to show up in the toolbar (and restart WebMatrix)
  5. Add the Express Node module with the help of NPM. It puts the module in a new folder in your root “node_modules”
  6. Add the following lines to your web.config, in the configuration section (at the bottom for example):
...
    <location path="scripts/node">
        <system.webServer>
            <handlers>
                <add name="iisnode" path="server.js" verb="*" modules="iisnode" />
            </handlers>

            <rewrite>
                <rules>
                    <rule name="express">
                        <match url="/*" />
                        <action type="Rewrite" url="/scripts/node/server.js" />
                    </rule>
                </rules>
            </rewrite>

        </system.webServer>

    </location>
</configuration
  • Add a new .js file and save it as /scripts/node/server.js
  • var express = require('express');
    
    var app = express.createServer();
    
    app.get('/scripts/node/hello/:name', function (req, res) {
        
    	
    	res.send('Hello ' + req.params.name + ' from node! [express sample]');
    	
    	
    });
    
    app.listen(process.env.PORT);
    

    That’s it! Now you should be able to surf to /scripts/node/hello/world and you should get “Hello world from node!” back.

    Update 2: What about Umbraco content?

    What if we like to do something a little bit more useful – make it possible to get and edit content? Well, our node application does not have the Umbraco contents available, so we need to get it in some other way : I guess http is the standard.

    Currently (in Umbraco 6.0) there is no available Restful Api out of the box (it will be added in 6.1 afaiu). However, the uRest package by Matt Brailsford seems to play nicely with u6 (edit : perhaps not, I could not get it to accept posts). Add that, and then change server.js and add a urest.js file as in this gist to get contents with internal http requests.

    app.get('/scripts/node/urest/documents/:id',function(req,res){
        var documentId = req.params.id;
        requestGetWithToken("/documents/" + documentId, function (response) {
            // just return the content to the response string:
            res.send(response);
        });
    });

    Now you can browse to the url /scripts/node/documents/{nnnn} to get a particular document.

    Check out the uRest documentation for information about how to create and edit content.

    Update 3: content straight from umbraco context with the help of EdgeJs

    I just managed to get actual content directly from umbraco context into nodejs with the help of the brilliant EdgeJs https://github.com/tjanczuk/edge by Tomasz Janczuk and https://github.com/sitereactor/umbraco-console-example by Morten Christensen.

    I will blog more details about it, but what I needed to do was this:
    1. Add Edge with the help of NPM.
    2. Create a class libary dll that fires up the Umbraco context (copied from Umbraco console example), with functions returning async Task

    public async Task<object> ListNodes(object input)
    {
      return "nodes: " + listNodes();
    }
    

    3. Setup functions inside my node app calling the .net functions

    var express = require('express');
    var edge = require('edge');
    var app = express.createServer();
    var listNodes = edge.func({
        assemblyFile: 'C:/harcodedpath-to-my-website/bin/umbracocontext.dll',
        typeName: 'UmbracoContext.Startup',
        methodName: 'ListNodes'
    }); 
     
    app.get('/scripts/node/hello', function (req, res) {         
        listNodes("",function(error,data){
            res.send(data);        
        })
    });
    app.listen(process.env.PORT);

    4. Add a node.exe.config into my node.exe folder with just a connectionstring to begin with:

    <?xml version="1.0" ?>
    <configuration>
        <connectionStrings>
            <remove name="umbracoDbDSN" />
            <add name="umbracoDbDSN"
                 connectionString="Datasource=C:\harcodedpath-to-my-website\App_Data\Umbraco.sdf"
                 providerName="System.Data.SqlServerCe.4.0" />
        </connectionStrings>
    </configuration>
    

    It’s obviously not ideal to set the connectionstring in the global node.exe folder. I think a good workaround to get local connectionstrings is to copy the node.exe to a folder within the site and set the iisnode handler to use the local node.exe instead.

    <iisnode
          nodeProcessCommandLine="&quot;c:\harcodedpath-to-my-website\nodejs\node.exe&quot;" 
    

    Edge does not make it possible (yet) to use the already existing instance of the asp.net application (share memory), so if we run umbraco in asp.net and node in parallell we will have two context instances.

    If you are concerned about the performance: read this.

    GetTreeById

    app.get('/scripts/node/getTreeById/:nodeId', function (req, res) {  
        getTreeById(Number(req.params.nodeId),function(error,data){
            res.send(data);        
        })
    });
    public async Task<object> GetTreeById(int nodeId)
    {
        var node = contentService.GetById(nodeId);
        return nodeToDictionary(node, true);
    
    }
    private Dictionary<string, object> nodeToDictionary(IContent content, bool includeChildren)
    {
        var nodeData = new Dictionary<string, object>();
        nodeData["Name"] = content.Name;
        nodeData["Id"] = content.Id;
                
        content.Properties.ForEach(p => { nodeData[p.Alias] = p.Value.ToString(); });
        if (includeChildren)
            nodeData["Children"] = content.Children().Select(child => nodeToDictionary(child, true)).ToList();
        return nodeData;
    }
    

    tree

    A require module pattern in Asp.Net Razor

    Standard

    Did you ever need to load modules dynamically in Razor? Do you like to write function libraries in pure Razor, and be able to use them from other files without placing that function libraries in App_Code, and without forcing the App to restart?

    Not? Oh, well, anyways – as a friday evening experiment I hacked together a Razor Require Module sample which worked out pretty good.

    I do recommend the regular way to add functionality, in .cs-files. I use Razor mostly as a pure View engine, with no logic other than view logic.

    But Razor can also be a really fun playground to test some ideas in, and with this I can temporarily add functions to for example an Umbraco site directly from within the online Umbraco UI.

    Also – the AppPool will restart after a certain number of “recompiles”, which kind of defeats the purpose with all this.

    Edit : Roslyn will probably be a better suit for this, see David Ebbo’s post. I wrote an experiment with Roslyn as a server scripting tool.

    Here’s the usage:

    Create a module, SomeModule.cshtml:

    @Require.Define("SomeModule", (module) =>
    {
        module.Exclaim = new Func<string, string>((message) => { 
        
            return message + "!"; 
        
        });
    
        module.AddToDatabase = new Func<dynamic, int>((newrecord)=>{
            
            // some code to add the newrecord to the database        
            // return the created id
    
            return 0;
        
        });
        
    });

    The code is using lambda syntax to add functions to the module. The module name is defined with a string.

    Later you use the module this way:

    @Require.File("~/SomeModule.cshtml")
    
    @{    
        var newId = App.SomeModule.AddToDatabase(new { name = "foo", info = "bar" });    
    }
    
    <p>New database item added with ID : @newId</p>

    The Require.File function checks if SomeModule has been defined already. If not it will define it and add the code dynamically by loading the SomeModule.cshtml.

    Each module is an ExpandoObject, which is added to the global App ExpandoObject. That’s why we use it with “App.ModuleName”.

    The Require code needed for this is only a few lines of code in the file Require.Cshtml in App_Code:

    @helper File(string fileName) {
    
        var p = (WebPage)WebPageBase.CreateInstanceFromVirtualPath(fileName);
        var ctx = new WebPageContext(new HttpContextWrapper(HttpContext.Current), p, null);
        p.ExecutePageHierarchy(ctx, new StringWriter());
    
    }
    @helper Define(string moduleName, Action<dynamic> definitions, bool alwaysRedefine = false) {
        if (alwaysRedefine || App[moduleName] == null)
        {
            App[moduleName] = new System.Dynamic.ExpandoObject();
            definitions.Invoke(App[moduleName]);
        }
    }

    If you like to add a function to an already loaded module it’s possible to do so. You need to add a parameter to the define to make it redefine the module even if its already defined:

    @Require.Define("OtherModule", (module) =>
    {
        @* 
           ...  Existing code ...
        *@
    
        module.NewFunction = new Func<string>(()=>{
            return "result";
        });
        
    }, true);

    A module can require other modules. And, you add modules and their functions dynamically without the need for App restarts.

    I got the final piece to this puzzle to this code from this gist by Niels Kühnel: dynamically render a razor file http://pastebin.com/fjXPnzAw, thanks Niels.

    Using Require in Umbraco
    I do most my coding in Visual Studio, nothing beats it. But I also like to be able to log into an online site and make a few additions to a running (small, not client) site, just when I have five minutes over from wherever I am. And with the Umbraco UI I can do that. However, until now I haven been able to re-use code easily.

    Tip: Change two settings in web.config to be able to run files from within the api folder directly (“http://mysite.com/macroscripts/api/demo&#8221;):

    <appSettings>
    ...
        <add key="umbracoReservedPaths" value="~/umbraco,~/install/,~/macroscripts/api/" />
    ...
        <add key="webpages:Enabled" value="true" />
    ...
    

    Simple client side routes and content loading in Umbraco

    Standard

    Do you like your users to be able to load subcontent on a page dynamically and support client side url’s (which in turn enables browser history, url-copy&pasting and bookmarks)? In this post I will show how you can do it in a very flexible way with the help of Backbone.js and a minimum of code.

    This is what I’m trying to achieve, I have an ordinary page with links to “sub content”, which is supposed to appear on the same page when the user clicks on a link:

    When the user clicks “sub content 2″ the url becomes some-page#subcontent-2 and the corresponding content shows:

    To use “client side routes” we need to add some library that handles such. The most commonly used one is probably Backbone.js.

    To use it you will need to add script reference to Backbone.js and to Underscore.js which it has as a dependency.

    Download the files or add reference to CDN-paths, for example:

    http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js
    
    http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js

    Defining our routes and load the asked for content.

    A client side route url part is everything in the url that comes after a hash, i.e. “/some-post#myview/whatever” => “myview/whatever”.

    Backbone is using a straight forward syntax to setup routes, where every route has a url matching route string and a function to call. It handles parameter url parts aswell. The syntax to use a parameter is adding a colon before its name i.e. “myview/:id”

    In our case we’ll use “:urlName” to match every url (“#subcontent-1″ and “#subcontent-2″) and pass the url string as the parameter urlName to the route function subContentsRoute.

    The subContentsRoute route function does only one thing : it loads the html content and puts it in the #subcontents div. It’s simply using a fixed url part + the urlName parameter value (i.e. “/some-post/subcontents-2″).

    var SubContentRouter = Backbone.Router.extend({
            routes: {
    		":urlName" : "subContentsRoute",
               	"*actions": "defaultRoute" // matches http://example.com/#anything-here
            	},
            subContentsRoute: function(urlName) {
    		$.get("/some-post/" + urlName, function(data){
    			$("#subcontents").html(data);
    		});
    	},
            defaultRoute: function( actions ){
                this.subContentsRoute('subcontent-1');
            }
        });
    
    $(function(){
        var app_router = new SubContentRouter;
        // Start Backbone history a neccesary step for bookmarkable URL's
    	Backbone.history.start();
    });

    Save it as subcontentBackboneApp.js and add a script reference into the html template :

    <script type="text/javascript" src="/scripts/subcontentBackboneApp.js"></script>

    The rest is common Umbraco usage – create documenttype, template, content and a small macro

    How to make /some-post/subcontent-2 return the right content html? Let’s setup Umbraco with a simple document type with only bodyText as a richtext property, and a template that only returns the html we like to add into our div tag.

    With a document and a template in place we add our documents:

    Lastly we need to create those client side links and add a container for our dynamic content. We do that by adding this macro code in the original textpage template:

          <umbraco:Macro runat="server" language="cshtml">
          @foreach(var child in Model.Children)
    	     {
    	        <a href="#@child.UrlName">@child.Name</a> 
    	     }
    	  <div id="subcontents"></div>

    Can I haz images and macros?
    Our subcontent can be anything, styles, tags, images. But if you use a macro, the macro context will be the subcontent node and not the containing node.

    Flexibility
    I find this simple approach with a router to be suitable for several similar usages to what I’m showing in this example.
    * Loading “more content”,
    * Loading “next sub article”,
    * Being the base for a small single page application within an Umbraco site

    Sample with Backbone model and view

    $(function(){
    
    	var subContentModel = new Backbone.Model({
    		htmlContent:""
    	});
    	
    	var SubContentView = Backbone.View.extend({
    		initialize : function () {
    			this.model.on("change",function () {
    				this.render();
    			}, this);
    		},
    		render : function() {
    			this.$el.html(this.model.get("htmlContent"));
    			return this;
    		}});
    
    	var subContentView = new SubContentView({
    		model: subContentModel, 
    		el:'#subcontents',
    		});
    	
    	var SubContentRouter = Backbone.Router.extend({
            routes: {
    			":urlName" : "subcontents",
                "*actions": "defaultRoute" 
            },
    		subcontents: function(urlName) {
    			$.get("/some-post/" + urlName, function(data){
    				subContentModel.set({htmlContent:data});
    			});
    		},
            defaultRoute: function( actions ){
                this.subcontents('subcontent-1');
            }
        });
    	
    	
    	var subContentRouter = new SubContentRouter;
    	Backbone.history.start();
    
    });

    Live notifications on your Umbraco site using SignalR

    Standard

    Using the SignalR library it’s possible to push notifications from the server to the clients. In this post I’m going to show how you can publish notifications about newly published documents to a site front page.


    For this to happen we need to add four pieces of code:

    1. A SignalR Hub that transports messages between server and client.
    2. An Umbraco event handler that sends message on document publish.
    3. A function that takes necessary information from the document and creates a sendable object.
    4. A client side script that activates SignalR and handles the message from the server.

    I use the terms Document and Node in the same way as the objects are named within Umbraco. The Document is the editable content object, and it has the event we listen to, but to get the properties we use the cached representation of the document = the Node.

    1. The SignalR Hub does not have any additional functionality except for what is built in, so our code is an empty Hub class declaration:

    public class NodePublishingHub:Hub
    {
    }

    2. The after document publish event handler sends a subset of node properties through the SignalR hub to the client:

    public class PublishEventsToHub : ApplicationBase
    {
        public PublishEventsToHub()
        {
            Document.AfterPublish += Document_AfterPublish;
        }
        void Document_AfterPublish(Document sender, umbraco.cms.businesslogic.PublishEventArgs e)
        {            
            var context = GlobalHost.ConnectionManager.GetHubContext<NodePublishingHub>();
            // we need to explicitly update the document cache
            umbraco.library.UpdateDocumentCache(sender.Id);
            context.Clients.NodePublished(GetNode(sender.Id,false));
        }
    }
    

    3. The node subset function takes a node and returns only the necessary data (I don’t know if there are any built in functions that already does this). We return it as an object. The Hub will convert it to Json automatically for us.

    public object GetNode(int nodeId, bool includeChildren)
    {
        var node = new umbraco.NodeFactory.Node(nodeId);        
        return new
        {
            node.Name,
            node.UrlName,
            node.NodeTypeAlias,
            node.CreatorName,
            Properties = node.PropertiesAsList.Select(p => new { p.Alias, p.Value }).ToDictionary(k => k.Alias, k => k.Value),
            node.CreateDate,
            node.UpdateDate,
            node.SortOrder,
            node.Url,
            ParentId = (node.Parent != null) ? node.Parent.Id : -1,
            ChildIds = node.ChildrenAsList.Select(n => n.Id),
            children = includeChildren ? node.ChildrenAsList.Select(n => GetNode(n.Id, true)) : null
        };
    }
    

    4. The client side function will initiate SignalR and add the nodePublished function to our client side part of the hub. The function will prepend node information to a ul/li for us (nodepublisher.js):

    $(function () {
          // Proxy created on the fly
          var nodePublishingHub = $.connection.nodePublishingHub;
          
          // Declare a function on the chat hub so the server can invoke it
          nodePublishingHub.nodePublished = function(node) {		  
             var updateDate = node.UpdateDate.replace('T', ' '); // quick and dirty format date + time		  
             $('#nodePublished').prepend('<li><a href="' + node.Url + '">' + node.Name + '</a>&nbsp;' + updateDate + '</li>');
          };
                
          // Start the connection
          $.connection.hub.start();
      });

    The Template Html is the Umbraco starter kit with the following additions:

    <script type="text/javascript" src="/scripts/jquery-1.6.4.min.js"></script>
    <script type="text/javascript" src="/scripts/jquery.signalR-0.5.3.min.js"></script>
    <script type="text/javascript" src="/signalr/hubs"></script>
    <script type="text/javascript" src="/scripts/nodepublisher.js"></script>	
    
    <div class="hotspot">
      <h4>Newly published nodes</h4>
        <ul id="nodePublished">
        </ul>
    </div>

    Other types of notifications
    You can of course send any kind of notifications through a SignalR hub. I’m going to use it to make live updates on the front page when the site users creates registrations on a system on the site. The things necessary to add is invoking a client side function from the server side

    context.Clients.NodePublished(GetNode(sender.Id,false));

    and having the client side function on the client “part” of the hub:

    nodePublishingHub.nodePublished = function(node) {...};

    Requirements
    For this to work you need to add SignalR to your Umbraco site. And you will also need to add SignalR as a reserved path in your web.config (add key=”umbracoReservedPaths” value=”~/umbraco,~/install/,~/signalr/” ). I tested this on a fresh Umbraco 4.9 site.

    Needs to be fixed
    This is clearly just a demonstration. To make it useful on a real site one would at least need two things.
    The list with newly published pages need to have some initial contents, otherwise the list will be empty when the users arrive, and it will be emptied on page refresh. And also because we use the after publish event we will get notifications also on publish after document edits.

    Using SignalR to build an Api (in Umbraco, WebMatrix or MVC)

    Standard

    I wrote a blog post the other day about using plain Razor scripts to create an easy to maintain Api on an Umbraco site. It’s a very straight forward way to make ajax-calls possible. However in reality I think many would say razor files is just not the right choice for server functionality like this, and for bigger solutions I do agree on that.

    The Umbraco standard way would be to use /Base. And the new AspNet WebApi would be another obvious alternative for it.

    But in this post I like to discuss using SignalR as a surprisingly nice technique for common api-functionality. Yes, SignalR is not only very nice for duplex, multiuser communications. With it’s fallback support, automatic routing and javascript proxy to serverside methods I really think it’s a stable and easy to use technique also for regular ajax scenarios.

    Here are the only steps you need to go through to get a simple api up with SignalR:

    1. Reserve the path /SignalR/Hubs within Umbraco web.config umbracoReservedPaths.
    2. Install-Package SignalR in your site
    3. Create a Hub with some methods that you like to expose to the client side

    public class OrderHub : Hub
    {
      public Order Get(int id)
      {
        return WebApp.Db.SingleOrDefault<Order>(id);
      }
    }
    

    4. Reference the necessary javascripts on your page

    <...jquery...>
    <script type="text/javascript" src="/scripts/jquery.signalR-0.5.3.js"></script>
    <script type="text/javascript" src="/signalr/hubs"></script>

    5. Add signalr client scripts

    // start the connection (it's extended from $)
    $.connection.start()
    
    // get something from the server, we can use our OrderHub method names (automatically camel cased), 
    // use a callback to do something with the retrieved order
      $.connection.orderHub.get(orderId, 
        function(order){
          alert("Yay, order " + order.name + " from " + order.date);
        });
    }

    There you go, basic api-functionality with a few lines of code.

    You can send jsons from client to server aswell, and get them as your own types (Poco’s) on the server side.

    The /signalr/hubs path is a path to an automatically generated javascript file that creates a proxy to your server methods. Open up that path in your browser to check out the code.

    And when you do need chat functionality, or you like to push information from server to client, thats also easily possible, just check out the numerous SignalR samples and the docs.

    Pros

    * Easy to setup and use, no need for web.config editing or adding routes
    * The js proxy makes your javascript short and nice + it’s possible to explore the api with a javascript console, in Chrome and Firefox you even get intellisense for you callable server side methods.
    * Push and duplex communication available when you need
    * Falls back to IE6 iirc
    * Cool library
    * Great support and still under heavy development

    Cons

    * New and not that well tested, changes between each new version
    * Requires Javascript on client
    * No Rest (if that’s a requirement)
    * Limited to 6 connections at a time (user cannot have more tab’s open in his/hers browser to your application)
    * Can’t use Session in a hub (but that might be a Pro)

    Some futher comments and observations

    Its nice to have the hubs in a separate VS project “MyProject.SignalR” or “MyProject.Core”. When doing so the nuget to install in that core project would be SignalR.Server. And the full SignalR should be installed in the Umbraco web site project.

    You can get current (logged in) username in a hub with the standard call to System.Web.Security.Membership.GetUser();

    Hub’s are per request

    No need to collect all functions in one Hub, use several Hubs to separate stuff

    I don’t think you can use Umbraco context in a hub ootb. Will check that out futher on, my use case here was to build a BL api to be used in a Umbraco site, not to expose Umbraco functionality.

    Two other blog posts that talks about using SignalR for regular ajax calls:

    Clean up your MVC app with SignalR by Yngve Bakken Nilsen

    Why should ASP.NET developers consider SignalR for ALL projects? by Kevin Griffin

    A simple razor api : JSON Poco’s in Umbraco / WebMatrix

    Standard

    I’m rebuilding some ajaxy stuff on an Umbraco site using Knockout to spice up the UX. And I wanted a nice way to write my api functions. I tried several different approaches (Base, SignalR, WebApi), but in the end I got back to simple Razor scripts with a tiny twist.

    1. Reserve a /macroScripts/api/ path in web.config to make your files callable directly from their url’s + you can still edit them from within Umbraco UI if you wish. Or just use /api/.

        <add key="umbracoReservedPaths" value="~/umbraco,~/install/,~/macroScripts/api" />
    

    2. Write one file for each remote procedure to get a nice and easy to maintain structure. Use InitializePage to get rid of unnessesary whitespace. Only add minimum code to the api-files, ideally just one call.

    2. Serialize and deserialize Json to Poco’s using the Json helper.

    3. Make a little js helper to make the calls nicer.

    Here’s a sample of how a Get (/macroScripts/api/order/get/{id}) script can look like:

    @functions{
        // URL : /macroScripts/api/order/get/{id} [GET]
        protected override void InitializePage()
        {
            base.InitializePage();
            // UrlData[0] is the first url part after the path, in our case the {id}
            var orderId = UrlData[0].AsInt();
            Json.Write(WebApp.Db.SingleOrDefault<Order>(orderId),Response.Output);
        }
    }

    And here’s a sample of a post (/macroScripts/api/order/insert)

    @functions{
        // URL : /macroScripts/api/order/insert [POST]
        protected override void InitializePage()
        {
            base.InitializePage();
            // Deserialize input stream to Order object
            var jsonData = new StreamReader(HttpContext.Current.Request.InputStream).ReadToEnd();
            var order = Json.Decode<Order>(jsonData);                
            var newOrderId = WebApp.Db.Insert(order);
            Json.Write(newOrderId, Response.Output);
        }
    }

    My javascript calls looks like this:

    // post knockout viewmodel:
    my.utils.postJs("/order/insert", ko.toJSON(viewModel), function (newOrderId) {
      // update viewmodel with newOrderId;
    });
    // get:
    my.utils.getJs("/order/get/" + orderId, function (order) {
      // do something with order
    }

    Thats it. Works on my machine.

    Some nice things about this:

    * It’s using Pocos, Json de- & serialized the same way as in WebApi and SignalR
    * It’s just Razor, no need for extra DLL’s
    * Easy to maintain structure

    Comments / questions / suggestions are very welcome as always!

    Here’s a gist with the same code as above + that little js helper

    Also make sure you’re using in your web.config to be able to use WebPages funcitonality.

    There is one problem with date formatting. The best workaround I found for it is to use Json.Net serializer (which is in Umbraco bin already). Like this:

            var isoConvert = new IsoDateTimeConverter();
            isoConvert.DateTimeFormat = "yyyy-MM-dd hh:mm:ss";
            Response.Write(JsonConvert.SerializeObject(Get(UrlData[0].AsInt()),isoConvert));
    
            var jsonData = new StreamReader(HttpContext.Current.Request.InputStream).ReadToEnd();
            var isoConvert = new IsoDateTimeConverter();
            isoConvert.DateTimeFormat = "yyyy-MM-dd hh:mm:ss";
            var order = JsonConvert.DeserializeObject<Order>(jsonData, isoConvert);
    
            Json.Write(Insert(order), Response.Output);
    

    Using SignalR with Umbraco to broadcast messages (or chat) [15 minutes]

    Standard

    My goal with this is to have a way to send messages from running tasks to me (and other admins) using a broadcast method … aswell as have some fun playing with SignalR which looks really cool :).

    Just by adding the SignalR dll and js files and some minimal code you’ll get started with SignalR within an Umbraco application in 15 minutes.

    Installation
    1. Either download and install my little uSignalR experimental package (SignalR files from 2011-11-21) or run the SignalR Nuget to get fresh files from the source, and add the myconnection.cs and the two templates as shown below.

    2. I could not find out how to add a reserved url to the web.config using package actions, so you will need to add ~/echo manually in your web.config:

    ...
    <appSettings>
    ...
    <add key="umbracoReservedUrls" value="~/config/splashes/booting.aspx,~/install/default.aspx,~/config/splashes/noNodes.aspx,~/echo"/>
    ...
    

    Then just open the /mysite/recieve page in two (or more) browsers and start “chatting”. And to try the server send functionality – open the /mysite/send page . You can see the code here below. To read more and explore the possibilities : look at the SignalR wiki

    Brief explanation of the parts that makes it happen

    In /App_Code/MyConnection.cs we hook up the connection which listens to messages and broadcasts them to the listeners.

    using System;
    using System.Threading.Tasks;
    using SignalR;
    
    public class MyConnection : PersistentConnection
    {
        protected override Task OnReceivedAsync(string clientId, string data)
        {
            return Connection.Broadcast(data);
        }
    }
    
    public class MySignalRRoute : umbraco.BusinessLogic.ApplicationBase
    {
        public MySignalRRoute()
        {
            SignalR.Routing.RouteExtensions.MapConnection<MyConnection>(System.Web.Routing.RouteTable.Routes, "echo", "echo/{*operation}");
        }
    }

    In the “Send” Template we just send messages to all listeners.

    <asp:Content ContentPlaceHolderID="ContentPlaceHolderDefault" runat="server">
    <umbraco:macro runat="server" language="cshtml">
    @{
        SignalR.Connection.GetConnection<MyConnection>().Broadcast("This is a message from the server");   
    }
    </umbraco:macro>
    </asp:Content>
    

    The “Recieve” Template is only html + javascript which lets the users send and listen to messages.

    <asp:Content ContentPlaceHolderID="ContentPlaceHolderDefault" runat="server">
    
    <script src="http://code.jquery.com/jquery-1.7.min.js" type="text/javascript"></script>
    
    <script src="Scripts/jquery.signalR.min.js" type="text/javascript"></script>
    
    <script type="text/javascript">
    
        $(function () {
    
            var connection = $.connection('echo');
            connection.received(function (data) {
                $('#messages').append('<li>' + data + '</li>');
            });
    
            connection.start();
    
            $("#broadcast").click(function () {
                connection.send($('#msg').val());
            });
        });
    </script>
    
    <input type="text" id="msg" />
    <input type="button" id="broadcast" value="broadcast" />
    
    <ul id="messages">
    </ul>
    </asp:Content>