-1

I am trying to implement Unity as an IoC container in a learning project I am working on. I have a layered application, UI->Service->Logic->DataAccess.

It's an MVC Application on the UI side.

In my controller, I have a constructor:

public HomeController()
{
    _container = new UnityContainer();
    _container.RegisterType<IUserService, UserService>();
    _container.RegisterType<IUserLogic, UserLogic>();
}

I then attempt to use the IService in one of my methods:

var service = _container.Resolve<IUserService>();
ReplyDto reply = service.Login(model.Email, model.Password);

But then get this error:

Resolution of the dependency failed, type = "Services.IUserService", name = "(none)".

I'm not sure why it's saying this. Do I maybe have an issue with MVC and the constructor? Breakpoint on the Resolve line shows that the _container does have the interface I am trying to resolve.

My UserService class has this in the constructor:

private IUserLogic _userlogic;

public UserService(IUserLogic logic)
{
    _userlogic = logic;
}

The Logic layer class is defined like this:

public class UserLogic : IUserLogic
{
    public ILog _logger;
    public IData _data;

    public UserLogic(IData data, ILog logger)
    {
        _data = data;
        _logger = logger;
    }

I am still in the process of propagating the IoC patter down through all layers.

And finally, the data access layer is defined as:

public class Data :IData
{
    Log _logger = new Log();
    MyEntities entities;
    public Data()
    {
        entities = new MyEntities();
        var instance = System.Data.Entity.SqlServer.SqlProviderServices.Instance;
    }

My _container has reference to the IUserLogic interfaces and which concrete class to use.

Craig
  • 18,074
  • 38
  • 147
  • 248
  • Unity has very default traces on what is going wrong... Since you did not show [MCVE] one had to guess that `UserLogic` has constructor that can't be used by Unity (either due to missing dependency or non-interface parameters). – Alexei Levenkov Sep 18 '16 at 01:33
  • Thanks @Alexei - I'll look into what you're alluding to. And post what I'm doing further down in the logic. – Craig Sep 18 '16 at 01:39
  • @AlexeiLevenkov - I've added the constructors now for all layers to the question. Does the error indicate that while trying to resolve the Service class, it failed on one of the constructors below it? – Craig Sep 18 '16 at 02:52
  • I've posted answer as based on your update it is the case - UserLogic can't be resolved. – Alexei Levenkov Sep 18 '16 at 04:19

2 Answers2

1

You should register container in the Global.asax.cs

    public class Global : HttpApplication
    {
        private void Application_Start(object sender, EventArgs e)
        {
            IUnityContainer container = new UnityContainer();
            container.RegisterType<IUserService, UserService>();
            container.RegisterType<IUserLogic, UserLogic>();

            UnityDependencyResolver dependencyResolver = new UnityDependencyResolver(container);
            GlobalConfiguration.Configuration.DependencyResolver = dependencyResolver;
            DependencyResolver.SetResolver(dependencyResolver);
        }
    }
bbonch
  • 534
  • 1
  • 5
  • 12
  • Thanks. Will make that change. Can I still ref reference "container" from my controller? And all other controllers? – Craig Sep 18 '16 at 01:31
  • 1
    While good suggestion for general program organization this has nothing to do with question - would be fine as comment pointing to one of many examples of your suggestion. – Alexei Levenkov Sep 18 '16 at 01:34
  • Now my Global.asax file needs reference to all my layers. Is that right? – Craig Sep 18 '16 at 03:18
  • @Craig: "Can I still ref reference "container" from my controller? And all other controllers?". You should *absolutely not* reference the controller from anywhere in the application but the [start up path](http://blog.ploeh.dk/2015/01/06/composition-root-reuse/). This is a [bad practice](http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/). – Steven Sep 18 '16 at 06:32
  • Thanks @Steven - So the container shouldn't be in the global.asax? Where should the container reside? – Craig Sep 18 '16 at 07:51
  • @Craig the global.asax is *exactly* where your container should be. The global.asax is the startup path. – Steven Sep 18 '16 at 08:05
  • Thanks @Steven - I'm just not sure how my controllers, then, would be able to access the container object. – Craig Sep 18 '16 at 09:36
  • @Craig that's the whole idea of Dependency Injection. They never access the container. They should get all the dependencies they need through their consrructor. – Steven Sep 18 '16 at 10:24
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/123632/discussion-between-craig-and-steven). – Craig Sep 18 '16 at 10:57
  • @bbonch - I'm trying this - but in the global file, I get a type or namespace issue on "UnityDependencyResolver" and "GlobalConfiguration". Is there a nuget package or reference I need for these? – Craig Sep 18 '16 at 22:25
1

UserLogic(IData data, ILog logger) - neither IData nor ILog shown as registered in container - so if code is exactly like you have in the post it is the reason why IUserLogic can't be resolved when unity tries to pass argument to UserService(IUserLogic) constructor.

Fix: register all dependencies (recursively)

To achieve that consider:

  • make sure types with no dependencies has constructors without arguments
  • register instances instead of types - if that works for your system
  • make constructors depend on concrete types (as all concrete types by default registered with Unity) - not testable choice...
  • provide parameters for all non-interface/non class arguments like int/string (How resolve a dependency with unity passing arguments in the constructor?)
Community
  • 1
  • 1
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • Perfect. That was the solution. But now I'm not sure where my Container should be. Moving it out of the controller sounds like the right thing (Or else all controllers need to create a container). It sounds like it shouldn't be in the Global.ascx either, and even if it is, I can't reference it. – Craig Sep 18 '16 at 07:50
  • @Craig here is a guide - http://weblogs.asp.net/shijuvarghese/asp-net-mvc-tip-dependency-injection-with-unity-application-block (it is a bit old, but basics are still true, registration of controller factory is simpler now as shown in bbonch's answer) – Alexei Levenkov Sep 19 '16 at 05:30