Castle Windsor registering components that match the same services

506 views Asked by At

I have the following code in my MVC application which works fine.

container.Register(Component.For<CountryServiceBase>()
    .ImplementedBy<CountryService>()
    .LifestylePerWebRequest());

Castle Windsor creates a component

CountryService / CountryServiceBase

My controller gets an instantiated object here :

public class MyController : MainController
{
    public CountryServiceBase CountryService {get; set;} // instantiate by Ioc : OK

My problem is that I have a lot of classes to register. So using Castle Windsor I did the following :

container.Register(
    Types
    .FromAssemblyNamed("mynamespace")
    .BasedOn(typeof(ServiceBase<>))
    .WithService.Base()
    .LifestylePerWebRequest());

Castle Windsor creates my components

CountryService / ServiceBase<Country>
CountryServiceBase / ServiceBase<Country>

But my MVC Application awaits a CountryService / CountryServiceBase and I don't know how to specify to Castle Windsor that it can match back CountryServiceBase to CountryService as both those classes (one of them being an abstract one) inherits ServiceBase

Is it even possible ?

Note : I posted a similar question but my investigation leads to a more accurate one so I deleted the old one.

3

There are 3 answers

1
Bilel Chaouadi On

You can use reflection to get all classes inheriting from your serviceBase. You can find a the way to do this here

Then you can implement the code above to instantiate all the services.

0
Alexander Balabin On

If your CountryServiceBase class is abstract, using Classes instead of Types should help to avoid having the base class registered (see here):

Classes on the other hand pre-filters the types to only consider non-abstract classes

However it does not look like you can avoid mentioning CountryServiceBase in your registration, maybe using OrBasedOn(CountryServiceBase) then your implementation will be available as both ServiceBase<> and CountryServiceBase.

0
Ilya Palkin On

Usually services are interfaces. That's why AllInterfaces() works for others.

If you check API you'll find Select() method that can be used easily.

If none of the above options suits you you can provide your own selection logic as a delegate and pass it to WithService.Select() method.

So registration code could be the following:

    container.Register(Types.FromThisAssembly()
        .BasedOn(typeof(ServiceBase<>))
        .WithService.AllInterfaces()
        .WithService.Select((t, b) => t.BaseType != null
                ? new[] { t.BaseType }
                : new Type[0])
        .LifestylePerWebRequest());

This solution is quite quick-and-dirty but at least it solves your issue.