如何更改app.config文件的位置

9

我想更改应用程序查找app.config文件的位置。

我知道可以使用ConfigurationManager.OpenExeConfiguration()来访问任意配置文件,但是当.NET Framework读取配置文件(例如ConnectionStrings或EventSources)时,它将查看默认位置。 我实际上想要更改整个.NET Framework(当然是针对我的应用程序)的位置。

我也知道可以使用AppDomainSetup来更改新AppDomain的app.config位置。 但是,这不适用于应用程序的主要AppDomain。

我还知道可以覆盖函数Main()并创建一个新的AppDomain,然后在该新的AppDomain中运行我的应用程序。 但是,这会产生其他副作用 - 例如,Assembly.GetEntryAssembly()将返回空引用。

考虑到.NET的其他所有工作方式,我希望能够通过应用程序清单或类似方式配置我的应用程序的启动环境,但我无法在这个方向上找到任何线索。

任何指针都将有所帮助。

大卫·穆林

4个回答

9
我使用了从Main()启动另一个AppDomain的方法,指定配置文件的“新”位置。
当从非托管代码调用时,GetEntryAssembly()返回null没有问题。至少对我来说是这样的,因为我使用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,并使用不同的配置。还要注意,您需要一些“魔法”选项来防止这种情况无休止地发生。
我从更大(真实的)代码块中精简出了这个示例,所以它可能不能直接使用,但应该能够说明概念。

嗯,在我的测试中(与你的不同),GetEntryAssembly返回了null。但是,我没有执行ExecuteAssembly - 我找到了我编写的“第二个Main”并执行了它。我会尝试你的方法,看看它是否适用于我。 - David Mullin
我认为ExecuteAssembly有所不同。至少文档说GetEntryAssembly返回可执行文件,或者传递给ExecuteAssembly()的文件。 - Christian.K

0
另一种方法是将配置文件与可执行文件放在一起,并将可更改部分移到外部的xml文件中,这些文件可以位于任何您选择的位置。
如果您仅以只读方式使用配置文件,则可以使用XML Inlcude将相关块添加到不同位置的XML文件中。如果您尝试直接使用Configuration.Save方法将值写回app.config,则此方法无效。

app.config:

<?xml version="1.0"?>
<configuration xmlns:xi="http://www.w3.org/2001/XInclude">
    <appSettings>
      <xi:include href="AppSettings.xml"/>
    </appSettings>
  <connectionStrings>
    <xi:include href="ConnectionStrings.xml"/>
  </connectionStrings>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/></startup>
</configuration>

ConnectionStrings.xml:

<?xml version="1.0"?>
<add name="Example1ConnectionString"
        connectionString="Data Source=(local)\SQLExpress;Initial Catalog=Example1DB;Persist Security Info=True;User ID=sa;Password=password"
        providerName="System.Data.SqlClient" />
<add name="Example2ConnectionString"
        connectionString="Data Source=(local)\SQLExpress;Initial Catalog=Example2DB;Persist Security Info=True;User ID=sa;Password=password"
        providerName="System.Data.SqlClient" />

AppSettings.xml:

<?xml version="1.0"?>
<add key="Setting1" value="Value1"/>
<add key="Setting2" value="Value2"/>

文件 URI 看起来像这样:

file:///C:/whatever.txt

你甚至可以定义故障转移文件,以防引用的文件丢失。这个模式来自于https://www.xml.com/pub/a/2002/07/31/xinclude.html

<xi:include href="http://www.whitehouse.gov/malapropisms.xml">
  <xi:fallback>
    <para>
      This administration is doing everything we can to end the stalemate in
      an efficient way. We're making the right decisions to bring the solution
      to an end.
    </para>
  </xi:fallback>


0

我不确定为什么您想要更改配置文件的位置 - 或许有不同的方法来解决您实际的问题。我曾经有一个需求,希望在相关应用程序之间共享配置文件 - 我选择使用自己的xml文件,因为它给了我完全控制架构的额外好处。

在您的情况下,可以使用configSource属性将配置文件的部分外部化到单独的文件中。请参见此处下的“使用外部配置文件”以查看如何对连接字符串部分进行操作。也许这可以帮助您。


想要这样做的主要原因是应用程序是通过ClickOnce安装的,这有效地隐藏了配置文件。然而,有些设置(如TraceSource条目)我希望在客户端机器上可配置,并且在安装之间持久存在(因为ClickOnce更新可能会替换配置文件)。 - David Mullin
我看到了 - 也许你可以使用AppSettings (http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx) 来实现这个?它们支持ClickOnce场景 - 参见 http://msdn.microsoft.com/en-us/library/ms228995.aspx。 - VinayC
我无法使用AppSettings,因为.Net Framework不会在那里查找TraceSources(或任何其他特定于框架的配置)。 - David Mullin

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);

然后按照您的需要使用config成员即可。


这可能对其他用户有用,但对解决OP的问题没有任何帮助。他在问题中明确说明了为什么这种方法对他行不通。具体来说,各种框架类(例如WCF配置)从默认位置的配置文件中获取设置...您无法影响它们改为使用您的“config”变量中的“Configuration”实例。 - TCC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接