4
votes

Hi I'm new to Castle Windsor and am struggling to understand some of the basics so I figured I post a question rather than go through the code in hopes of resolving my issue sooner.

I have a webservice that needs to pull information from the config file web.config. This information is in a custom configuration section and I am wondering how I can get that information to the class that needs it. I don’t want to tie that class to the config file as I may host this through IIS or a custom windows service. My first attempt was to do something like this:

iocCon.Register(Component.For<ErrorMessagesSection>().LifeStyle.Singleton.Instance(FindConfigSection<ErrorMessagesSection>())); 

private T FindConfigSection<T>() where T : ConfigurationSection
    {
        System.Configuration.Configuration config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("/web.config");//TODO: remove this hard coding to iis hosting  .OpenExeConfiguration(ConfigurationUserLevel.None);
        ConfigurationSectionGroupCollection sectionGroups = config.SectionGroups;

        foreach (ConfigurationSectionGroup sectionGroup in sectionGroups)
            foreach (ConfigurationSection configurationSection in sectionGroup.Sections)
                if (configurationSection.GetType() == typeof(T))
                    return (T) configurationSection;
        return null;
    }

The section can only be defined once so this basically grabs the section so it can be injected into the constructor of an error message factory class. This doesn't throw any errors however I've noticed that the section gets created twice which is causing other problems (which I should fix but...) anyway to get around this I decided I would create the single instance and register it myself so I tried:

UGLY_HACK = new ConfigFileErrorMessageManager(eMessages);
iocContationer.Register(Component.For<IErrorMessageManager>().ImplementedBy<ConfigFileErrorMessageManager>().LifeStyle.Singleton.Instance(UGLY_HACK));

That is the first registration of a just created container and it blows up with the following:

[ComponentRegistrationException: This component has already been assigned implementation xxx.ConfigFileErrorMessageManager]
Castle.MicroKernel.Registration.ComponentRegistration`1.ImplementedBy(Type type,     IGenericImplementationMatchingStrategy genericImplementationMatchingStrategy) +310

Castle.MicroKernel.Registration.ComponentRegistration`1.Instance(TService instance) +44

My first question: how is this error possible (nothing else has been registered) / or does it mean something more subtle than it seems to? Second question: what is the best practice for getting configuration info to the classes that need it (am I going about this wrong)?

Thanks for your help

1

1 Answers

5
votes

It seems like all you really would require is an adapter for ConfigurationManager that would allow you to register the configuration for the application with Windsor.

Here's an IConfigurationManager implementation with an adapter for WebConfigurationManager that would allow you to do just that.

To register it

container.Register(
    Component.For<IConfigurationManager>()
             .Instance(new WebConfigurationManagerAdapter()));

Now you can inject IConfigurationManager into components that need to access configuration.

Should you only want to inject a particular section, you could register a factory method with Windsor to retrieve the strongly typed section from the IConfigurationManager registered with the container e.g. something like

container.Register(
    Component.For<ErrorMessagesSection>()
             .UsingFactoryMethod(kernel => 
                 kernel.Resolve<IConfigurationManager>()
                       .GetSection<ErrorMessagesSection>("errorSectionName")));