Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Property Dependency Injection used in Constructor using Unity

Ok, I have a dependent property defined in a base class and I'm trying to use it inside of the constructor of its derived class but that does not work, the property appears as null. Unity resolves the dependent property AFTER resolving an instance with container.Resolve();

One alternative I have is to add a IUnityContainer parameter to my MyViewModel class constructor and set the ILogger property my self with something like:

public MyViewModel(IUnityContainer container)
{
  Logger = container.Resolve<ILogger>();
}

EDIT: Another suggestion by @Wiktor_Zychla is to pass a constructor-injected parameter as:

public MyViewModel(ILogger _logger)
{
    Logger = _logger;
}

This seems to work fine, but I would have to do that for all my derived ViewModels..

But then I'm not using the annotated ILogger dependency in my base class. See my class samples below. The question is: Which alternatives do I have, or what am I doing wrong?

Thanks!

I have a ViewModel base class like this:

public abstract class ViewModelBase
{
    [Dependency]
    public ILogger Logger { get; set; }
....
}

Then I have a class deriving that:

public class MyViewModel : ViewModelBase
{
    public MyViewModel()
    {
         //I want to use my dependent property in constructor, but doesn't 

         Logger.Error("PRINT AN ERROR");
    }
}

And in my application entry point I am registering my ILogger as a singleton and my MyViewModel class:

container.RegisterType<ILogger, MyAppLogger>(new ContainerControlledLifetimeManager());
container.RegisterType<MyViewModel>();
like image 699
Adolfo Perez Avatar asked Jun 20 '12 18:06

Adolfo Perez


2 Answers

Unity resolves the dependent property AFTER resolving an instance with container.Resolve();

Which is quite obvious, if you think about it. Just try to do this manually. You won't succeed. To be able to inject a property, there must be an instance, and having an instance, means the constructor has been called.

Your problem is caused because you are doing too much in your constructor. From a dependency injection perspective, a constructor should do nothing more than accept its dependencies (check that they are not null), and store them in private fields. Doing anything more than this is an anti-pattern. You shouldn't have any logic in your constructor.

Having logic in constructors makes creating the object graph unreliable, while constructing object graphs should be fast and reliable.

When you follow this principle, there will not be a problem, since once you run any business logic, your class will be completely instantiated. Since the constructor should do nothing more than set private fields, nothing can go wrong and there can't be any reason to call Logger.Error("PRINT AN ERROR"); as you are doing.

like image 177
Steven Avatar answered Oct 20 '22 02:10

Steven


1) You can use a different instance of your logger in every viewmodel by simply dropping the ContainerControlledLifetimeManager.

2) You can register a different Type of logger for every viewmodel by specifying it at registration time.

container.RegisterType<ILogger, MyAppLogger>();
container.RegisterType<ILogger, MyOtherLogger>("uniqueNameOfAnILoggerRegistration);
container.RegisterType<MyViewModel>(new InjectionConstructor(
    new ResolvedParameter(typeof(ILogger), "uniqueNameOfAnILoggerRegistration")));

Using constructor injection your viewmodel will be injected with a brand new instance of MyOtherLogger.

As property injection should be reserved for "nice to have" values and your classes obviously rely on the existence of a logger I would strongly recommend to use ctor injection.

like image 36
Sebastian Weber Avatar answered Oct 20 '22 02:10

Sebastian Weber