Using the ASP.NET Web API Framework with EPiServer

Posted on February 23, 2012 by Frederik Vig in ASP.NET, EPiServer

With the ASP.NET Web API framework we can easily build restful API’s that allow us to expose our data to a whole bunch of different clients, everything from rich JavaScript applications to Flash or mobile apps.

The cool thing about the Web API framework is that you don’t need ASP.NET MVC 4 to run it, we can easily get everything we need with NuGet and then deploy it to our server without having to install anything extra on the server.

Getting started

Our EPiServer site needs to run .NET 4 for this to work, for this tutorial I installed a local copy of the AlloyTech sample site. I then upgraded it to use .NET 4 and installed the ASP.NET Web API through NuGet.

This will download and add everything we need for running ASP.NET Web API on our site.

We now need to setup the routing rules in the Application_Start method in global.asax. After adding the routing rules my global.asax looks like this.

using System;
using System.Linq;
using System.Text;
using System.Web.Http;
using System.Web.Routing;
using System.Web.UI;
using System.Web.UI.WebControls;
using EPiServer.Core;
using EPiServer.Globalization;
using EPiServer.Web;
using EPiServer.XForms.WebControls;
using Label = System.Web.UI.WebControls.Label;
using RouteParameter = System.Web.Http.RouteParameter;
 
namespace EPiServer.Templates
{
	public class Global : EPiServer.Global
	{
		protected void Application_Start(Object sender, EventArgs e)
		{
                    XFormControl.ControlSetup += new EventHandler(XForm_ControlSetup);
                    RegisterRoutes(RouteTable.Routes);
                }
 
                public static void RegisterRoutes(RouteCollection routes)
                {
                    routes.MapHttpRoute(
                       name: "ActionApi",
                       routeTemplate: "api/{controller}/{action}/{id}",
                       defaults: new { id = RouteParameter.Optional }
                    );
                }
 
                #region Global XForm Events
                ...
                #endregion
        }
}

For more information on the routing table take a look at this article: Routing in ASP.NET Web API.

Creating the API

Create a new class and give it the name PagesController, place it in a folder called Api. Our controller is going to inherit from the abstract base class ApiController.

using System.Web.Http;
 
namespace EPiServer.Api
{
    public class PagesController : ApiController
    {
    }
}

We are going to use the Pages API to expose EPiServer PageData to the public. We can then easily use this content in different channels and applications.

The URLs for our API are going to look something like this: /api/pages/get/{id}, /api/pages/getchildren/{id}.

using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using EPiServer.Core;
using EPiServer.Mapping;
using EPiServer.Security;
using EPiServer.ViewModels;
 
namespace EPiServer.Api
{
    public class PagesController : ApiController
    {
        public PageDataView Get(int id)
        {
            PageData page = DataFactory.Instance.GetPage(new PageReference(id));
 
            if (page == null)
            {
                throw new HttpResponseException(System.Net.HttpStatusCode.NotFound);
            }
 
            if (!page.CheckPublishedStatus(PagePublishedStatus.Published) || !page.QueryDistinctAccess(AccessLevel.Read))
            {
                throw new HttpResponseException(System.Net.HttpStatusCode.Forbidden);
            }
 
            return page.ConvertToPageDataView();
        }
 
        public IEnumerable<PageDataView> GetChildren(int id)
        {
            var pages = DataFactory.Instance.GetChildren(new PageReference(id));
 
            if (pages == null)
            {
                throw new HttpResponseException(System.Net.HttpStatusCode.NotFound);
            }
 
            Filters.FilterForVisitor.Filter(pages);
 
            if (pages.Count == 0)
            {
                throw new HttpResponseException(System.Net.HttpStatusCode.Forbidden);
            }
 
            return pages.Select(p => p.ConvertToPageDataView());
        }
    }
}

The content can of course also come from dynamic data store or any other place for that matter. Note that I created a view model or data transfer object to send to the client. The main reason is that you’ll get a serialization exception if you try and use a PageData object.

using System;
 
namespace EPiServer.ViewModels
{
    public class PageDataView
    {
        public string Heading { get; set; }
 
        public string LinkUrl { get; set; }
 
        public string MainIntro { get; set; }
 
        public string MainBody { get; set; }
 
        public DateTime StartPublish { get; set; }
 
        public string Author { get; set; }
    }
}
using EPiServer.Core;
using EPiServer.ViewModels;
 
namespace EPiServer.Mapping
{
    public static class PagesMapper
    {
        public static PageDataView ConvertToPageDataView(this PageData pageData)
        {
            return new PageDataView
                       {
                           Author = pageData.CreatedBy,
                           StartPublish = pageData.StartPublish,
                           MainBody = pageData["MainBody"] as string ?? string.Empty,
                           MainIntro = pageData["MainIntro"] as string ?? string.Empty,
                           Heading = pageData["Heading"] as string ?? pageData.PageName,
                           LinkUrl = pageData.LinkURL
                       };
        }     
    }
}

Just some very simple mapper code here.

Consuming the API

<div class='loadingIndicator'>Loading...</div>
    <ul data-bind="foreach: listItems">
    <li>
          <a data-bind="attr: { href: LinkUrl }, text: Heading"></a>
          <span data-bind="text: StartPublish"></span>
    </li>
</ul>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://knockoutjs.com/js/knockout-2.0.0.js"></script>
<script>
        $(".loadingIndicator").ajaxStart(function () {
            $(this).fadeIn();
        }).ajaxComplete(function () {
            $(this).fadeOut();
        });
 
        $.getJSON('/api/pages/getchildren/41', function (data) {
            viewModel.listItems(data);
        });
 
        var viewModel = {
            listItems: ko.observableArray(null)
        };
 
        ko.applyBindings(viewModel);
</script>

I’m using the Knockout JavaScript library for populating the list and jQuery for getting the data from the API. This will display a loading message to the user and then populate the list with the data it gets back.

Related Posts: