Search code examples
c#.netinversion-of-controlunity-container

Why does Unity (DI) work in the Controller, but not in my service layer?


I've used quite a few different DI containers in the past, but never Unity (Specifically Unity 4.0.1).

I'm working with a plain old .NET MVC app with typical 3 tier architecture. Repository -> Domain -> WebUI.

I need to know what I am doing wrong so that I can get my registered dependencies to work on the domain layer. Here is what I have in my global.asax.

protected void Application_Start()
{
    // ...

    IUnityContainer container = new UnityContainer();
    RegisterDependencies(container);
    DependencyResolver.SetResolver(new WebApplicationDependencyResolver(container));
}

protected void RegisterDependencies(IUnityContainer container)
{
    container.RegisterType<IUnitOfWork, UnitOfWork>();
}

Here is the WebApplicationDependencyResolver used above:

namespace WebApplication1.Infrastructure
{
    public class WebApplicationDependencyResolver : IDependencyResolver
    {
        private IUnityContainer _container;
        public WebApplicationDependencyResolver(IUnityContainer container)
        {
            _container = container;
        }

        public object GetService(Type serviceType)
        {
            try
            {
                return _container.Resolve(serviceType);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            try
            {
                return _container.ResolveAll(serviceType);
            }
            catch (Exception)
            {
                return null;
            }
        }
    }
}

My Domain Layer class CustomerService.cs (which I used both in it's own project and in a folder in the main project):

namespace WebApplication1.Services
{
    public class CustomerService
    {
        private readonly IUnitOfWork _uow;

        public CustomerService(IUnitOfWork uow)
        {
            _uow = uow;
        }
    }
}

Now, when I try to call the CustomerService class in my controller like so, it doesn't work:

public ActionResult Index()
{
    var service = new CustomerService();
    return View();
}

But If I use the resolver on the controller itself, it works:

public class HomeController : Controller
{
    private IUnitOfWork _unitOfWork;

    public HomeController(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public ActionResult Index()
    {
        var service = new CustomerService(_unitOfWork);
        return View();
    }
}

Can anyone direct me in the right direction, to get DI working on the domain layer?


Solution

  • Try injecting the service in the controller instead of injecting IUnitOfWork. Then use the service instance in the controller methods:

    public HomeController(CustomerService service)
    {
      _service = service
    }
    
    public ActionResult Index()
    {
      var model = _service.GetAllCustomers();
      return View(model);
    }
    

    This should work, but it is not a good idea to have your class depend on another class. A dependency should be a contract (interface). You should refactor CustomerService to extract an interface ICustomerService and inject that one instead in the controller. Then you need to register it with the container in method RegisterDependencies:

    container.RegisterType<ICustomerService, CustomerService>();