Why I think your doing it wrong: Umbraco AltTemplate & Data Views

Common sense warning

Before I start this post let me outline this is my opinion and you may or may not agree with it. However if you want to discuss it with me in the comments I will be more than happy to, but please respect each others opinions and views and don’t start an angry flame war.

OK enough of the common sense stuff lets get to it.

I personally think you are doing it wrong if you are using alternative templates in Version 6 of Umbraco to return JSON or XML for example.
So read on to find out why and the approach I think you should be using.

Why are you doing it wrong?

I personally feel you are now doing it wrong in V6 of Umbraco and this method is now outdated now that we have more technology and options available to us these days. I must admit I was an avid user of the alternative template approach, allowing me to put a macro in a template and return some JSON or XML data that I needed. Which could be easily accessible via the URL instead of the ?altTemplate=getAllComments so I could do mysite.co.uk/getAllComments

I believe this was perfectly fine and is still OK to use if you want to, but I believe there is a better option. Another downside is that if you have a website with lots of data endpoints, you quickly clutter up your website with lots of templates specifically with a single macro in it, to return some data.

How should I be doing it?

I personally think you should be using the benefits of Umbraco and MVC and harness the power of the Web API controller which is part of the .NET 4.5 Framework. Which allows you to handle HTTP requests such as GET, POST, PUT & DELETE all very easily. But most commonly people are using alternative templates in Umbraco to do a simple GET request and return some JSON or XML which they normally use with JavaScript in their client side code of their site.

One of the benefits of using the .NET Web API controller is that it allows you to return JSON or XML without any work required from you. This is all done automatically with the http request headers, which either requests the format to be returned is XML or JSON. So that’s already saved us some time and effort already.

The main reason I believed people are using alternative templates is to allow them to have friendly URL endpoints for their data retrieval. For example mysite.co.uk/getAllComments but the same can be easily achieved with a Web API controller.

However the Umbraco core team has made it even easier for us, as they have their own version of the Web API controller that we can use, that gives us some added bonuses such as access to the Umbraco API and context which would have been a lot harder to do in a normal Web API controller.

So I will wrap this post up with some code examples for you to mull over and decide whether or not Web API controllers are right for you or if you still prefer the approach of using the alternative template method.

Show me the code!

First you will need to create a new class in your Umbraco website that is your WebApi Controller. I recommend you create the class in the Controllers folder, to follow the guidelines & patterns of ASP.NET MVC. Create a new class file and call it BlogAPI.cs 

You will need to ensure you class inherits from the following class Umbraco.Web.WebApi.UmbracoApiController by doing so we get access to some of the magical Umbraco properties that will make our lives alot easier to write our API data endpoints.

ApplicationContext ApplicationContext {get;}
ServiceContext Services {get;}
DatabaseContext DatabaseContext {get;}
UmbracoHelper Umbraco {get;}
UmbracoContext UmbracoContext {get;}

With these magical properties we are able to achieve most scenarios easily. So take a look through the class below which is heavily commented and see what you think.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Umbraco.Core;
using Umbraco.Web.WebApi;

namespace UmbracoUKFestival.controllers
{
    public class BlogComment
    {
        public int UmbracoNodeId { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public string Website { get; set; }
        public string Message { get; set; }
    }

    public class BlogApiController : UmbracoApiController
    {
        public IEnumerable GetBlogPostComments(int umbracoNodeId)
        {
            //Get the blog post from the Umbraco Node ID
            var blogPost = Umbraco.TypedContent(umbracoNodeId);

            //List of Comments that we will store our comments in & return
            var blogComments = new List();

            //Just double check the node exists in Umbraco (as bad ID may be passed to API)
            if (blogPost != null)
            {
                //Get child nodes of the blogPost node
                var comments = blogPost.Children.Where(x => x.DocumentTypeAlias == "BlogComment");

                //Check we have comments
                if (comments.Any())
                {
                    foreach (var comment in comments)
                    {
                        //Generate a new Blog Comment object
                        var blogComment = new BlogComment();

                        //Fetch the values from the umbraco node and set them on our BlogComment object
                        blogComment.UmbracoNodeId   = comment.Id;
                        blogComment.Name            = comment.GetProperty("commentName").Value.ToString();
                        blogComment.Email           = comment.GetProperty("commentEmail").Value.ToString();
                        blogComment.Website         = comment.GetProperty("commentWebsite").Value.ToString();
                        blogComment.Message         = comment.GetProperty("commentMessage").Value.ToString();

                        //Add it to our list of comments
                        blogComments.Add(blogComment);
                    }
                }
            }

            //Return the list of comments
            return blogComments;
        }
    }
}

You can then do a GET request to http://mysite.co.uk/umbraco/api/blog/GetBlogPostComments?umbracoNodeId=1234 to fetch the child BlogComment node types from the Umbraco node. It’s as simple as that.

Look forward to your opinions on this.
Warren 🙂

Advertisements

16 thoughts on “Why I think your doing it wrong: Umbraco AltTemplate & Data Views

  1. Do we know if can have custom (nice) URLs (routes) for Umbraco’s WebApi? e.g. say I have an RSS feed for a news section, I’d prefer it to be “/news/rss” rather than “/umbraco/api/GetNewsRss”

    1. Hello Lee,
      That is a very good point and will be something I will need to have a bit of experiment with. But it may be possible to update the routing to use a normal MVC controller and update the route config on the App Startup event of Umbraco perhaps?

      If you find out before me, please let me know.

      Cheers,
      Warren 🙂

    2. I am wondering the same thing and was going to try doing some simple URL rewriting to see if that worked as I prefer to give as little info about what the system is behind the site as possible in case a vulnerability is exposed in the future I want there to be as few clues as to whether the site is hackable.

  2. Hey

    This is ace, but… what about caching?

    I want to spit out some node information as a JSON array to manipulate on the front end. I want to take advantage of macro output caching so I am calling a method that makes a list of ‘blogcomment’ objects, then I am serializing this and outputting the html.raw string as the contents of a javascript variable. That way, I can take advantage of output caching as well as manipulate the JSON client side.

    Would be interested to get anyone’s thoughts on this approach!

  3. Hey Bill,
    I am not sure you would want to cache the JSON from the API Controller personally, as it should always show the latest data in my opinion and however you consume your data you would do the caching at the point.

    So if you using an Umbraco Macro to fetch the JSON and ouput it in a view/template then you can make use of @Html.CachedPartial() helper in your view.

    Or your HTTP Client call in your server side code, be it the controller or the view do some caching before fetching the results from the API

    There are many ways to do this, even in JavaScript as well I suppose but like I said it really depends on how your fetching/consuming your API.

    Cheers,
    Warren

  4. Hi Warren. I wonder if you might be able to offer some help? I have tried to implement an API using the MVC framework and controller in much the same way you have I am using the ContentService to do my Puts, Delete and Posts which are all working fine.

    I am trying to Get some information out using the helperclass like you are in the post above.
    var courseSubj = Umbraco.TypedContent(1062);

    But i am getting the following error after instantiating the class

    “Cannot return the IPublishedContent because the UmbracoHelper was constructed with an UmbracoContext and the current request is not a front-end request.”

    I am using the following URL to access my api
    http://localhost:11497/umbraco/api/coursedateapi/getallcourses

    Have i missed something obvious?

    1. Hello Chris,
      I am not entirely sure why you are getting the error using Umbraco.TypedContent()

      I would suggest using the our.umbraco.org forums to see if you can get some help.

      As with Umbraco there are many ways to do the same/similar thing. Youc could try using the ContentService instead.

      http://our.umbraco.org/documentation/Reference/Management-v6/Services/ContentService

      Have you tried setting a break point & stepping through your API controller?

      And finally thought have you inherited from UmbracoApiController

      Cheers,
      Warren 🙂

      1. Thanks for taking the time to reply. Yes I have tried stepping through which is where I picked up that particular error and I am also inheriting the UmbracoApiController.

        I’ll just use the ContentService instead as you mentioned.

        Many thanks
        Thanks
        Chris

  5. Recently done a couple of contracts where my first action has been to rewrite people’s altTemplates that output manually sculpted JSON into Web API with Automapper. Does my nut in every time I see it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s