Visual Studio中特定于开发人员的app.config / web.config文件

时间:2010-09-14 09:46:49

标签: c# visual-studio configuration web-config app-config

我们有几个.NET项目,我们在配置文件中存储某些设置。 现在每个开发人员都有自己的配置文件,这些配置文件略有不同(连接到本地数据库的不同连接字符串,不同的WCF端点等)。

目前我们倾向于检查app / web.config文件并根据我们的需要进行修改。 这导致了许多问题,因为当从tfs获取最新版本时,有人会不时检查自己的设置或松散自定义配置。

我的问题是:你如何处理这样的情况?或者你根本没有这个问题?

9 个答案:

答案 0 :(得分:65)

我们使用的系统结合了此页面上的几个现有答案,并在this suggestion by Scott Hanselman上绘制。

简而言之,我们所做的是拥有一个通用的app.config / web.config,并在各个文件中包含大部分特定设置,如此处的其他答案所示。例如对于我们的SMTP设置,app.config包含

<system.net>
  <mailSettings>
    <smtp configSource="config\smtp.config" />
  </mailSettings>
</system.net>

源控件中的 文件。但是,像这样的单个文件不是:

<?xml version="1.0" encoding="utf-8" ?>
<smtp deliveryMethod="Network">
  <network host="127.0.0.1" port="25" defaultCredentials="false" password="" userName ="" />
</smtp>

虽然这不是故事结束的地方。新开发人员或新的源代码安装怎么样?大部分配置不再受源代码控制,手动构建所需的所有.config文件都很痛苦。我更喜欢拥有至少可以直接编译的源代码。

因此,我们会在源代码管理中保留.config文件的版本,名为 .config.default 文件。因此,新的源代码树如下所示:

alt text

尽管如此,对开发人员来说并没有任何用处,因为对于Visual Studio来说,它们只是无意义的文本文件。因此批处理文件copy_default_config.bat负责从.config.default文件创建一组初始的.config文件:

@echo off
@REM Makes copies of all .default files without the .default extension, only if it doesn't already exist. Does the same recursively through all child folders.
for /r %%f in (*.default) do (
    if not exist "%%~pnf" (echo Copying %%~pnf.default to %%~pnf & copy "%%f" "%%~pnf" /y)
)
echo Done.

该脚本可以安全地重新运行,因为已经拥有.config文件的开发人员不会覆盖它们。因此,可以想象,可以将此批处理文件作为预构建事件运行。 .default文件中的值对于新安装可能不完全正确,但它们是一个合理的起点。

最终每个开发人员最终得到的是配置文件的文件夹,如下所示:

alt text

这可能看起来有些令人费解,但它绝对比开发人员踩到彼此的脚趾更麻烦。

答案 1 :(得分:21)

在您的Web.config中使用来自其他文件的源

<configuration>
    <connectionStrings configSource="ConnectionStrings.config" />
...
</configuration>

将web.config保留在版本控制中,不要为ConnectionStrings.config执行此操作。 现在所有开发人员都有一个连接字符串文件。

您可以对本地相关的所有设置执行此操作。

答案 2 :(得分:18)

这是web.config文件和Visual Studio 2010的解决方案:

1)手动编辑您的Web应用程序.csproj文件以添加AfterBuild目标,如下所示:

  <Project>
   ...
    <Target Name="AfterBuild">
      <Copy SourceFiles="web.config" DestinationFiles="obj\$(Configuration)\tempweb.config" />
      <TransformXml Source="obj\$(Configuration)\tempweb.config"
                  Transform="web.$(USERNAME).config"
                  Destination="obj\$(Configuration)\tempweb2.config" />
      <ReadLinesFromFile File="obj\$(Configuration)\tempweb2.config"><Output TaskParameter="Lines" ItemName="TransformedWebConfig"/></ReadLinesFromFile>
      <ReadLinesFromFile File="web.config"><Output TaskParameter="Lines" ItemName="UnTransformedWebConfig"/></ReadLinesFromFile>
      <Copy Condition=" @(UnTransformedWebConfig) != @(TransformedWebConfig) " SourceFiles="obj\$(Configuration)\tempweb2.config" DestinationFiles="web.config" OverwriteReadOnlyFiles="True" />
    </Target>
  </Project>

此目标将转换对应于当前登录的开发人员的Web.config文件 - 因此为$(USERNAME)变量 - ,并在1中创建相应的文件。 只有在每次构建时内容已更改(以避免重新启动)时,它才会替换本地Web.config,即使本地Web.config是源控制的,这就是OverwriteReadOnlyFiles设置为True的原因。事实上,这一点是有争议的。

2)为项目中的每个开发人员创建一个名为Web.[developer windows login].config的文件。 (例如,在以下屏幕截图中,我有两个名为smo和smo2的开发人员):

enter image description here

这些文件(每个开发人员1个)可以/应该是源控制的。它们不应该被标记为依赖于主Web.config,因为我们希望能够单独检查它们。

此文件中的每一个都表示要应用于主Web.Config文件的转换。 此处描述了转换语法:Web.config Transformation Syntax for Web Application Project Deployment。我们重用这个很酷的Xml文件转换任务,它与Visual Studio一起开箱即用。此任务的目的是合并 Xml元素和属性,而不是覆盖整个文件。

例如,以下是一个示例web.[dev login].config,用于更改名为“MyDB”的连接字符串,而不管Web.config文件的其余部分如何:

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <connectionStrings>
      <add name="MyDB" 
        connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True" 
        xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />
    </connectionStrings>
</configuration>

现在,这个解决方案并不完美,因为:

  • 构建之后,开发人员可能在本地具有与源控制系统不同的Web.Config
  • 从源控制系统获取新的Web.Config时,他们可能必须强制本地写入
  • 开发人员不应该在主web.config中签出/。应该保留给很少的人。

但至少,你只需要为每个开发人员维护一个独特的主web.config和一个转换文件。

可以对App.config(非网络)文件采取类似的方法,但我没有进一步详细说明。

答案 3 :(得分:2)

我们正在使用machine.config来避免环境之间的web.config存在差异。

答案 4 :(得分:0)

忽略文件怎么样,所以它永远不会被检入?我遇到了类似的问题,并将web.config添加到Subversion的忽略列表中。

在TFS中,这有点困难,请参阅this post了解如何操作。

答案 5 :(得分:0)

您可以应对的一种方法是使用标记化系统并使用rake脚本来更改值。

一个更基本的方法可能是为web.config中的所有AppSettings提供AppSettings.config文件的链接(类似于连接),即

<appSettings configSource="_configs/AppSettings.config" />

然后有一个文件夹,每个开发人员都有一个子文件夹中的版本(即/ _configs/dave/)。然后,当开发人员处理他们自己的代码时,他们会从子文件夹复制到链接文件夹的根目录。

您需要确保传达对这些文件的更改(除非您进行标记)。如果您将AppSettings.config文件保留在源代码管理之外,并且只检查开发人员个人文件夹(所有这些文件夹),那么他们将被强制复制正确的文件夹。

我更喜欢令牌化,但如果这只是一个快速解决方案,那么起床和跑步会更加困难。

答案 6 :(得分:0)

忽略文件并拥有Commom_Web.Config和Common_App.Config。使用具有构建任务的持续集成构建服务器,将这两个重命名为普通名称,以便构建服务器可以完成其工作。

答案 7 :(得分:0)

我们遇到同样的问题,我们正在做的是

  • 使用testserver / production values检查web.config
  • 开发人员访问Windows资源管理器并更改文件的只读模式
  • 编辑配置以适应他们的环境。
  • 只有在部署值更改或添加或删除任何配置条目时,才会检入web.config。
  • 这需要对每个配置条目进行大量注释,因为每个配置需要更改

答案 8 :(得分:-1)

假设您使用的是Visual Studio,为什么不使用不同的解决方案配置? 例如:您可以使用使用Web.config.debug的Debug配置和使用Web.config.release的Release配置。 Web.config.debug应该有像

这样的东西
<appSettings file="C:/Standard_Path_To_Configs/Standard_Name_For_Config.config"> 

使用文件Standard_Name_For_Config.config来设置所有个人开发人员设置,而Web.config.release始终具有生产设置。 您可以将默认配置存储在某个源控制文件夹中,并让新用户从那里获取它们。