【问题标题】:How to change location of app.config如何更改 app.config 的位置
【发布时间】:2011-04-07 15:22:40
【问题描述】:

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

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

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

我也知道我可以重写函数 Main() 并像上面一样创建一个新的 AppDomain 并在那个新的 AppDomain 中运行我的应用程序。但是,这还有其他副作用 - 例如,Assembly.GetEntryAssembly() 将返回一个空引用。

考虑到 .Net 中其他一切的工作方式,我希望有某种方法可以配置我的应用程序的启动环境——通过应用程序清单或其他方式——但我什至找不到一丝希望朝着那个方向。

任何指针都会有所帮助。

大卫·穆林

【问题讨论】:

    标签: c# .net path app-config


    【解决方案1】:

    我使用该方法从 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”。我会试试你的方法,看看它是否适合我。
    • 我认为 ExecuteAssembly 与众不同。至少文档说 GetEntryAssembly 返回可执行文件,传递给 ExecuteAssembly() 的那个。
    【解决方案2】:

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

    在您的情况下,可以使用 configSource 属性将配置文件的部分外部化到单独的文件中。请参阅“使用外部配置文件”下的here 以检查连接字符串部分是如何完成的。也许,这可能对你有所帮助。

    【讨论】:

    • 想要这样做的主要原因是应用程序是通过 ClickOnce 安装的,它有效地隐藏了配置文件。但是,我希望在客户端计算机上配置一些设置(如 TraceSource 条目)并在安装之间保持不变(因为 ClickOnce 更新可能会替换配置文件)。
    • 我明白了 - 也许您可以为此使用 AppSettings (msdn.microsoft.com/en-us/library/k4s6c3a0.aspx)?它们支持 ClickOnce 方案 - 请参阅 msdn.microsoft.com/en-us/library/ms228995.aspx
    • 我不能使用 AppSettings,因为 .Net 框架不会在那里寻找 TraceSources(或任何其他特定于框架的配置)。
    【解决方案3】:
    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);
    

    然后根据需要使用配置成员。

    【讨论】:

    • 这可能对其他一些用户有用,但对解决 OP 的问题没有任何帮助。他在问题中明确说明了为什么这种方法对他不起作用。具体来说,各种框架类(例如 WCF 配置)从默认位置的配置文件中获取设置……您不能影响它们,而是在“config”变量中使用 Configuration 实例。
    【解决方案4】:

    另一种方法是将配置文件与可执行文件一起保留,并将相关的可更改部分移动到外部 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>

    【讨论】:

      猜你喜欢
      • 2016-08-07
      • 2010-11-09
      • 1970-01-01
      • 1970-01-01
      • 2016-11-06
      • 2014-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多