NooBody
NooBody

Reputation: 21

Resolving multiple implementations with property injection of optional dependencies

Today i came across a seemingly strange issue regarding resolving multiple implementations of a type in combination with property injection of a optional dependency, in my case a logger instance.

I am using Unity 2.1 and UnityConfiguration in order to realize convention-based configuration.

I am using the SetAllPropertiesConvention in order to inject an implementation of ILogger into many of my types.

If i'm resolving a single implementation using for example container.Resolve<IProcessor>() the instance of ILogger is properly injected.

However, if i'm resolving multiple instances of that type using container.ResolveAll<IProcessor>() the property remains null.

Here my registration code:

container.RegisterInstance(typeof (ILogger), LoggerService.GetLogger());
container.Configure(c => c.Scan(scan =>
                    {
                        scan.AssembliesInBaseDirectory(a => a.FullName.StartsWith("My.Company"));
                        scan.InternalTypes();
                        scan.With<AddAllConvention>().TypesImplementing<IFetchDataCommand>();
                        scan.With<AddAllConvention>().TypesImplementing<IPrintConverter>();
                        scan.With<SetAllPropertiesConvention>().OfType<ILogger>();
                    }));

SetAllPropertiesConvention itself uses the following code to register the logger es property injected:

IEnumerable<PropertyInfo> properties =
                type.GetProperties().Where(p => p.CanWrite && p.PropertyType == interfaceType);

foreach (PropertyInfo property in properties)
{
    registry.Register(null, type).WithInjectionMembers(new InjectionProperty(property.Name));
}

Is this a bug, or did i something wrong. Any ideas?

Upvotes: 1

Views: 979

Answers (1)

Jevgenij Nekrasov
Jevgenij Nekrasov

Reputation: 2760

If you are using RegisterType<T, U>() method to register your dependencies without any parameters you won't register different implementations. You need to provide named registrations, like this:

RegisterType<IProcessor, MyProcessor1>("MyProcessor1")
RegisterType<IProcessor, MyProcessor2>("MyProcessor2")

ResolveAll() does not include mapping without name.

EDIT:

Not sure why you cannot configure property injection using convention, but you can set it after type is building up. Something like this:

    var container = new UnityContainer();
    container.RegisterInstance(typeof (ILogger), new Logger());

    container.Configure(x => 
        {
            x.AfterBuildingUp<IFetchDataCommand>().Call((c,s) => s.Logger = c.Resolve<ILogger>());
            x.Scan(
                scan =>
                    {
                        scan.Assembly(Assembly.GetExecutingAssembly());
                        scan.InternalTypes();
                        scan.With<AddAllConvention>().TypesImplementing<IFetchDataCommand>();
                        scan.WithSetAllPropertiesConvention().OfType<ILogger>();
                    });
        });

    var dataCommand = container.ResolveAll<IFetchDataCommand>().ToArray();

    Assert.That(dataCommand[0].Logger, Is.Not.Null);
    Assert.That(dataCommand[1].Logger, Is.Not.Null);

This line is important :

x.AfterBuildingUp<IFetchDataCommand>().Call((c,s) => s.Logger = c.Resolve<ILogger>());

And my classes:

public interface IDataCommand
{
    ILogger Logger { get; set; }
}

public class Logger : ILogger
{
    public string Name { get; set; }
}

public class FetchDataCommand : IDataCommand
{
    public ILogger Logger { get; set; }
}

public class StoreDataCommand : IDataCommand
{
    public ILogger Logger { get; set; }
}

Upvotes: 1

Related Questions