Search code examples
c#asp.net-mvcdependency-injectionunity-container

How to register multiple classes that implements the same interface to UnityContainer?


I am trying to setup IoC container in my Asp.Net MVC 5 application so I can access these objects anywhere in my application.

I choose to use Unity.Mvc container for the job.

I want to use reflection or some other technique to auto register any class in my assemblies that implements an interface called IRunOnEachRequest.

Here is what I did

I created the following interfaces

public interface IRunTask
{
    void Run();
}

public interface IRunAfterEachRequest : IRunTask
{
}

public interface IRunOnEachRequest : IRunTask
{
}

Then in the UnityConfig.RegisterTypes method, I am trying to do the following

var assemnlies = AppDomain.CurrentDomain.GetAssemblies().ToList();

foreach (Assembly assembly in assemnlies)
{
    try
    {
        var tasks = assembly.GetTypes().Where(x => x.IsClass && typeof(IRunTask).IsAssignableFrom(x)).ToList();

        foreach (Type task in tasks)
        {

            if (typeof(IRunAfterEachRequest).IsAssignableFrom(task))
            {
                //container.RegisterType<IRunAfterEachRequest, typeof(task)>();
            }
            else if (typeof(IRunOnEachRequest).IsAssignableFrom(task))
            {
                //container.RegisterType<IRunOnEachRequest, typeof(task)>();
            }
        }
    }
    catch
    {

    }
}

But the line container.RegisterType<IRunAfterEachRequest, typeof(task)>(); is giving me error.

Questions

  • Is there a better more elegant want into registering multiple types in UnityContainer?
  • Is there a way to auto register using a default convention? For Example, if I have an interface called IUnitOfWork and implementation called UnitOfWork in current assembly "same name without the I then register them into the container automatically.

Solution

  • The trick is to register them by name:

    public interface IRunTask
    {
        void Run();
    }
    
    public class RunTask1 : IRunTask { public void Run() { } }
    public class RunTask2 : IRunTask { public void Run() { } }
    public class RunTask3 : IRunTask { public void Run() { } }
    

    Execution code:

    var ctr = new UnityContainer();
    var taskTypes = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.IsClass && typeof(IRunTask).IsAssignableFrom(x)).ToList();
    
    // Register from IRunTask to T using T.Name as a unique key for the name. You can add additional params like a lifetimemanager etc.
    taskTypes.ForEach(t => ctr.RegisterType(typeof(IRunTask), t, t.Name));
    var tasks = ctr.ResolveAll<IRunTask>().ToList(); // RT1, RT2, RT3
    tasks.ForEach(t => t.Run());
    

    Is there a better more elegant want into registering multiple types in UnityContainer?

    I prefer to register via a config file and I never used Unity for Resolving multiple types that have the same interface (I've done this in the past using MEF which I have no idea if it's still popular for resolving plugins).

    Is there a way to auto register using a default convention? For Example, if I have an interface called IUnitOfWork and implementation called UnitOfWork in current assembly "same name without the I then register them into the container automatically.

    I'm not sure, but I think you are missing something here. The whole purpose of IOC is to create more than one type (could be a mock for a unit test, a behavior or a multi-tenant plugin). I wouldn't want my app to auto register types.
    If you still insist, you can create a default attribute and simply write some reflection code that will auto register types.