26

I'm new to Autofac (not to DI). Here is the situation:

I have these interfaces:

public interface IQuery<out TResult> : IQuery { }

public interface IQueryHandler<in TQuery, out TResult> where TQuery : IQuery<TResult> {
    TResult Handle(TQuery query);
}

and there is a lot of implementation of them in my solution:

class GetPersonQuery : IQuery<PersonModel> { }
class GetPersonQueryHandler : IQueryHandler<GetPersonQuery, PersonModel> { }

class GetArticleQuery : IQuery<ArticleModel> { }
class GetArticleQueryHandler : IQueryHandler<GetArticleQuery, ArticleModel> { }

class GetSomethingQuery : IQuery<IEnumerable<SomeModel>> { }
class GetSomethingQueryHandler : IQueryHandler<GetSomethingQuery, IEnumerable<SomeModel>> { }

and so on. I'm currently registering them like this:

builder.RegisterType<GetPersonQueryHandler>()
    .As<IQueryHandler<GetPersonQuery, PersonModel>>();

builder.RegisterType<GetArticleQueryHandler>()
    .As<IQueryHandler<GetArticleQuery, ArticleModel>>();

builder.RegisterType<GetSomethingQueryHandler>()
    .As<IQueryHandler<GetSomethingQuery, SomeModel>>();

// blah blah blah

As you can see, I have a many same registrations. In SimpleInjector (which I was using before), I could register all of them by a single line:

container.RegisterManyForOpenGeneric(
    typeof(IQueryHandler<,>),
    AppDomain.CurrentDomain.GetAssemblies());

Is it possible to do this stuff in Autofac?

amiry jd
  • 27,021
  • 30
  • 116
  • 215
  • 1
    Sorry ): I'm working with @Javad_Amiry's team (Kavand). That is because of the problem Javad_Amiry asked before (here and on codeplex). Unfortunately in this project we cannot use simple injector. But our main DI lib still is SimpleInjector. We used it in many projects and we'll continue using it. :) – amiry jd May 29 '13 at 12:55

2 Answers2

44

You can do this with Autofac you just need to use the scanning feature and use the AsClosedTypesOf method:

AsClosedTypesOf(open) - register types that are assignable to a closed instance of the open generic type.

So your registration will look like this:

builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
       .AsClosedTypesOf(typeof (IQueryHandler<,>)).AsImplementedInterfaces();
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
nemesv
  • 138,284
  • 16
  • 416
  • 359
  • Do u need the AsImplementedInterfaces call or does AsClosedTypes register the type is the closed type u passed it? – Sam Jul 05 '14 at 06:05
  • 4
    @Sam if you want to resolve with the iterface type e.g with `IQueryHandler` then you need the `AsImplementedInterfaces` because the default registration method is `AsSelf`. – nemesv Jul 05 '14 at 07:44
  • 3
    The behaviour I have seen (meaning I tried it out) is I didn't need the AsImplementedInterfaces. This is because the AsClosedTypes method appears to perform that task for you which makes sense as it has the As prefix. So to be clear I have registered like above without AsImplementedInterfaces and I can ask the container for the closed interface and it all works (using latest Autofac if that matters). – Sam Jul 07 '14 at 06:50
  • 1
    @Sam The difference is that if you use `AsImplementedInterfaces()` then it will *also* register against **all** its public interfaces, not just `IQueryHandler<>`. You can check this by looking at the `ComponentRegistry` on the container after you call Build(). So in your case you are correct, `AsImplementedInterfaces()` is not required. – Simon Brangwin Mar 18 '15 at 21:48
2

If you have a single concrete generic type, and don't want the scanning overhead and improve the startup performance, you can register as below:

builder.RegisterGeneric(typeof(ConcreteGenericType<>)).As(typeof(IServiceType<>);
zafar
  • 1,965
  • 1
  • 15
  • 14