Generic Repo DI exception

Oct 18, 2013 at 4:07 AM
Hi,

SI is throwing the following exception:
No registration for type TenantController could be found and an implicit registration could not be made. The constructor of the type TenantController contains the parameter of type IReadRepository<Tenant> with name 'readRepository' that is not registered. Please ensure IReadRepository<Tenant> is registered in the container, or change the constructor of TenantController.
My registration looks like so:
        public static void Bootstrap(Container container)
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }
            container.RegisterManyForOpenGeneric(typeof(IRepositoryQuery<>), typeof(IRepositoryQuery<>).Assembly);
            container.RegisterManyForOpenGeneric(typeof(IReadRepository<>), typeof(IReadRepository<>).Assembly);
            container.RegisterManyForOpenGeneric(typeof(IWriteRepository<>), typeof(IWriteRepository<>).Assembly);

        }
My Repos:
    public class ReadRepository<TEntity> 
        : IReadRepository<TEntity> where TEntity : class
    {

        private readonly Guid instanceId;
        private ClientManagementContext context;

        protected ReadRepository(ClientManagementContext context)
        {
...
    public class WriteRepository<TEntity> : IWriteRepository<TEntity> where TEntity : class
    {
        private readonly Guid instanceId;
        //private DbSet<TEntity> dbSet;
        private ClientManagementContext context;
        public WriteRepository(ClientManagementContext context)
        {
...
    public sealed class RepositoryQuery<TEntity> : IRepositoryQuery<TEntity> where TEntity : class
    {
        private readonly List<Expression<Func<TEntity, object>>> _includeProperties;
        private readonly ReadRepository<TEntity> _repository;
        private Expression<Func<TEntity, bool>> _filter;
        private Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> _orderByQuerable;
        private int? _page;
        private int? _pageSize;

        public RepositoryQuery(ReadRepository<TEntity> repository)
        {
            _repository = repository;
            _includeProperties = new List<Expression<Func<TEntity, object>>>();
        }
...
My MVC Controller:
    public class TenantController : Controller
    {
        public IReadRepository<Tenant> ReadRepository { get; set; }
        public IWriteRepository<Tenant> WriteRepository { get; set; }

        public TenantController(
            IReadRepository<Tenant> readRepository,
            IWriteRepository<Tenant> writeRepository)
        {
            ReadRepository = readRepository;
            WriteRepository = writeRepository;
        }
...
And finally SI MVC Init code:
    public static class SimpleInjectorInitializer
    {
        /// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
        public static void Initialize()
        {
            // Did you know the container can diagnose your configuration? Go to: http://bit.ly/YE8OJj.
            var container = new Container();
            
            InitializeContainer(container);

            container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
            
            container.RegisterMvcAttributeFilterProvider();
       
            container.Verify();
            
            DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
        }
     
        private static void InitializeContainer(Container container)
        {
            RepositoryBoostrapper.Bootstrap(container);
            BusinessLayerBootstrapper.Bootstrap(container);

            // For instance:
            // container.Register<IUserRepository, SqlUserRepository>();
        }
    }
I've tried different combinations and have had success wiring up other commands for this and other controllers with SI in the recent past (but not with these new Repos).
Coordinator
Oct 18, 2013 at 7:10 AM
You are call RegisterManyForOpenGeneric, but this method:
Registers all concrete, non-generic, publicly exposed types that are located in the given assemblies
that implement the given openGenericServiceType with a transient lifetime. ->
The implementations you want to register however are generic. What you need is to call RegisterOpenGeneric:
container.RegisterOpenGeneric(typeof(IRepositoryQuery<>), typeof(RepositoryQuery<>));
container.RegisterOpenGeneric(typeof(IReadRepository<>), typeof(ReadRepository<>));
container.RegisterOpenGeneric(typeof(IWriteRepository<>), typeof(WriteRepository<>));
Although the RegisterManyForOpenGeneric could have picked up generic types and called RegisterOpenGeneric for you (it currently only calls Register(Type, Type)), the API explicitly makes the distinction between generic and non-generic types, since generic types often need custom handling. Registering such generic type for you will often lead to unwanted registrations and by leaving out generic types, the API keeps you in control over how those generic types can be registered.
Marked as answer by dot_NET_Junkie on 2/26/2014 at 1:19 PM