Search code examples
sitecoreinversion-of-controlsitecore7.2glass-mappersitecore-mvc

Sitecore DI with Unity


I'm trying to setup a brand new Sitecore 7.2 website and I'm looking to integrate MVC 5, Glass Mapper and Microsoft Unity as a DI container and Sitecore doesn't want to play very nice.

My scenario is this:

  • Got a Web project called PoC.Quotes.Web - this will contain only CSS, HTML and any other assets, no controllers
  • Got a class library project called PoC.Quotes.Controllers - this only contains controllers
  • Got a class library project called PoC.Quotes.DataLayer - this contain a interface ISitecoreRepository and it's concrete implementation SitecoreRepository

The SitecoreRepository class has a constructor that receives 1 single parameter, the Glass Mapper Context, and one of my controllers receives 1 single parameter in the constructor...the ISitecoreRepository.

Sitecore repository class:

public class SitecoreRepository : ISitecoreRepository
{
    ISitecoreContext sitecoreContext = null;

    public SitecoreRepository(ISitecoreContext context)
    {
        this.sitecoreContext = context;
    }
}

Controller class:

public class HomeController : Controller
{
    private ISitecoreRepository _repository;
    public HomeController(ISitecoreRepository repository)
    {
        this._repository = repository;
    }
}

Every time I run the project Sitecore throws an error saying that it cannot create a controller of type (PoC.Quotes.Controllers.HomeController, PoC.Quotes.Controllers). I guess it shows the fully qualified name because that's how I set it up in the controller rendering.

First problem is the controller constructor parameter. I took it out and use this statement to get the instance for the repository:

System.Web.Mvc.DependencyResolver.Current.GetService<ISitecoreRepository>();

The result is null, because the class SitecoreRepository is only having 1 constructor with 1 parameter and it won't get instantiated. Once I get that parameter out of the question too, then all works great.

However, to me this kinda defies the purpose of having a DI container.

I've tried looking at Castle Windsor, but although there is more documentation online, nothing works as I'm getting similar issues.

It is a bit annoying because if I run a similar test in a basic MVC 5 app (I did that just to be sure I'm not going mad), all works fine in less than 5 minutes.

Any ideas?

Edit:

In an interesting twist, after a few good hours spent on this issue, I've noticed that actually either Unity or Windsor containers work fine with one limitation...a big one.

In my controller rendering I've set the controller property as the fully qualified name of the controller:

PoC.Quotes.Controllers.HomeController, PoC.Quotes.Controllers

However, if I go in Sitecore and change that property to just Home, by magic all is good. I've even tried the interim version of using PoC.Quotes.Controllers.Home but still get an error, a different one mind you.

Not sure if I'm doing something wrong but it feels a bit odd.

Any ideas how to get this fixed?


Solution

  • Spent a considerable amount of time on this and managed to come up with a solution. It was a bit long to write in here so I've put it on a blog post http://agooddayforscience.blogspot.co.uk/2015/10/sitecore-multi-tenancy-and-di-containers.html

    Basically it wasn't an issue with Unity or other DI container, it was around how Sitecore handles fully qualified names. Yes, I know that ideally you don't want to use those but to follow the MVC pattern, but I've explained more in the blog post around why use fully qualified names.

    As a high level explanation the problem resides in 2 Sitecore classes ControllerRunner and SitecoreControllerFactory. Both classes contain some methods that identify the fully qualified name and use reflection to call the parameter-less constructor to instantiate a new instance. The fix I've applied overrides these methods to call the controller factory regardless.

    Thanks for all the help provided.

    Andrei