Valera
Valera

Reputation: 609

Windsor Component registration based on common interface

I'm trying to register several types that share the same interface ISetting with Windsor container.

Clarification: ISetting interface doesn't require any implementation. It's only purpose is to help locate setting types within the assembly. Otherwise these setting types are not related to each other in any way, shape or form.

Normally I would create these types one-by-one with code along these lines:

var settingsManager = new SettingsManager();
var applicationSettings = settingsManager.LoadSettings<ApplicationSettings>();
var emailSettings = settingsManager.LoadSettings<EmailSettings>();

But I would like to register these components by convention, so I don't have to do it manually.

So far I have following code in one of WindsorInstallers:

    container.Register( Classes.FromAssemblyContaining<ISetting>()
                                   .BasedOn<ISetting>()
                                   ...help...
                                   );

Clarification: Setting will be used within the class as concrete type (see below)

public class Service2
{
    private readonly EmailSettings _settings;

    public Service2(EmailSettings settings)
    {
        _settings = settings;
    }

    public void Awesome()
    {
        Console.WriteLine(_settings.Value);
    }
}

My Goal: Even though I could inject all setting types into container one-by-one, I'm looking for a solution where I could locate and register all types inheriting from ISetting using one (maybe two) statements.

Upvotes: 2

Views: 2569

Answers (1)

dbones
dbones

Reputation: 4504

it depends on how you want to use it (inject it)

here's is a possible solution

container.Register(
Classes
    .FromThisAssembly()
    .BasedOn<ISettings>()
    .WithServiceSelf()  //for way 3
    .WithServiceFirstInterface() //way 1 & 2
    .Configure(c => c.Named(c.Implementation.Name)) //way 1 & 2
    );

Way 1 - resolve directly - I do not think you will be using this one

in your example you are gettings the settings directly, you can used the named parameter with the container as follows

var settings = container.Resolve<ISettings>("EmailSettings");

when resolving the settings this way we used the named parameter to select the correct implementation.

Way 2 - injection using the named parameter

in this case we have a service as follows (again guessing a possible useage)

public class Service1
{
    private readonly ISettings _emailSettings;

    public Service1(ISettings emailSettings)
    {
        _emailSettings = emailSettings;
    }

    public void Awesome()
    {
        Console.WriteLine(_emailSettings.Value);
    }
}

for this to work we need to register this type to use the named parameter with the constructor parameter, which looks like the following:

//using a named parameter
container.Register(
    Component.For<Service1>().ImplementedBy<Service1>()
    .DependsOn(Dependency.OnComponent(typeof(ISettings), "EmailSettings")));

the depends on looks for properties/ctor params to inject on. it then uses the named implementation.

way 3 - we use the direct type

this possible way assumes the service knows that it requires a concrete type, example:

public class Service2
{
    private readonly EmailSettings _settings;

    public Service2(EmailSettings settings)
    {
        _settings = settings;
    }

    public void Awesome()
    {
        Console.WriteLine(_settings.Value);
    }
}

the registration for this one is the same as usual

//using the actual type
container.Register(Component.For<Service2>().ImplementedBy<Service2>());

the key part is how you register your settings types. if I have not covered your use, please could you provide some more information.

hope this helps

Upvotes: 5

Related Questions