• Publisert
  • 6 min

ASP.NET Web API in EPiServer CMS 7 projects

Here is how you can use Web API in an EPiServer CMS 7 MVC project with dependency injection in the API controllers.

I want to expose a simple API from an application without creating any big web service layers. To accomplish this I will be creating a controller called ProofOfConcept in a clean Alloy MVC project. It should work in a web forms flavor of a CMS7 project as well, but I have not tested that. The controller uses an injected IContentLoader as a repository and fetches product pages from EPiServer. It then goes on to expose objects of a custom class called ConceptItem in the API.

One of the main goals is to re-use the dependency resolving already configured in the application; StructureMap.

Set up Web API

The Web API pretty much works out of the box when you install it via NuGet. Just find the package Microsoft.AspNet.WebApi and install it in your web project. There are quite a few dependencies tagging along, but Microsoft.AspNet.WebApi gives you what you need.

After that, the first thing to do is set up a route. We have to tell our application about that and it will act as an endpoint for our API. The quickest fix is to set it up in your global application’s startup method:

public class Global : EPiServer.Global
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        GlobalConfiguration.Configuration.Routes.MapHttpRoute(
            name : "DefaultApi",
            routeTemplate : "api/{controller}/{id}",
            defaults : new { id = RouteParameter.Optional });
    }
}

The thing to notice here is of course the call to the MapHttpRoute method. It maps up a route that enables us to have controllers under a root called ~/api in our application. I left out the rest of the code in the Global class out for clarity. 

The fun part – the API controller

The controller class will be called ProofOfConceptController in my sample. It takes in an IContentLoader in the only constructor present. I will then use this content loader instance as a data factory and fetch some pages (ProductPage instances to be precise) and map them to a simpler type of object before returning them. I have implemented “get one” and “get many” in this sample.  As long as the method name starts with “Get” the web API will know what to do. Pretty neat. There is of course corresponding method naming you can use  for POST when creating stuff, PUT for updating and DELETE for, well deleting. But this is all part of the web API and documented better elsewhere. (You should check it out though. It’s really cool to work with.)

I let the controller code speak for itself:

public class ProofOfConceptController : ApiController
{
    private readonly IContentLoader repo;

    public ProofOfConceptController(IContentLoader repo)
    {
        this.repo = repo;
    }

    /// <remarks>GET api/ProofOfConcept</remarks>
    public IEnumerable<ConceptItem> Get()
    {
        return repo.GetChildren<ProductPage>(ContentReference.StartPage).Select(Map);
    }


    /// <remarks>GET api/ProofOfConcept/5</remarks>
    public ConceptItem Get(int id)
    {
        return Map(repo.Get<ProductPage>(new ContentReference(id)));
    }


    private static ConceptItem Map(PageData p)
    {
        return new ConceptItem { Title = p.Name, Date = p.StartPublish, ID = p.ContentLink.ID };
    }

    // Omitted from concept: POST, PUT, DELETE
}

Not much going on in this proof of concept right now. In fact, it doesn’t even implement any nasty serialization logic, which is nice. It simply calls upon the content loader to fetch ProductPage (from the Alloy template) instances and converts them into a ConceptItem class:

public class ConceptItem
{
    public DateTime Date { get; set; }
    public string Title { get; set; }
    public int ID { get; set; }
}

After compiling and running the Alloy web site, I point my browser of choice over to ~/api/ProofOfConcept and it is with some disappointment I realize I have an error. It’s a System.ArgumentException complaining that the controller ProofOfConceptController “does not hava a default constructor”. So, it seems my dependency injection attempt didn’t work but the routing kicked in like expected.

Resolving dependencies

There is already a dependency resolver implemented in the web project so I would like to re-use that. After fixing the resolver, I need to make a minor change to the initialization module that sets up the resolving at application startup.

StructureMap dependency resolver.

In this sample I will make it implement the IDependencyResolver interface found in System.Web.Http.Dependencies in addition to the one in System.Web.Mvc. I added two explicit using statements to tell them apart in code:

using MvcDependencyResolver = System.Web.Mvc.IDependencyResolver;
using HttpDependencyResolver = System.Web.Http.Dependencies.IDependencyResolver;

public class StructureMapDependencyResolver : MvcDependencyResolver, HttpDependencyResolver
{
    private readonly IContainer _container;

    public StructureMapDependencyResolver(IContainer container)
    {
        _container = container;
    }

    public IDependencyScope BeginScope()
    {
        // This example does not support child scopes
        return this;
    }

    public void Dispose()
    {
    }


    public object GetService(Type serviceType)
    {
        if (serviceType.IsInterface || serviceType.IsAbstract)
            return GetInterfaceService(serviceType);
        return GetConcreteService(serviceType);
    }


    public IEnumerable<object> GetServices(Type serviceType)
    {
        return _container.GetAllInstances(serviceType).Cast<object>();
    }


    private object GetConcreteService(Type serviceType)
    {
        try
        {
            // Can't use TryGetInstance here because it won’t create concrete types
            return _container.GetInstance(serviceType);
        }
        catch (StructureMapException)
        {
            return null;
        }
    }


    private object GetInterfaceService(Type serviceType)
    {
       return _container.TryGetInstance(serviceType);
    }
}

The only real difference from the dependency resolver in the Alloy MVC templates is that I have inherited two variants of the IDependecyResolver interface: MvcDependencyResolver & HttpDependencyResolver. In addition I have added implementations for the methods BeginScope and Dispose required by System.Web.Http.Dependencies.IDependencyResolver .

Initialization

In the public ConfigureContainer method  in the initializer I will new up a StructureMapDependencyResolve and pass that resolver instance along to MVC and WebAPI:

[InitializableModule]
public class DependencyResolverInitialization : IConfigurableModule
{
    public void ConfigureContainer(ServiceConfigurationContext context)
    {
        context.Container.Configure(ConfigureContainer);

        StructureMapDependencyResolver resolver = new StructureMapDependencyResolver(context.Container);

        DependencyResolver.SetResolver(resolver);
        GlobalConfiguration.Configuration.DependencyResolver = resolver;
    }


    public void Initialize(InitializationEngine context)
    {
    }


    public void Preload(string[] parameters)
    {
    }


    public void Uninitialize(InitializationEngine context)
    {
    }


    private static void ConfigureContainer(ConfigurationExpression container)
    {
        //Swap out the default ContentRenderer for our custom

        container.For<IContentRenderer>().Use<ErrorHandlingContentRenderer>();

        //Implementations for custom interfaces can be registered here.
    }
}

Notice the ConfigureContainer method where I pass the dependency resolver along. The rest of the code is standard Alloy MVC template material.

Will it float?

Yes! Now browsing to ~/api/ProofOfConcept returns a serialized list of objects. ~/api/ProofOfConcept/5 tries to fetch a singe object (Alloy Plan in my case).

Fiddling with the request composer

Usages

The web API is really cool. We use it in several projects and it is just great when we need a simple and RESTful API that can be called upon from javascript via JSON. When we in addition can unleash everything the EPiServer ServiceLocator has to offer it gets very powerful. And injecting the dependencies is almost a must when testing the API controller logic.

This sample is an easy one using a simple content loader for fetching stuff, but it opens up a lot of possibilities. For instance; I was quite pleased when after we set up a custom content type inherited from IContent, we were able to use Web API to post and get data in no time at all. From client side javascript to EPiServer’s content storage in very little time — that means more time to to other things.