Dependency Injection using Simple Injector for Sitecore 8 WebApi Attribute Routing in APIControllers

Posted 01/24/2015 by Akshay Sura

I have been working with Simple Injector for a while now, partly because its way faster than Ninject and also because it lands in the top 5 in speed. Simple Injector has very good .NET Support.

There are a few challenges getting WebAPI attribute routing in place in Sitecore 8 with dependency injection using Simple Injector. My Scenario is to communicate with Jive to pull data into a JSON based UI.

First I start of with "Highly testable Sitecore code using MVC, Ninject, Synthesis, Moq, and NUnit" but modified to use Simple Injector. This sets up dependency injection for regular controllers, no problem.

The issue is when you add in APIControllers to the solution. I wasn't able to get Attribute routing working, worse yet, its different to get it working in Sitecore 7.2, 7.5 and 8. The following posts helped me figure out a solution:

My issue was that I didn't want to add in configs and overriding pipeline processors. I wanted it to be simple. Based on the blog posts above, I ended up using WebActivatorEx.

Now for my simple APIController with Simple Injector:

namespace PROJECTNAME.Website.Controllers.Services
{
    // the RoutePrefix is the base path to the API controller
    //[RoutePrefix("api/jive")]
    public class JiveController : ApiController
    {
        private readonly ICache _currentCache;
        private readonly IJiveData _jiveData;

        public JiveController(ICache CurrentCache, IJiveData JiveData)
        {
            _currentCache = CurrentCache;
            _jiveData = JiveData;
        }

        [HttpPost]
        public IHttpActionResult GetJiveItems(JiveRequest jiveRequest)
        {
            List<PostItem> returnPosts = _currentCache.GetOrCreateItem(jiveRequest.IDs, () => _jiveData.RefreshData(jiveRequest.IDs, jiveRequest.Type, jiveRequest.Url), new TimeSpan(12, 0, 0));

            if (returnPosts != null && returnPosts.Count > 0)
                return Ok(returnPosts.Take(jiveRequest.Count));
            else
                return Ok(new List<PostItem>());

            //the default MediaTypeFormatter will handle the serialization
        }
    }

}

The problem was that I got the following error:

Server Error in '/' Application.

The object has not yet been initialized. Ensure that HttpConfiguration.EnsureInitialized() is called in the application's startup code after all other initialization code.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.InvalidOperationException: The object has not yet been initialized. Ensure that HttpConfiguration.EnsureInitialized() is called in the application's startup code after all other initialization code.

I was already registering the Interfaces for Injection in the App_Start for Simple Injector, what else do I need to do?

namespace PROJECTNAME.Website.App_Start
{
    public class WebsitePackage : IPackage
    {
        public void RegisterServices(Container container)
        {
            container.Register<IScriptLogic, ScriptLogic>();
            container.Register<IProgramInfo, ProgramInfo>();
            container.Register<ICanonical, Canonical>();
            container.Register<IMetaTags, MetaTags>();
            container.Register<INavigationLogic, NavigationLogic>();
            container.Register<ISettings, SiteSettings>(Lifestyle.Singleton);
            container.Register<IFooterLogic, FooterLogic>();
            container.Register<ICarouselLogic, CarouselLogic>();
            container.Register<IDateTime, DefaultDateTime>();
            container.Register<ICache, SimpleCache>();
        }
    }
}

Since Simple Injector was having an issue I found a few articles on how to resolve this with filters etc but found Simple Injector ASP.NET Web API Integration Quick Start for IIS-hosted applications. By adding the Simple Injector Web API and the following into the App_Start WebActivatorEx code, it started working. 

[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(PROJECTNAME.Website.App_Start.SimpleInjectorWebApiInitializer), "Initialize")]
namespace PROJECTNAME.Website.App_Start
{
    public static class SimpleInjectorWebApiInitializer
    {
        public static void Initialize()
        {
            var container = new Container();

            container.RegisterWebApiRequest<IDateTime, DefaultDateTime>();
            container.RegisterWebApiRequest<ICache, SimpleCache>();
            container.RegisterWebApiRequest<IJiveData, JiveData>();
            container.Verify();
            
            GlobalConfiguration.Configuration.DependencyResolver =
                new SimpleInjectorWebApiDependencyResolver(container);

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

The thing to note is that we are registering the WebApiRequests.

The results passed back from your APIController are based on the default MediaTypeFormatter. The objects you return as a list, the default media type formatter will handle the serialization based on the content type specified from the client (providing it is json or xml). I didn't need to do the following since JSON was the default provider:

GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());

Here are a few useful links:

Share:

Archive

Syndication