Unity Configuration using multiple config files

Mar 3, 2008 at 5:14 AM
Is there a way to configure a container in multiple configuration files? For instance, I want to register types for a container in a web.config file located at the root & also register types for the same container in the web.config file of sub-folders. When I try to do this I get a ConfigurationError stating that the entry for the container has already been added.
Mar 3, 2008 at 5:37 AM
I was using David Hayden's example to configure my web app's container:
http://www.pnpguidance.net/Post/UnityIoCDependencyInjectionASPNETModelViewPresenter.aspx

In his example, he configures his web app's unity container with the default UnityContainerElement. I got around my issue by using different container names in each configuration file & iterating through the UnityContainerElements & calling Configure using my web app's single UnityContainer. Does any-1 see any issue with this? Can any-1 suggest a better way of achieving what I want to do?

I changed the InitializeContainer method to this:

private static void InitializeContainer()
{
if (_container == null)
_container = new UnityContainer();

UnityConfigurationSection section = (UnityConfigurationSection)
ConfigurationManager.GetSection("unity");

foreach (UnityContainerElement element in section.Containers)
{
element.Configure(_container);
}
}
Mar 3, 2008 at 5:53 AM
Something like that was what I was going to suggest. I don't see any issues; it fits in with the design just fine.

The only gotcha I can see is if you've got different mappings for the same type/name pairs in different files, the last one in wins. But that shouldn't be much of an issue in practice I would think.

-Chris
Mar 3, 2008 at 1:47 PM
You could also create sub-containers for each folder configuration. That obviously implies your presenters have some knowledge of their context but it would eliminate duplicate type/name combinations. It would also allow child sections to override elements if need be.

-Dan
Mar 3, 2008 at 9:27 PM
That piece of code I modified didn't do the trick. It only grabs the config section for the directory of the first page you visit when the application starts & it's parent directories. What I needed was code that grabbed the config sections for the root directory & all its sub directories. I remembered seeing code like this in the WCSF contrib for parsing module configuration (WebConfigModuleInfoStore):

http://www.codeplex.com/wcsfcontrib/SourceControl/ListDownloadableCommits.aspx

Here's that code adapted ("copied, pasted & renamed") to configure using unity configuration:

private static void InitializeContainer()
{
if (_container == null)
_container = new UnityContainer();

IUnityConfigurator configurator = new WebConfigUnityConfigurator();
configurator.Configure(_container);
}

public interface IUnityConfigurator
{
/// <summary>
/// Configures a unity container
/// </summary>
void Configure(IUnityContainer container);
}

//Adapted from WCSF Contrib's WebConfigModuleInfoStore
public class WebConfigUnityConfigurator : IUnityConfigurator
{
#region Private Fields

private readonly string _baseDirectory;

#endregion

#region Constructors

/// <summary>
/// Initializes a new instance of <see cref="WebConfigUnityConfigurator"/>.
/// </summary>
public WebConfigUnityConfigurator()
: this(String.Empty)
{
}

/// <summary>
/// Initializes a new instance of <see cref="WebConfigUnityConfigurator"/>.
/// </summary>
/// <param name="baseDirectory">The directory from which to start searching for the
/// configuration files.</param>
public WebConfigUnityConfigurator(string baseDirectory)
{
_baseDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, baseDirectory);
}

#endregion

#region IUnityConfigurator Members

/// <summary>
/// Configures a unity container
/// </summary>
public void Configure(IUnityContainer container)
{
Configure(container, _baseDirectory);
}

#endregion

#region Private Methods

private static void Configure(IUnityContainer container, string rootDirectory)
{
foreach (string fileName in Directory.GetFiles(rootDirectory, "Web.Config", SearchOption.TopDirectoryOnly))
{
Configuration configuration = GetConfiguration(Path.Combine(rootDirectory, fileName));

UnityConfigurationSection localSection = (UnityConfigurationSection)configuration.GetSection("unity");

if (localSection != null)
{
foreach (UnityContainerElement element in localSection.Containers)
{
element.Configure(container);
}
}
}
foreach (string childDirectory in Directory.GetDirectories(rootDirectory))
{
Configure(container, childDirectory);
}
}

private static Configuration GetConfiguration(string configFilePath)
{
System.Configuration.Configuration configuration;
System.Web.HttpContext context = System.Web.HttpContext.Current;
if (context == null)
{
configuration = GetConfigurationForCustomFile(configFilePath);
}
else
{
configuration = WebConfigurationManager.OpenWebConfiguration(context.Request.ApplicationPath + "/" + configFilePath.Replace(context.Request.PhysicalApplicationPath, ""));
}
return configuration;
}

private static Configuration GetConfigurationForCustomFile(string fileName)
{
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = fileName;
File.SetAttributes(fileMap.ExeConfigFilename, FileAttributes.Normal);
return ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
}

#endregion
}
May 20, 2010 at 9:25 AM

i am trying to solve the exact problem. can someone post what their config file looks like now that the unity configuration is split into several files?

May 30, 2010 at 10:26 PM

Me too!! Please post a complete sample for newbies

Jun 24, 2010 at 8:55 PM
Edited Jun 24, 2010 at 9:08 PM
I was able to get this working. You have to divide your configurations by dependency on other configurations, and load them in the reverse order. For instance, if you had configuration files for city, county, state, you would load them in that same order, then tie together the objects with a root-level unity.config file. For this example, I'm assuming that each configuration file contains: {code:html} <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> </configSections> {code:html} Here's the code to load it: {code:c#} public static IUnityContainer Initialize () { var unitySections = new List<UnityConfigurationSection> { GetUnitySectionFrom("Unity.City.config"), GetUnitySectionFrom("Unity.County.config"), GetUnitySectionFrom("Unity.State.config"), GetUnitySectionFrom("Unity.config") }; return LoadConfigurations (unitySections); } private static IUnityContainer LoadConfigurations (List<UnityConfigurationSection> unitySections) { var container = new UnityContainer (); foreach (var section in unitySections) { container.LoadConfiguration(section); } return container; } private static UnityConfigurationSection GetUnitySectionFrom (string fileName) { var configuration = ConfigurationManager.OpenMappedExeConfiguration ( new ExeConfigurationFileMap { ExeConfigFilename = fileName }, ConfigurationUserLevel.None); return configuration.GetSection ("unity") as UnityConfigurationSection; } {code:c#}
Oct 7, 2010 at 10:25 AM
Edited Oct 7, 2010 at 1:01 PM

the important questions for me:

can someone post what their config file looks like now that the unity configuration is split into several files?


Is there a way to configure a container in multiple configuration files? 

For instance, I want to register types for a container in a web.config file located at the root

and also register types for the same container (and others containers) in the web.config file of sub-folders. 

And also register other types for others containers in a company.config file in path C:\Company\Framework\Configs. 


When I try to do this I get a ConfigurationError stating that the entry for the container has already been added.

 

Any complete sample with code and config files ?? thanks

 

 

Oct 7, 2010 at 12:56 PM

You can check this out

http://brainfruitcode.com/file.axd?file=UnityConfiguration.zip

Jacobo