Unity Framework IoC with default constructor
Asked Answered
E

2

9

I'm trying to inject a dependency to my MVC controllers like this

private static void RegisterContainer(IUnityContainer container)
{            
    container
        .RegisterType<IUserService, UserService>()
        .RegisterType<IFacebookService, FacebookService>();
}

The UserService class has a constructor like this...

public UserService(): this(new UserRepository(), new FacebookService())
{
    //this a parameterless constructor... why doesnt it get picked up by unity?
}

public UserService(IUserRepository repository, IFacebookService facebook_service)
{
    Repository=repository;
    this.FacebookService=facebook_service;
}

The exception I am getting is the following...

The current type, Repositories.IUserRepository, is an interface and cannot be constructed. Are you missing a type mapping?

It looks like it's trying to inject a constructor into the service, but the default would suffice? Why is it not mapping to the parameterless constructor?

Enclose answered 15/9, 2010 at 2:57 Comment(1)
What are Repository and this.FacebookService?Vilipend
D
25

The Unity default convention (which is pretty clearly spelled out in the documentation) is to choose the constructor with the most parameters. You can't just make a blanket statement that "it's not true that IoC will find the most specific constructor , if you don't specify the constructor parameters while registering a type , it will automatically call default constructor." Each container implementation can and does have different defaults.

In Unity's case, like I said, it will choose the constructor with the most parameters. If there are two that have the most parameters, then it'll be ambiguous and throw. If you want something different, you must configure the container to do that.

Your choices are:

Put the [InjectionConstructor] attribute on the constructor you want called (not recommended, but quick and easy).

Using the API:

container.RegisterType<UserService>(new InjectionConstructor());  

Using XML config:

<container>
  <register type="UserService">
    <constructor />
  </register>
</container>
Decare answered 15/9, 2010 at 21:34 Comment(3)
What a pity even outdated Windsor Castle chooses best matched constructor and Unity still cannot.Yadirayaeger
It was a deliberate tradeoff. Unity can resolve concrete types that aren't registered with the container, Windsor cannot that I know of. This makes "best matched" really ambiguous, so we went with a more deterministic default.Decare
Thanks for clarification. I see my comment contains unnecessary strong argument. That should be "Unit does not auto select constructor" instead of "cannot" :) Looks like they chose other path by design decision as well https://mcmap.net/q/706102/-resolving-classes-without-registering-them-using-castle-windsor Anyway I am happy with Unity and with it's flexibility.Yadirayaeger
E
0

I can't speak to Unity specifically, but IoC containers will generally try to use the most specific constructor they can find because it's a constructor.

If there's a constructor that takes two dependencies for injection, then presumably they are required for using the object; the default constructor will have to do something to fulfill them if the container calls it. The container's job is to fulfill dependencies, so why would it leave it up to the class to do that if it were not instructed to leave it up to the class?

To your specific question, according to your code:

private static void RegisterContainer(IUnityContainer container)
{            
    container
        .RegisterType<IUserService, UserService>()
        .RegisterType<IFacebookService, FacebookService>();
}

IUserRepository is not registered. Add a line like

.RegisterType<IUserRepository, UserRepository>()
Elbe answered 15/9, 2010 at 3:32 Comment(4)
it's not true that IoC will find the most specific constructor , if you don't specify the constructor parameters while registering a type , it will automatically call default constructor.Polyvinyl
I don't know which containers you've used, but I almost never specify constructors in my mappings. I know for sure that StructureMap will prefer a more fulfilling constructor to the default constructor - I'm using it in my current project, and that's how I unit test some of the objects that have to have a default constructor (WCF Services, for example). I'm pretty sure that Castle Windsor will also prefer a more specific constructor.Elbe
@saurabh In my experience with Unity, when no parameters are specified the most specific constructor is used.Kleptomania
In Unity , new can specify Injection Parameters.Which will be injected while construction so if you have a class which is having a parameter in a ctor, you can specify while registering types.Polyvinyl

© 2022 - 2024 — McMap. All rights reserved.