如何在VS2010 C#控制台应用程序中将我的App.config编译进exe文件中?

34

我正在使用c#在Visual Studio 2010中创建控制台应用程序。我希望这个应用程序是独立的,只需要exe文件,就能在任何地方运行。我还想使用app.config存储连接字符串等信息。

我的问题是,我似乎无法将app.config数据包含到编译后的exe文件中。我确实看到它创建了appname.exe.config文件,但我不希望人们在获取应用程序时要担心抓取两个单独的文件。

我所做的所有谷歌搜索都没有找到答案。这可能有可能吗?


2
可能是嵌入式资源配置文件的重复问题。 - John Saunders
1
回复:重复的问题,我在搜索中没看到过那个。这很糟糕,因为那个确实回答了我的问题。虽然我必须说,硬编码应用程序设置与方便的配置文件相比让我感到不满意。我想这是因为我是一个Web程序员。 - Patches
1
@HansPassant 问题在于像WCF这样的东西是围绕着配置文件设计的,虽然可以在代码中进行配置,但文档较少且更加复杂。XML本身比C#更擅长设置配置文件,因此如果您不需要用户更改这些配置,则可以在app.config中配置WCF,但将其嵌入式。 - Didier A.
17
搜索这个问题会得到很多"你这个白痴不要这样做",但实际上"是的,我想这样做,因为我的WCF配置在 app.config 中更容易,我不想让用户更改它"。此外,在普通用户的计算机上,他们会隐藏已知的文件扩展名,所以他们看到的是 "appname.exe" 并双击它,但实际上这是一个扩展名被隐藏的 "appname.exe.config" 文件。如果你安装并在他们的桌面上放一个快捷方式,这不是一个问题,但我真的需要为每个临时程序创建一个安装程序来避免这种情况吗? - TCC
4
WCF至少有一个在代码中进行配置的选项,但是一些依赖程序集甚至是.NET框架需要在应用配置文件中设置条目...我无法改变那种行为,用户也不需要更改这些值...因此,想要以某种方式嵌入应用配置文件并非“愚蠢”。 - TCC
显示剩余5条评论
10个回答

12

你不能这样做。这种配置文件的一半目的是允许在应用程序本身之外更改应用程序的配置。

您只需修改程序,使其不依赖于应用程序配置文件 - 最简单的方法是将配置中的值放入只读全局变量中。


我想我错过了配置文件的重点。我将不得不硬编码它们。 - Patches
12
尽管+1有好处,但问题在于当工具将某些内容放入app.config而非用户时(例如添加对Web服务的引用时),用户绝对不能修改它,但它必须单独打包成文件。更加荒谬的是:常规应用设置(包括连接字符串)会嵌入到exe文件中——您可以仅发送exe文件并连接数据库。但是,Web服务引用的设置不会被嵌入,一旦您引用一个Web服务,就必须分发.config文件。这很愚蠢。 - GSerg
8
如果唯一需要一个app.config的原因是为了确保你的程序无法在.NET 4.0上运行,那就更糟糕了 - 因为由于某种原因,微软无法在程序集本身中标记4.5.2的要求... - Roman Starkov
2
另一个糟糕的 app.config 设置示例:启用 useLegacyJit,因为您的代码 如此 直到今天仍会在 Win10 上由于 RyuJIT 的错误而崩溃。解决方法对于想要作为单个 exe 发布的程序是不可访问的,并且这绝不是任何意义上的用户设置。 - Roman Starkov

9

我可以理解你的意思,但是答案可能比你想象的更加复杂。

  1. 将app.config作为嵌入式资源
  2. 手动解析app.config以获取默认应用程序设置/连接字符串/等等。
  3. 仍然查找app.config并使用app.config值覆盖先前读取的默认值。

这样,您就有了一些合理的默认值,无需将其与您的app.config保持为常量,您可以将应用程序仅作为exe运行,并且仍然可以通过添加app.config来在运行时修改它。

需要记住的一件事是,从资源中读取app.config不会给您与正常app.config相同的行为。您基本上是手动读取它并使用它。


2
嗯,这个想法是为了让事情变得更容易,而不是更难。看起来我最好在我的代码中创建一个设置对象。 - Patches

5

您的意思是需要将其添加到exe中作为资源吗?首先,您无法这样做,app.config是基于文件而不是资源的。

另一方面,配置文件的唯一目的就是可以更改它。否则,只需硬编码或使用常量即可。


4

最佳解决方法似乎是在应用程序启动时自己创建。

  1. 将App.Config添加为资源,重命名为“App_Config”
  2. 检查配置文件是否存在
  3. 如果不存在,则编写默认的 .config 文件

示例代码:

Program.cs

    [STAThread]
    static void Main()
    {
        CreateConfigIfNotExists();
    }

    private static void CreateConfigIfNotExists()
    {
        string configFile = string.Format("{0}.config", Application.ExecutablePath);

        if (!File.Exists(configFile))
        {
            File.WriteAllText(configFile, Resources.App_Config);
        }
    }

