Saturday, March 17, 2012

Dependency injection – Auto registration in Unity


Unity Auto Registration extends Unity IoC container and provides fluent syntax to configure rules for automatic type registration. You can add Unity Auto Registration package using NuGet package manager.



Using few code lines you can scan specified assemblies and register all types that satisfy the rules. Rules for determining whether to include/exclude type/assembly are predicates so you can use lambda syntax to specify them or direct method name. For e.g. you can register interfaces, using AsFirstInterfaceOfType() which will throw an exception if more than one interface is found on a type.  You can also use decorated attributes type to register types to the container.
For e.g. All my repositories that implement the type
public interface IRepository
{
    IEnumerable All();
    T One(Funcbool> condition);
    IEnumerable All(Funcbool> condition);
    void Add(T entity);
    void Save(T entity);
    void Remove(T entity);

    HashSet Context { get; }
}
public class CustomerRepository : BaseRepository<Customer>
{
    //Implementation methods
}
Can be registered as
_container = new UnityContainer();
_container.ConfigureAutoRegistration()
    .LoadAssembliesFrom(RegistrationAssemblies.AssemblyNames)
    .Include(r => r.ImplementsOpenGeneric(typeof(IRepository<>)), Then.Register().AsFirstInterfaceOfType())
    .ApplyAutoRegistration();
Where RegistrationAssemblies.AssemblyNames is a string array of the assemblies to look for types to register.
You can also decorate the types with a common attribute to register types. For e.g. the business logic components in this sample is decorated with the attribute [Logic] as given below

[Logic]
public class CustomerLogic : ICustomerLogic
{
    public IEnumerable<Customer> GetAllByName(string name)
    {
        var repository = IoC.Container.Resolve<IRepository<Customer>>();
        return repository.All(c => c.Name.StartsWith(name));
    }
}
These types can be registered using the DecoratedWith method as given below.
_container = new UnityContainer();
_container.ConfigureAutoRegistration()
    .LoadAssembliesFrom(RegistrationAssemblies.AssemblyNames)
    .Include(r => r.ImplementsOpenGeneric(typeof(IRepository<>)), Then.Register().AsFirstInterfaceOfType())
    .Include(If.DecoratedWith<Logic>, Then.Register().AsFirstInterfaceOfType())
    .ApplyAutoRegistration();

2 comments:

Unknown said...

This is a brilliant extension, thanks! Using it to run through the Modules directory accessed by my bootstrapper and register all my View/Viewmodel types to specific interfaces.

A couple of questions:
1) How does your code define "FirstInterfaceOfType". Is it the first one applied in code to this class directly?

Example:
ViewModelBase implements IViewModelBase
XXXViewModel inherits ViewModelBase
Implements IXXXViewModel
IXXXViewModel inherits IViewModelBase

If I autoregister XXXViewModelBase AsFirstInstanceOfType, will I get IViewModelBase or IXXXViewModel?

2) Is there a way to combine As(Of X) with a name?

That's all! Thanks again!
Rich

Unknown said...

Hi again.

I think I've found a bug in the Then.Register.Interfaces property - I get a Null reference error on the property getter. It seems like every time I evaluate it. I'd be happy to fix this myself if the code's available for this, If not, I'd appreciate a fix so I can use it! :)

I am trying to register another container extension automatically at the same time as I register the type, so trying to access Interfaces for that purpose.

Thanks,
Rich