2

I'm looking for ways of getting rid of Windsor Xml configuration files. I want to leave only necessary settings (mostly strings) and move them to AppSettings.

Is there a good way to do it? Preferably without manual mapping between AppSettings and dependencies (ctor params).

I don't mind implementing something for this to happen but I want to minimize boilerplate code of the actual business-problem-solving application.

Kostassoid
  • 1,870
  • 2
  • 20
  • 29

3 Answers3

6

You can configure dependency on AppSettings.

Aleš Roubíček
  • 5,198
  • 27
  • 29
  • Thanks, I was kind of looking for this one. But @Bronumski idea provides even a better solution (in my case). – Kostassoid Jun 09 '12 at 11:10
  • 1
    This is cool too, not come across this before. @Kostassoid I cant take credit for the code though :) – Bronumski Jun 11 '12 at 09:17
3

Using a sub dependency resolver to inject the values

After your comment about not wanting to inject a configuration object I started to have a look at some of my SubDependancyResolvers and on the off chance I googled how to get the property name in the SubDependancyResolver and I came across an actual implementation. The project is at mausch and consits of "Miscellaneous experiments and other yerbas". I cannot verify the code works but it follows how my resolvers work.

Their implementation consists of an attribute that you apply to a settings class that maps the app settings in the config to the settings properties. An alternative would be to have an attribute that you apply to the property you want to inject into the constructor and do away with the settings class all together:

public class AppSettingsAttribute: Attribute {}

public class AppSettingsResolver : ISubDependencyResolver
{
private readonly IKernel kernel;

public AppSettingsResolver(IKernel kernel)
{
    this.kernel = kernel;
}

public object Resolve( CreationContext context, ISubDependencyResolver contextHandlerResolver, Castle.Core.ComponentModel model, DependencyModel dependency )
{
    if( (
        from constructor in model.Constructors
        from dependencyModel in constructor.Dependencies
        where dependencyModel == dependency

        from parameterInfo in constructor.Constructor.GetParameters()
        select parameterInfo ).Any( parameterInfo => parameterInfo.Name == dependency.DependencyKey ) )
    {
        var converter = (IConversionManager) kernel.GetSubSystem(SubSystemConstants.ConversionManagerKey);

        return converter.PerformConversion(ConfigurationManager.AppSettings[dependency.DependencyKey], dependency.TargetType);
    }
    return null;
}

public bool CanResolve( CreationContext context, ISubDependencyResolver contextHandlerResolver, Castle.Core.ComponentModel model, DependencyModel dependency )
{
    return (
        from constructor in model.Constructors
        from dependencyModel in constructor.Dependencies
        where dependencyModel == dependency

        from parameterInfo in constructor.Constructor.GetParameters()
        where parameterInfo.Name == dependency.DependencyKey
        select ( Attribute.GetCustomAttribute( parameterInfo, typeof(AppSettingsAttribute) ) != null ) 
    ).FirstOrDefault();
}
}

[ TestFixture ]
public class When_resolving_dependancies_from_the_app_settings_configuration_section
{
    [ Test ]
    public void Should_resolve_a_string_and_an_int()
    {
        var container = new WindsorContainer();

        container.Kernel.Resolver.AddSubResolver(new AppSettingsResolver( container.Kernel ));
        container.Register( Component.For<Dependent>() );

        var dependent = container.Resolve<Dependent>();

        dependent.Foo.Should().Be( "bar" );

        dependent.Baz.Should().Be( 1 );
    }

    public class Dependent
    {
        public string Foo { get; private set; }
        public int Baz { get; private set; }

        public Dependent([AppSettings]string foo, [AppSettings]int baz)
        {
            Foo = foo;
            Baz = baz;
        }
    }
}
Bronumski
  • 14,009
  • 6
  • 49
  • 77
  • 2
    I'm the author of this code. Here's an earlier question about the same thing: http://stackoverflow.com/questions/244935/inject-app-settings-using-windsor . Here's my blog post about it: http://bugsquash.blogspot.com/2008/09/changing-windsor-components.html – Mauricio Scheffer Jun 08 '12 at 17:22
  • Excellent! I don't think using attribute is a good idea but this technique will allow me to write really sweet resolver which will cover all my needs. Thanks! – Kostassoid Jun 09 '12 at 11:13
  • @Kostassoid Had a go at implementing the sub dependency resolver so that it injects the properties straight into the class without the need for a middle class. I have updated the answer with my implementation. – Bronumski Jun 12 '12 at 12:02
  • @Bronumski thanks for the update, interesting! currently i ended up with somewhat different approach, which allows not only to inject value types but implementations too: https://github.com/Kostassoid/Anodyne/blob/master/src/main/Anodyne-Windsor/AppSettingsResolver.cs – Kostassoid Jun 12 '12 at 23:06
0

Using property injection with specific configuration classes

Create an interface for your configuration and then have an implementation that wraps up the ConfigurationManager.AppSettings which you inject it into Windsor as a dependancy.

class SomeThingDependentOnSomeConfiguration
{
    public SomeThingDependentOnSomeConfiguration(ISomeConfiguration config) { ... }
}

interface ISomeConfiguration
{
    int SomeValue { get; }
    string AnotherValue { get; }
}

class SomeConfigurationAppSettings : ISomeConfiguration
{
    public int SomeValue
    {
        get
        {
            return Convert.ToInt32(ConfigurationManager.AppSettings["SomeValue"]);
        }
    }

    public string AnotherValue
    {
        get
        {
            return ConfigurationManager.AppSettings["AnotherValue"];
        }
    }
}

This allows you later on to introduce a ConfigurationSection (which IMO is much cleaner than the app settings) or you could replace it with a class that uses hard coded values if that is what you need.

class SomeConfigurationConfigurationSections : ConfigurationSection, ISomeConfiguration
{
    [ConfigurationProperty("SomeValue")]
    public int SomeValue
    {
        get { return (int)this["SomeValue"]; }
    }

    [ConfigurationProperty("AnotherValue")]
    public string AnotherValue
    {
        get { return (string)this["AnotherValue"]; }
    }
}
Bronumski
  • 14,009
  • 6
  • 49
  • 77
  • This is straightforward, but exactly what i wanted to avoid, so much code for getting two values. A key idea is that these value have to be injected so i was hoping (and still am) for some elegant shortcut. Perhaps using DictionaryAdapterFactory or something similar. – Kostassoid Jun 08 '12 at 14:00
  • @Kostassoid You could use a SubDependancy resolver, I'll have a quick think and put up some pseudo code. – Bronumski Jun 08 '12 at 14:51
  • @Kostassoid I have added an alternative answer. I am going to leave this one here as it is still a viable solution for someone else wanting to solve the same problem. – Bronumski Jun 08 '12 at 15:46