Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

App config for dynamically loaded assemblies

I'm trying to load modules into my application dynamically, but I want to specify separate app.config files for each one.

Say I have following app.config setting for main app:

<appSettings>
  <add key="House" value="Stark"/>
  <add key="Motto" value="Winter is coming."/>
</appSettings>

And another for library that I load using Assembly.LoadFrom:

<appSettings>
  <add key="House" value="Lannister"/>
  <add key="Motto" value="Hear me roar!"/>
</appSettings>

Both libraries have a class implementing the same interface, with the following method:

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

And sure enough calls to Name from both main class and loaded assembly class output Stark.

Is there a way to make main app use its own app.config and each loaded assembly use theirs? Names of config files are different in the output, so that should be possible I think.

like image 371
Grozz Avatar asked Aug 16 '12 18:08

Grozz


2 Answers

Ok, here's the simple solution I ended up with: Create the follow function in the utility library:

public static Configuration LoadConfig()
{
    Assembly currentAssembly = Assembly.GetCallingAssembly();
    return ConfigurationManager.OpenExeConfiguration(currentAssembly.Location);
}

Using it in dynamically loaded libraries like this:

private static readonly Configuration Config = ConfigHelpers.LoadConfig();

No matter how that library gets loaded it uses the correct config file.

Edit: This might be the better solution for loading files into ASP.NET applications:

public static Configuration LoadConfig()
{
    Assembly currentAssembly = Assembly.GetCallingAssembly();
    string configPath = new Uri(currentAssembly.CodeBase).LocalPath;
    return ConfigurationManager.OpenExeConfiguration(configPath);
}

To copy file after build you might want to add the following line to post-build events for asp app (pulling the config from library):

copy "$(SolutionDir)<YourLibProjectName>\$(OutDir)$(Configuration)\<YourLibProjectName>.dll.config" "$(ProjectDir)$(OutDir)"
like image 140
Grozz Avatar answered Sep 18 '22 12:09

Grozz


As far as I know, you need separate application domains for the app.config to work separately. The creation of an AppDomainSetup allows you to specify which config file to use. Here's how I do it:

try
{
  //Create the new application domain
  AppDomainSetup ads = new AppDomainSetup();
  ads.ApplicationBase = Path.GetDirectoryName(config.ExePath) + @"\";
  ads.ConfigurationFile = 
    Path.GetDirectoryName(config.ExePath) + @"\" + config.ExeName + ".config";
  ads.ShadowCopyFiles = "false";
  ads.ApplicationName = config.ExeName;

  AppDomain newDomain = AppDomain.CreateDomain(config.ExeName + " Domain", 
    AppDomain.CurrentDomain.Evidence, ads);

  //Execute the application in the new appdomain
  retValue = newDomain.ExecuteAssembly(config.ExePath, 
    AppDomain.CurrentDomain.Evidence, null);

  //Unload the application domain
  AppDomain.Unload(newDomain);
}
catch (Exception e)
{
  Trace.WriteLine("APPLICATION LOADER: Failed to start application at:  " + 
    config.ExePath);
  HandleTerminalError(e);
}

Another way you could go about getting the desired effect would be to implement your configuration values inside a resource file compiled into each of your DLLs. A simple interface over the configuration object would allow you to switch out looking in an app.config versus looking in a resource file.

like image 31
Josh Avatar answered Sep 18 '22 12:09

Josh