Using Unity, how do you register type mappings for generics?

entity-framework repository-pattern separation-of-concerns unity-container

Question

While attempting to create a solution for the Entity Framework repository, I am having problems using Unity to register the types that include generics.

Given:

    // IRepository interface
    public interface IRepository<TEntity>
    {
        // omitted for brevity
    }

    // Repository implementation
    public class Repository<TEntity, TContext> : IRepository<TEntity>, IDisposable 
            where TEntity : class
            where TContext : DbContext
    {
        // omitted for brevity
    }

    // service layer constructor
    public MyServiceConstructor(IRepository<Account> repository)
    {
        _repository = repository;
    }

The type mapping from IRepository to Repository has to be registered. But the Unity syntax for this kind of mapping is giving me difficulties.

Without success, I have attempted the following:

container.RegisterType<IRepository<>, typeof(Repository<,>)>();
container.RegisterType<typeof(IRepository<>), Repository<,>>();

EDIT

Based on @Steven's comment, I've implemented the following:

// UnityRepository implementation   
public class UnityRepository<TEntity> : Repository<TEntity, MyDbContextEntities>
        where TEntity : class
{
    public UnityRepository() : base(new MyDbContextEntities()) { }
}

// Unity bootstrapper
container.RegisterType(typeof(IRepository<>), typeof(UnityRepository<>));
1
9
9/27/2013 4:50:55 PM

Accepted Answer

What you're attempting to accomplish is

container.RegisterType(typeof(IRepository<>), typeof(Repository<,>));

Although generally effective, this won't work in this situation because there isIRepository<TEntity> Having one general defense, andRepository<TEntity, TContext> has two, and Unity (obviously) is unable to determine which kind to substitute forTContext .

This is what you need:

container.RegisterType(
    typeof(IRepository<>),
    typeof(Repository<, MyDbContextEntities>));

In other words, you should provide theRepository<TEntity, TContext> as an open partial generic type (with one parameter filled in). Unfortunately, this is not supported by the C# compiler.

Unity, however, does not support partial open generic types, even if C# did. In actuality, the majority of IoC libraries do not support this. Additionally, in order to build the partial open generic type for the two libraries that does support it, you would still need to perform the following unpleasant task:

Type myDbContextEntitiesRepositoryType =
    typeof(Repository<,>).MakeGenericType(
        typeof(Repository<,>).GetGenericParameters().First(),
        typeof(MyDbContextEntities));

However, there is a simple workaround to make this function: establish a derived class with a single generic type:

// Special implementation inside your Composition Root
public class UnityRepository<TEntity> : Repository<TEntity, MyDbContextEntities>
        where TEntity : class
{
    public UnityRepository([dependencies]) : base([dependencies]) { }
}

This open generic type is now simple to register:

container.RegisterType(typeof(IRepository<>), typeof(UnityRepository<>));
17
9/26/2016 3:31:08 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow