NBox и проблема с App.config

Written by elwood

Как известно, CLR при запуске .NET-приложения пытается прочитать config-файл с именем запускаемой сборки + расширение “.config”. Но ведь если запускаемый exe-файл переименовать, то config-файл не подгрузится – и приложение, возможно, перестанет работать. С этим частенько сталкиваются разработчики при работе над деплоингом приложения. И, к сожалению, .NET не содержит способов, позволяющих самому приложению задать имя config-файла во время некой процедуры “прединициализации”. Это возможно лишь для опций, которые читаются классом Settings путем написания собственного SettingsProvider’a, реализующего интерфейс IApplicationSettingsProvider (см Application Settings Architecture для более подробной информации).

Но мы можем сделать самостоятельно из нашего приложения некий “микрозагрузчик”, который создает AppDomain, конфигурирует его и запускает сам себя, используя сконфигурированный AppDomain. Это действительно работает, причем в самом примитивном случае код очень компактен :

 
 AppDomainSetup setupInfo = new AppDomainSetup();
 string entryAssemblyPath = Assembly.GetEntryAssembly().Location;
 string entryAssemblyDir = Path.GetDirectoryName(entryAssemblyPath);
 setupInfo.ApplicationBase = Path.GetDirectoryName(entryAssemblyPath);
 setupInfo.ConfigurationFile = Path.Combine(entryAssemblyDir, "MyApp.exe.config");
 
 AppDomain forkedDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString(), null, setupInfo);
 forkedDomain.ExecuteAssembly(Assembly.GetEntryAssembly().Location);
 AppDomain.Unload(forkedDomain);

Однако, необходимо следить за тем, чтобы такие ухищрения не приводили к сильной деградации производительности на этапе загрузки. Возможно, стоит написать отдельную сборку, которая будет загружать уже то, что нужно нам. Эта сборка будет очень малого размера, и работать будет практически без потери производительности.

А теперь подумаем, что произойдет, если у приложения, обработанного с помощью NBox (а это, как правило, один-единственный исполняемый файл), изменить имя файла. Если приложение не использовало config-файлы, то все будет ок. Но в противном случае – при запуске – CLR просто не подцепит старый конфиг, и приложение, скорее всего, работать не будет. Но, используя вышеприведенные приемы, мы можем заставить NBox распознать config-файл, и перезапустить самого себя, предварительно сконфигурировав AppDomain нужным config-файлом. А чтобы работа по разворачиванию файлов и сборок не производилась дважды, NBox может извлечь файлы во время начального запуска, и, перезапустившись, уже не извлекать файлы, работая со сборками. Таким образом можно минимизировать потери производительности, одновременно получая еще одну степень свободы в том, как сконфигурировать запускаемое приложение.

В принципе, теперь даже не обязательно извлекать config-файл рядом с exe-файлом упакованного приложения. NBox может закешировать извлекаемые config-файлы во временной директории, извлекая их заново в случае необходимости. Для пользователя это означает минус один файл, создаваемый в каталоге приложения, а для разработчика – уверенность в том, что его конфигурация будет применена независимо от названия exe-файла.

PS. Интересно, что метод AppDomainSetup.SetConfigurationBytes, который бы мог избавить нас от использования файлов в таких случаях, похоже, просто не работает 🙂 Здесь тред об этом : AppDomainSetup.SetConfigurationBytes has no visible effect on configuration…