This project is read-only.

Registering open generic of open generic

May 2, 2013 at 12:48 AM
I'm trying to implement some generic queries following a command/query pattern. I'm able to register my other query handlers as shown below:
container.RegisterManyForOpenGeneric(typeof(IQueryHandler<,>),
    typeof(IQueryHandler<,>).Assembly);
but this does not seem to register my generic query handler, which looks like this:
public class GenericGetQueryHandler<TEntity> 
        : QueryHandlerBase, IQueryHandler<GenericGetQuery<TEntity>, IEnumerable<TEntity>>
        where TEntity : class, IEntity
    {
        public GenericGetQueryHandler(Func<IUnitOfWork> unitOfWorkFactory) : base(unitOfWorkFactory)
        {
        }

        public IEnumerable<TEntity> Handle(GenericGetQuery<TEntity> query)
        {
            var repo = UnitOfWork.GetRepository<TEntity>();
            var results = repo.GetQuery(query.Criteria);
            return results;
        }
    }
My generic query implementation looks like this:
public class GenericGetQuery<TEntity> : IQuery<IEnumerable<TEntity>> 
        where TEntity : class, IEntity
    {
        public GenericGetQuery(Expression<Func<TEntity, bool>> criteria)
        {
            Criteria = criteria;
        }

        public Expression<Func<TEntity, bool>> Criteria { get; set; }
    }
I am unable to retrieve the generic query handler using this code, so there is obviously something wrong with my registration that I suspect has something to do with the nested generic types:
var qryHandler = container.GetInstance<IQueryHandler<GenericGetQuery<Customer>, IEnumerable<Customer>>>();
At runtime, it fails with an exception from Simple Injector indicating that no registration for type IQueryHandler<GenericGetQuery<Customer>,IEnumerable<Customer>> could be found.

I've also tried some of the other registration extension methods, for generic types, but couldn't get anything to work. I'm basically trying to avoid creating a query class for each entity in my database (over 300) for the simpler select-style queries.

Any help would be greatly appreciated.
May 2, 2013 at 10:56 AM
Edited May 2, 2013 at 10:07 PM
RegisterManyForOpenGeneric is for batch-registration. What you want to do is map any open generic version of IQueryHandler<GenericGetQuery<TEntity>, IEnumerable<TEntity>> to GenericGetQueryHandler<TEntity>. For mapping open generic types, the RegisterOpenGeneric extension method is available. You can add the following registration to do your registration:
container.RegisterOpenGeneric(
    typeof(IQueryHandler<,>),
    typeof(GenericGetQueryHandler<>));
It seems however, that your GenericGetQueryHandler<T> simply directly maps to the GetQuery method of an IRepository<T>. At first glance, this looks like an extra layer of abstraction that doesn't have any extra benefits, since the consumer could as easily depend directly on the IRepository<T>. Make sure you really need this construct if all you do is mapping, because it would be harder for other developers to grasp.
Marked as answer by dot_NET_Junkie on 2/26/2014 at 1:26 PM
May 3, 2013 at 8:34 PM
That did the trick, thanks. I have other reasons why I need the extra abstraction, but your point is well taken.

Thanks very much for Simple Injector, it is a really great tool!