Umbraco Web Api and MVC Dependency Injection

Introduction

In this article, I am going to present a complete tutorial how easily setup Dependency Injection using Inversion of Control container in Umbraco V7 solution. There are many .NET containers, but before we pick a specific one - it's worth visiting the IoC Battle page, where you can find a performance comparison of popular IoC frameworks. In this example, we will focus on Autofac. Once configured, we should be able to use Dependency Injection in both MVC and Web API controllers. Using this flexible technique, we are able to inject components such as services directly into controllers, but there are more advantages like:

  • Configuration flexibility
  • Loosely couple architecture
  • Testing using mock objects
  • Removing knowledge of a concrete implementations
  • Concurrent or independent development

In many cases our website should be able to integrate with other services – in some cases, we need to create REST endpoint to feed some data. This can be done in a very easy way using Umbraco.Web.WebApi.UmbracoApiController. This class wraps a classic WebApi engine and it’s possible to use Umbraco related objects and services. Our plan is to use the benefits of Dependency Injection in sample controllers.

Solution set up

In the beginning, we should follow these steps:

  • Create .NET solution with empty .NET ASP project
  • Install Umbraco CMS from NuGet repository

Next, go to Nuget package Manager repository and install Autofac library with dependencies:

  • Autofac.MVC5
  • Autofac.WebApi2

Umbraco CMS Autofac

protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
        {
            GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
            RegisterIoCContainer();
        }

After the process finishes, we are ready to use Autofac and set up the container – Umbraco application started event is the right place. RegisterIoCContainer() method wraps the logic of building the container.

private void RegisterIoCContainer()
        {
            var builder = new ContainerBuilder();

            /* MVC Controllers */
            builder.RegisterControllers(Assembly.GetExecutingAssembly());
            builder.RegisterAssemblyModules(Assembly.GetExecutingAssembly());
            builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
            builder.RegisterModelBinderProvider();

            /* WebApi Controllers */
            builder.RegisterApiControllers(typeof(UmbracoApplication).Assembly);
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

            builder.RegisterModule<WebModule>();

            var container = builder.Build();

            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
            GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
        }

WebModule is a custom class which is used to bundle up a set of related components into one logical unit – it’s flexible and recommended approach. In this case, we have only two components SampleService and UmbracoContext – but you can register as many as you want. Thanks to the last line, UmbracoContext.Current is available through Dependency Injection.

public class WebModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<SampleService>()
                .As<ISampleService>();

            builder.Register(c => UmbracoContext.Current).AsSelf();
        }
    }

Data feed

For this purpose let’s create sample service with one method GetItems() returning some dummy data. We wanna use this data in both RenderMVCController and UmbracoApiController

public class SampleService : ISampleService
    {
        public IList<string> GetItems()
        {
            return new List<string>()
            {
                "Autofac",
                "Ninject",
                "Unity",
                "Castle Windsor",
                "Spring.NET",
                "StructureMap"
            };
        }
    }

Controllers and view

public class SampleWebApiController : UmbracoApiController
    {
        private readonly ISampleService _sampleService;

        public SampleWebApiController(ISampleService sampleService)
        {
            _sampleService = sampleService;
        }

        [System.Web.Http.HttpGet]
        public JsonResult Get()
        {
            return new JsonResult() { Data = new { items = _sampleService.GetItems() }, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
        }
    }

To create a view and show data from our ViewModel, we need to create document type, whose name corresponds to the name of the controller rendering the view. So let’s go to the backoffice and create a document type named “SampleRenderMvc” with a template. Then let’s create a custom class in “Controllers” folder named “SampleRenderMvcController”. After injecting ISampleService into local variable via constructor we are able to use ISampleService contract.

public class SampleRenderMvcController : RenderMvcController
    {
        private readonly ISampleService _sampleService;

        public SampleRenderMvcController(ISampleService sampleService)
        {
            _sampleService = sampleService;
        }

        public ActionResult Index(RenderModel model)
        {
            return CurrentTemplate(new ExtendedModel(model.Content) { Items = _sampleService.GetItems() });
        }
    }

    public class ExtendedModel : RenderModel
    {
        public ExtendedModel(IPublishedContent content)
            : base(content)
        {
        }

        public IList<string> Items { get; set; }
    }

SampleRenderMvcController is ready, so let’s create a simple view based on ExtendedModel with items property. Go to Views folder and change view type from UmbracoTemplatePage to UmbracoViewPage. With UmbracoViewPage view, it is possible to iterate via custom model property and render the list.

@inherits Umbraco.Web.Mvc.UmbracoViewPage<UmbracoCMSDIMixedMode.Web.Controllers.RenderMvc.ExtendedModel>
@using ContentModels = Umbraco.Web.PublishedContentModels;
@{
    Layout = null;
}

<p>Popular IoC list:</p>

<ul>
    @foreach (var item in Model.Items)
    {
        <li>@item</li>
    }
</ul>

Manual testing

Checking API request is simple, I decided to use popular rest API client – Fiddler:

To see if our MVC view properly displays service data, just enter the path of the content node into the browser – in my case, it’s the root folder:

Umbraco CMS IOC

A complete solution is available on GitHub

ABOUT THE AUTHOR
Piotr Łuksza

Piotr Łuksza

DotNet Consultant 💪| Umbraco Certified Master | Azure Cloud☁️& Digital marketing Enthusiast

Follow me: