Resolving Interface with generic type constraint with Castle Windsor

1k views Asked by At

Given the interface where FooRequest and FooResponse are abstract:

 public interface IFooHandler<TRequest, TResponse> where TRequest : FooRequest where TResponse : FooResponse
{
    TResponse CheckFoo(TRequest request);
}

An implementation of:

public class MyFooHandler :  IFooHandler<MyFooRequest, MyFooResponse>
{
    public MyFooResponse CheckFoo(MyFooRequest request)
    {
        /* check for foos */
    }
}

How would I register this in Castle Windsor so I can resolve it using (where IoCContainer is a WindsorContainer:

Global.IoCContainer.Resolve<IFooHandler<FooRequest, FooResponse>>();

to resolve an instance of MyFooHandler?

2

There are 2 answers

0
Ognyan Dimitrov On BEST ANSWER

In Castle Windsor you can use such code :

public void Install(IWindsorContainer container, IConfigurationStore store)
{
    container.Register(
    Component.For(typeof(IRepository<>)).ImplementedBy(typeof(Repository<>))
}
);

public class Repository<T> : IRepository<T> where T : class, IEntity
{
...
}

Therefore I find registering and resolving generics pretty simple for registering and resolving generics with interfaces. There a lots of questions on castle and generics around.

0
Ric .Net On

I'm not familiar with Castle & Windsor but I'm pretty sure this is a use case which is not supported by this DI container.

As far as I know Simple Injector is the only container out there which completely honours generic type constraints out-of-the-box on 99.9% of the possibilities. Autofac is also aware of generic type constraints but it is easy to create a type constraint which compiles but breaks at runtime with Autofac.

Generics are fun to work with in all cases but especially when you use Simple Injector as your container of choice, IMO. The documentation for using generics can be found here.

Because you're using generics I expect you have many closed implementations of your IFooHandler<TRequest,TResponse> interface. Registering all these implementations is a one liner with Simple Injector:

var container = new Container();
container.RegisterManyForOpenGeneric(typeof(IFooHandler<,>)
                                        , Assembly.GetExecutingAssembly());

// resolve:
container.GetInstance<IFooHandler<FooRequest, FooResponse>>();

There are numerous advanced options, which you can use to greatly improve the 'SOLIDness' of your application. These can all be found in the documentation.

There is one specific one I want to mention: By registering a open generic decorator, Simple Injector is capable of retrieving instances which are decorated with this (or more) decorators. This feature makes it super easy to stick to SOLID design and still implement the most advanced scenarios and/or cross cutting concerns. Note that even in this scenario Simple Injector will look at and act accordingly to the generic type constraints and the different decorators.