1
  1. I would like to load the MyApp.exe.config from a sub folder of the app bin folder rather than the app bin folder itself (eg ./Configs/MyApp.exe.config).
  2. I dont want to have to work with a System.Configuration object (as returned by ConfigurationManager.OpenExeConfiguration(configPath) because this is just a string map. I would like to keep working with the existing generated Settings : ApplicationSettingsBase object in Settings.Designer.cs as that has setting values cast to proper objects.

I.e I just want to redirect where Settings loads itself from. Ive had a look round and all I can find are solutions that involve working directly with System.Configuration object directly - but how to rewire this up to Settings?

Kind of seems a reasonable thing to want to do - can't understand why it appears so difficult? Any solutions most welcome!

Ricibob
  • 7,505
  • 5
  • 46
  • 65
  • Im I missing something here? Are we really LOCKED into to loading app.config from the same folder as the bin? – Ricibob Nov 27 '12 at 14:09

3 Answers3

4

Jims solution is clean when you have a single configSection in the app.config. In our case we have several configSections (for app, libraries, nlog etc) and we want to just load the whole file from a new location. This wasnt really clear from the orignal question.

The eaisest way to do this seemed to be to use a new AppDomain with an AppDomainSetup object on which we set the ConfigurationFile property to path to new config file.
The question is then when and how to create the new app domain. This post offers an elegant solution that seems to work with minor modifications.

1: Add a Startup event handler:

Application x:Class="InstallTool.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
Startup="AppStartup"

2: In that handler (in the default application domain) create a new application domain - the creation of which just recursively calls the Startup event handler. When the new app domain is finsihed with (app closed) just closed it an abort startup in the "outer" app domain. This avoids having to make cross app domain calls or have a bootstrapper app to create the new app domain.

    public void AppStartup(object sender, StartupEventArgs e) {
        if (AppDomain.CurrentDomain.IsDefaultAppDomain()) {
            string appName = AppDomain.CurrentDomain.FriendlyName;
            var currentAssembly = Assembly.GetExecutingAssembly();

            // Setup path to application config file in ./Config dir:
            AppDomainSetup setup = new AppDomainSetup();
            setup.ApplicationBase = System.Environment.CurrentDirectory;
            setup.ConfigurationFile = setup.ApplicationBase + 
                                string.Format("\\Config\\{0}.config", appName);

            // Create a new app domain using setup with new config file path:
            AppDomain newDomain = AppDomain.CreateDomain("NewAppDomain", null, setup);
            int ret = newDomain.ExecuteAssemblyByName(currentAssembly.FullName, e.Args);
            // Above causes recusive call to this method.

            //--------------------------------------------------------------------------//

            AppDomain.Unload(newDomain);
            Environment.ExitCode = ret;
            // We get here when the new app domain we created is shutdown.  Shutdown the 
            // original default app domain (to avoid running app again there):
            // We could use Shutdown(0) but we have to remove the main window uri from xaml
            // and then set it for new app domain (above execute command) using:
            // StartupUri = new Uri("Window1.xaml", UriKind.Relative);
            Environment.Exit(0);
            return;
        }
    }
Community
  • 1
  • 1
Ricibob
  • 7,505
  • 5
  • 46
  • 65
1

What you need is a custom SettingsProvider. The default for your local application is LocalFileSettingsProvider, which gets the settings from the appname.exe.config file in the same directory as appname.exe. You might be able to create a class derived from LocalFileSettingsProvider, which looks in a different directory. Failing that, you'll have to derive from SettingsProvider.

Also see ApplicationSettingsBase.Providers property.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
1

Ricibob's solution works fine, if you don't have Threads/Background tasks in your application. If you do have them it causes problems. Moreover you can achieve the above solution in one line:

 AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", YOUR_CONFIG_LOCATION);
avijendr
  • 3,958
  • 2
  • 31
  • 46
  • 1
    My method is overly complicated for what its trying to achieve and there are various issues with it - in hindsight I do not recommend it. If this solutions works then it is golden. I havent yet had time to verify it - will try to do so. – Ricibob Mar 17 '16 at 12:35