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
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")));