App.config – jak używać innego pliku do konfiguracji

Prosty przypadek: biblioteka potrzebuje trzymać hasło i użytkownika do konfiguracji aplikacji w app.configu. Rozwijam bibliotekę, która jest  wersjonowana w gicie. Dodałem wyjątek do .gitignore, aby plik app.config się nie wersjonował. Następnie dodałem bibliotekę z testami i tam też muszę dodać konfigurację. Dodać kolejny wyjątek  to już przesada więc można by tak zrobić aby biblioteka testowa używała już istniejącej konfigurację z innego pliku app.config. Oto dwa sposoby

Te dwa sposoby mnie zadowalają:

  1. Można zrobić tak aby w app.configu w sekcji <app settings> wykorzystać przekierowanie do innego pliku,
  2. albo zrobić tak aby korzystać podczas tworzenia testów z innego pliku app.config.

Poniżej rozwiązania:

Inny plik w sekcji  <app settings>

To rozwiązanie jest bardzo proste w użyciu. Tworzymy nowy plik xml, który zawiera sekcje <appConfig> jak niżej:

<?xml version="1.0" encoding="UTF-8"?>
<appSettings>
    <add key="Blah" value="Nim nim nim" />
</appSettings>

Następnie aby skorzystać z konfiguracji w pliku app.config dodajemy taki wpis już w samym pliku app.config

<appSettings configSource="appSettings.config"/>;

Od teraz konfiguracja do <appConfig> będzie brana z pliku appSettings.config

Ten sposób mocno ułatwia już zabawę. Do .gitignore dodajemy tylko plik z konfiguracją a w testach dajemy link do oryginalnego pliku. Dzięki temu mamy większość problemów załatwionych.

PS

Ten sam motyw można zastosować dla gałęzi <connectionStrings>.

Inny plik app.config

Można jednak zrobić to trochę inaczej, pisząc więcej kodu i bawiąc się w bebechach. Taki hardcore!

Korzystanie w testach z orginalnego pliku app.config wykonuje w następujący sposób:

[Test]
public void Publish_News_Post_From_File_Test()
{
    using (AppConfig.Change(@"J:\Dropbox\Dropbox\c#\Projects\AutoBlogProgramisty.Net\AutoBlogProgramistyPosts\AutoBlogProgramistyPosts\bin\Debug\AutoBlogProgramistyPosts.dll.config"))
    {
        var publisher = new Publisher(new NewsFileParser(this.FileName));
        Assert.AreNotEqual(string.Empty, publisher.Publish());
    }
}

W ten sposób tylko na moment przełączam się na inny plik app.config  w całości. Pomiędzy klamrami using mam dostęp do całego pliku app.config ze ścieżki.

Aby korzystać z tego pomysły należy użyć następującego kodu:

public abstract class AppConfig : IDisposable
    {
        public static AppConfig Change(string path)
        {
            return new ChangeAppConfig(path);
        }

        public abstract void Dispose();

        private class ChangeAppConfig : AppConfig
        {
            private readonly string oldConfig =
                AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE").ToString();

            private bool disposedValue;

            public ChangeAppConfig(string path)
            {
                AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", path);
                ResetConfigMechanism();
            }

            public override void Dispose()
            {
                if (!disposedValue)
                {
                    AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", oldConfig);
                    ResetConfigMechanism();

                    disposedValue = true;
                }
                GC.SuppressFinalize(this);
            }

            private static void ResetConfigMechanism()
            {
                typeof(ConfigurationManager)
                    .GetField("s_initState", BindingFlags.NonPublic |
                                             BindingFlags.Static)
                    .SetValue(null, 0);

                typeof(ConfigurationManager)
                    .GetField("s_configSystem", BindingFlags.NonPublic |
                                                BindingFlags.Static)
                    .SetValue(null, null);

                typeof(ConfigurationManager)
                    .Assembly.GetTypes()
                    .Where(x => x.FullName ==
                                "System.Configuration.ClientConfigPaths")
                    .First()
                    .GetField("s_current", BindingFlags.NonPublic |
                                           BindingFlags.Static)
                    .SetValue(null, null);
            }
        }
    }

Kod jest trochę zakręcony i nie każdy moment, rozumiem dlaczego tak należy zrobić (jednak metodą prób i błędów działa kod dział wyśmienicie)  jednak dzięki niemu możemy szybko i dość wygodnie używać innego pliku app.config, na przykład w bibliotekach testowych.

Tłumaczyć i objaśniać nie ma za dużo co. Podstawa to zrozumieć, że na siłę podmieniamy w danej bibliotece wiązania do CAŁEGO pliku app.config.

Podsumowanie

Najczęściej używam podejścia numer 2  w projektach testowych, są momenty, że dobrze jest korzystać z całego nowego pliku do konfiguracji. Głównie wtedy gdy nie ma za dużo konfiguracji.

Są jeszcze inne sposoby, jednak głównie opierają się na grzebaniu w kodach lub własnych implementacjach. Pełno rozwiązań jest na StackOverflow : )

Jedno przemyślenie nt. „App.config – jak używać innego pliku do konfiguracji

  1. Pingback: dotnetomaniak.pl

Możliwość komentowania jest wyłączona.