记住,在构建时,它只会写入您当前的配置。当您部署新版本时,它不会自动更新配置。它将在构建时按原样包含配置。但这可能已经足够了 :)


4
某些情况下,这是一个好的解决方案。然而,安装程序通常以管理员权限运行并可以在C:\Program Files下安装。应用程序本身不具备管理员权限,因此无法写入EXE所在的文件夹(例如,在C:\ Program Files下)。 - George

4
正如其他人所指出的,配置文件的想法是避免硬编码的值。
作为替代方案,您可以编写一个自定义配置部分,其中每个元素都是可选的,并具有默认值。这样,任何可以使用默认值的人都不需要配置文件。但是,如果他们需要覆盖默认值,他们可以提供一个。
(抱歉,只是一点头脑风暴。我没有可用的示例。)

10
不幸的是,微软滥用了这个文件,用于除配置之外的其他事情。换句话说,它被用来强制要求.NET 4.5应用程序拒绝在早期版本的.NET上运行。这种做法很反常规,因为它不支持用户自定义配置(同时也使单个可执行文件应用程序无法实现),难道不是吗? - Roman Starkov
1
@RomanStarkov:另一个不幸的情况是当您想将 gcAllowVeryLargeObjects 设置为 true 时。这绝对是用户不应该触及的东西,因为如果禁用,它可能会导致程序崩溃。我很难相信这不是 VS 中项目属性的标准选项。 - Dan W

3
一般情况下,您不应这样做,因为app.config提供了一种在运行时进行配置的机制。至于您的具体目标(在代码之外维护配置,但使其遵循二进制),您有几个选择:
  • 动态创建配置文件
  • 将设置存储在注册表中
  • 将设置作为控制台应用程序中的资源字符串存储
我相信还有其他更有创意的选择。我的建议是第二个选项。当应用程序首次启动时,从可执行文件中创建必要的键并设置它们的默认值。这样,如果您需要在以后进行任何调试,只需运行regedit并进行任何必要的更改即可,而无需重新编译。

1
我希望这个东西完全独立,所以我想我会放弃使用注册表。看起来你的第三个选项最适合我的目的。 - Patches

2

2

就像这里的人们所说的一样,配置文件的整个目的是用于修改应用程序之外的某些设置。您可以硬编码或使用常量,但如果需要,也可以在Windows注册表中使用。这样,您可以对应用程序进行更改,仍然只有一个单独的exe文件。

代码项目提供了一些关于从注册表中读取、写入和删除信息的好资料。 http://www.codeproject.com/KB/system/modifyregistry.aspx 但是,在编辑注册表时要小心。许多应用程序都依赖它,因此如果您做错了什么,可能会破坏某些设置。我建议先阅读,然后再操作。

public string Read(string KeyName)  {
RegistryKey rk = baseRegistryKey;
// Open a subKey as read-only

RegistryKey sk1 = rk.OpenSubKey(subKey);
// If the RegistrySubKey doesn't exist -> (null)

if ( sk1 == null )
{
    return null;
}
else
{
    try 
    {
        // If the RegistryKey exists I get its value
        // or null is returned.
        return (string)sk1.GetValue(KeyName.ToUpper());
    }
    catch (Exception e)
    {
        // AAAAAAAAAAARGH, an error!
        ShowErrorMessage(e, "Reading registry " + KeyName.ToUpper());
        return null;
    }
  }
}

public bool Write(string KeyName, object Value)  {
  try
  {
      // Setting
      RegistryKey rk = baseRegistryKey ;
      // I have to use CreateSubKey 
      // (create or open it if already exits), 
      // 'cause OpenSubKey open a subKey as read-only
      RegistryKey sk1 = rk.CreateSubKey(subKey);
      // Save the value
      sk1.SetValue(KeyName.ToUpper(), Value);
      return true;
  }
  catch (Exception e) {
        // AAAAAAAAAAARGH, an error!
        ShowErrorMessage(e, "Writing registry " + KeyName.ToUpper());
        return false;
    }
  }    

public bool DeleteKey(string KeyName)  {
  try
  {
      // Setting
      RegistryKey rk = baseRegistryKey ;
      RegistryKey sk1 = rk.CreateSubKey(subKey);
      // If the RegistrySubKey doesn't exists -> (true)
      if ( sk1 == null )
          return true;
      else
          sk1.DeleteValue(KeyName);
      return true;
  }
  catch (Exception e)
  {
      // AAAAAAAAAAARGH, an error!
      ShowErrorMessage(e, "Deleting SubKey " + subKey);
      return false;
  }
}

当然,这只适用于Windows操作系统。我假设你正在使用Visual Studio,因此你很可能在使用Windows。

祝编码愉快,好运!


1

-3
拿一个WinForm应用程序为例,在编译过程中,会生成一个名为'xxx.EXE.config'的文件,与输出的EXE文件一起。它将包含'app.config'的设置。也要分发这个文件。

2
-1 -- 这正是我特意想要避免的。如何避免这样做是我整个问题的核心。我甚至说过 - “我确实看到它创建了appname.exe.config,但我不希望人们担心抓取两个单独的文件...” - Patches

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