A runtime for Umbraco - Part 3

June 20, 2015

This is an old archived post, content maybe out of date, links may be broken and layout may be broken.

And so on to part 3 - and the runtime has a name ”Speedwagon“.

Since I last wrote, the project has become all hipster with Kevin offering up a Node implementation of the runtime at https://github.com/KevinJump/nodebraco.runtime.site

I’ve also bared my soul and published the source for the runtime at: https://github.com/darrenferguson/moriyama-umbraco-runtime

This time, I want to write about the CacheLessRuntimeContentService and show how we can get a piece of content from our JSON files and make it available for an MVC view to render.**

The default runtime controller does this:

var url = ctx.Request.Url;
var urlString = String.Format("{0}{1}{2}{3}", url.Scheme, Uri.SchemeDelimiter, url.Authority, url.AbsolutePath);

var model = RuntimeContext.Instance.ContentService.GetContent(urlString);

if (model != null)
    return View("~/Views/" + model.Template + ".cshtml", model);

Response.StatusCode = 404;
return View("~/Views/404.cshtml", Build404Model(ctx.Request.Url));

Simplified into plain English this just means here is a URL, get me some content.

The CacheLessRuntimeContentService gets content from disc every time you ask for it. it also acts as a base class for other implementations of the content service which override certain methods to check in a content cache etc.

public virtual RuntimeContentModel GetContent(string url)
    url = ProcessUrlAliases(url);

    Logger.Info("Got from disk " + url);
    var contentFile = PathMapper.PathForUrl(url, false);

    if (!File.Exists(contentFile))
        if (Removed != null)
            Removed(url, new EventArgs());

        return null;

    var content = FromFile(contentFile);

    if (Added != null)
        Added(content, new EventArgs());
    return content;

The PathMapper is something I’ve mentioned previously which turns a URL into a path on disc and the FromFile method just deserialises JSON. ProcessUrlAliases just swaps out the URL of the request with the URL that Umbraco runs on.

In a cached content service GetContent is overridden to look in the Cache and fall-back to the base method in the cache less implementation.

So what is missing from Part 3 is traversal. I’m going to try and explain this in words, but it is probably best to peek into the source.

Children are just content items that have a URL that begin with the same URL but contain one more Slash. Descendants are just content items that begin with the same URL. Root content is just content with a level of 1. Top navigation is just content with a Level of two. The logic is all really simple.

To have access to this information, the runtime just maintains a file that contains a list of all URLs.

For example. in a View I can do:

foreach (var page in Model.Home().Children().Where(page => page.Type == "BlogTextPage" && !page.HideInNavigation()))

Under the hood Home does:

protected string HomeUrl(RuntimeContentModel model)
   var a = Urls.Where(x => model.Url.StartsWith(x)).OrderBy(x => x.Length);
   return a.First();

And Children does:

protected IEnumerable ChildrenUrls(RuntimeContentModel model)
    return Urls.Where(x => x.StartsWith(model.Url) && x != model.Url && x.Split('/').Length == model.Url.Split('/').Length + 1);

There are lots of efficiencies to be gained - but for now the logic is kind of readable.

So a wrap for part 3 I think. Part 4 will be how to extend the default Runtime Controller, to do posting of blog comments and other form submissions. Part 5, implementation of cached content services, and part 6 what needs to be done to speed this up and make it integrate seamlessly with Umbraco.

Thanks for your interest to date - I’d love your feedback on the source, but please go easy. I did rush it somewhat.


Matt - June 24, 2015

keep up the good work - very interesting path you’re heading down

Brice - September 28, 2015

I just came across your Runtime articles, inadvertently, while searching for Umbraco custom logging.

We have been doing the same using Solr as the repository instead of flat files. We have had a couple of sites up for a few years and it is working out pretty well on Umbraco 4. One difference is we spit out a minimum of template from the initial request/response and the rest of the site fills itself in with javascript requests. WE would probably use more caching and less JS next time.

I am in the process of building a new site in this style on Umbraco 7 and I had really thought about using Node on the front-end but I may have to use c#/mvc due to time/budget contraints. Finding your posts was very timely! This go-round

I am happy to see you have taken this a step further and packaged it up (I am right in the middle of doing the same thing almost exactly like this!). We use the Solr platform on www.steamboatchamber.com and www.vvf.org. I look forward to seeing more posts… and using the Node implementation to seed my own version.

About the Author

About Darren

Leave a Comment

Comments are manually moderated and added once reviewed.