2

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.

Valera
  • 537
  • 7
  • 14

1 Answers1

5

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

dbones
  • 4,415
  • 3
  • 36
  • 52
  • Thank you for response. I've made some clarifications in my original question to better describe what is needed. – Valera Jul 24 '13 at 13:15
  • Way 3 :) should work, use the registration at the top. then any component which requires the concrete type will have that injected. note the settings is registered only once. – dbones Jul 25 '13 at 13:08
  • Way 3 will register all concrete `ISetting` implementations - that's true. But I need to run each of those classes through 'settingsManager.LoadSettings() where T : ISetting'. It sounds like I should utilize UsingFactoryMethod to configure each component, but I cannot come up with exact syntax. – Valera Jul 25 '13 at 13:26
  • what does LoadSettings do? it looks like it will create the instance of the class from the type. If you would like to use the registering by convention in Windsor, could you change the signature to LoadSettings(Type type)? – dbones Jul 25 '13 at 22:25
  • LoadSettings will create an instance of the class based on type - that's correct. dbones - I came to the same conclusion, that signature of LoadSettings should be changed to LoadSettings(Type type) to accommodate my scenario. – Valera Jul 29 '13 at 14:15
  • Any time you need to create an instance of a class at runtime you should use an abstract factory, you should NOT be using the concrete type, see this http://stackoverflow.com/questions/1943576/is-there-a-pattern-for-initializing-objects-created-via-a-di-container – reggaeguitar Feb 10 '16 at 20:57