2010-09-03 6 views
8

Я хочу изменить местоположение, где мое приложение ищет файл app.config.Как изменить местоположение app.config

Я знаю, что я могу использовать ConfigurationManager.OpenExeConfiguration() для доступа к произвольному файлу конфигурации, однако, когда .Net Framework читает файл конфигурации (например, для ConnectionStrings или EventSources), он будет искать местоположение по умолчанию , Я хочу на самом деле изменить местоположение, глобально для всей .NET Framework (для моего приложения, конечно).

Я также знаю, что я могу использовать AppDomainSetup для изменения местоположения app.config для нового AppDomain. Однако это не относится к основному AppDomain приложения.

Я также знаю, что могу переопределить функцию Main() и создать новый AppDomain, как указано выше, и запустить мое приложение в новом AppDomain. Однако это имеет другие побочные эффекты - например, Assembly.GetEntryAssembly() вернет нулевую ссылку.

Учитывая, как все работает в .Net, я ожидаю, что какой-то способ настроить среду запуска моего приложения - через манифест приложения или некоторые из них - но я не смог найти даже мерцание надеюсь, в этом направлении.

Любой указатель будет полезен.

Дэвид Маллин

ответ

9

Я использовал подход с запуском другого AppDomain из Main(), указав «новое» местоположение конфигурационного файла.

Нет проблем с GetEntryAssembly(); это только возвращает нуль, когда вызывается из неуправляемого кода - или, по крайней мере, это не для меня, так как я использую ExecuteAssembly() для создания/запуска второй AppDomain, так же, как это:

int Main(string[] args) 
{ 
    string currentExecutable = Assembly.GetExecutingAssembly().Location; 

    bool inChild = false; 
    List<string> xargs = new List<string>(); 
    foreach (string arg in xargs) 
    { 
     if (arg.Equals("-child")) 
     { 
     inChild = true; 
     } 
     /* Parse other command line arguments */ 
     else 
     { 
     xargs.Add(arg); 
     } 
    } 

    if (!inChild) 
    { 
     AppDomainSetup info = new AppDomainSetup(); 
     info.ConfigurationFile = /* Path to desired App.Config File */; 
     Evidence evidence = AppDomain.CurrentDomain.Evidence; 
     AppDomain domain = AppDomain.CreateDomain(friendlyName, evidence, info); 

     xargs.Add("-child"); // Prevent recursion 

     return domain.ExecuteAssembly(currentExecutable, evidence, xargs.ToArray()); 
    } 

    // Execute actual Main-Code, we are in the child domain with the custom app.config 

    return 0; 
} 

Обратите внимание, что мы эффективно перезапускают EXE, как AppDomain и с другой конфигурацией. Также обратите внимание, что вам нужно иметь некоторую «магическую» опцию, которая предотвращает ее бесконечное продолжение.

Я разработал это из большего (реального) фрагмента кода, поэтому он может работать не так, как есть, но должен иллюстрировать концепцию.

+0

Хммм. В моем тесте на этот подход (который отличался от вашего), GetEntryAssembly действительно возвращал значение null. Но я не делал ExecuteAssembly - я нашел «вторую главную», которую я написал и выполнил. Я попробую ваш подход и посмотрю, будет ли это работать для меня. –

+0

Я думаю, что ExecuteAssembly имеет значение. По крайней мере, Документы говорят, что GetEntryAssembly возвращает исполняемый, * или * тот, который был передан ExecuteAssembly(). –

0

Я не знаю, почему вы хотите изменить местоположение файла конфигурации - возможно, там может быть другой подход для решения вашей актуальной проблемы. У меня было требование, когда я хотел поделиться файлом конфигурации со связанными приложениями - я решил использовать собственный XML-файл, поскольку он дал мне дополнительную выгоду от полного контроля над схемой.

В вашем случае вы можете экрнализировать разделы своего конфигурационного файла в отдельный файл с использованием свойства configSource. См. here в разделе «Использование файлов внешней конфигурации», чтобы проверить, как это было сделано для раздела строк подключения. Возможно, это может вам помочь.

+0

Основной причиной этого является то, что приложение устанавливается через ClickOnce, который эффективно скрывает файл конфигурации. Тем не менее, есть настройки (например, записи TraceSource), которые я хочу настроить на клиентском компьютере, и сохраняться между установками (поскольку обновление ClickOnce может заменить файл конфигурации). –

+0

Я вижу - возможно, вы можете использовать AppSettings (http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx) для этого? Они поддерживают сценарий ClickOnce - см. Http://msdn.microsoft.com/en-us/library/ms228995.ASPX. – VinayC

+0

Я не могу использовать AppSettings, потому что .Net Framework не будет искать там TraceSources (или любую другую конфигурацию, специфичную для конкретной инфраструктуры). –

0
var configPath = YOUR_PATH; 
if (!Directory.Exists(ProductFolder)) 
{ 
    Directory.CreateDirectory(ProductFolder); 
} 

if (!File.Exists(configPath)) 
{ 
    File.WriteAllText(configPath, Resources.App); 
} 

var map = new ExeConfigurationFileMap 
{ 
    ExeConfigFilename = configPath, 
    LocalUserConfigFilename = configPath, 
    RoamingUserConfigFilename = configPath 
}; 

Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None); 

Затем используйте конфигурационный элемент, как хотите.

+0

Это может быть полезно для некоторых других пользователей, но ничего не делает для решения проблемы OP. Он прямо заявляет, почему этот подход не может работать для него в вопросе. В частности, различные классы инфраструктуры (например, конфигурация WCF) получают настройки из файла конфигурации в местоположении по умолчанию ... вы не можете влиять на них, вместо этого используйте экземпляр «Configuration» в вашей переменной «config». – TCC