163

我有一个 .NET 应用程序,它具有用于调试和发布版本的不同配置文件。例如,调试 app.config 文件指向已启用调试的开发SQL Server,而发布目标指向实时 SQL Server。还有其他设置,其中一些在调试/发布时有所不同。

我目前使用两个单独的配置文件(debug.app.config 和 release.app.config)。我在项目上有一个构建事件,说明如果这是一个发布构建,则将 release.app.config 复制到 app.config,否则将 debug.app.config 复制到 app.config。

问题是应用程序似乎从 settings.settings 文件中获取其设置,所以我必须在 Visual Studio 中打开 settings.settings ,然后提示我设置已更改,因此我接受更改,保存 settings.settings 并拥有重建以使其使用正确的设置。

是否有更好/推荐/首选的方法来达到类似的效果?或者同样,我是否完全错误地处理了这个问题,是否有更好的方法?

4

13 回答 13

62

任何可能因环境而异的配置都应该存储在机器级别,而不是应用程序级别(有关配置级别的更多信息。)

这些是我通常在机器级别存储的配置元素类型:

当每个环境(developer、integration、test、stage、live)在​​c:\Windows\Microsoft.NET\Framework64\v2.0.50727\CONFIG目录下都有自己独特的设置,那么你就可以在不同环境之间提升你的应用代码了构建后的修改。

显然,机器级 CONFIG 目录的内容在与您的应用程序不同的存储库或不同的文件夹结构中获得版本控制。您可以通过智能使用configSource使您的 .config 文件对源代码控制更加友好。

我在 25 多家不同公司的 200 多个 ASP.NET 应用程序上从事这项工作已有 7 年了。(不是想吹牛,只是想让你知道我从未见过这种方法不起作用的情况。)

于 2009-01-07T22:09:41.957 回答
52

这可能会帮助一些处理 Settings.settings 和 App.config 的人:在 Visual Studio(在我的例子中是 Visual Studio 2008)中编辑 Settings.settings 网格中的任何值时,请注意“属性”窗格中的 GenerateDefaultValueInCode 属性。

如果将 GenerateDefaultValueInCode 设置为 True(此处默认为 True!),则默认值将编译到 EXE(或 DLL)中,当您在纯文本编辑器中打开文件时,您可以发现它嵌入在文件中。

我正在开发一个控制台应用程序,如果我在 EXE 中默认,该应用程序总是忽略放置在同一目录中的配置文件!一场噩梦,整个互联网上都没有这方面的信息。

于 2009-08-26T08:44:02.030 回答
34

这里有一个相关的问题:

改进您的构建过程

配置文件附带了一种覆盖设置的方法:

<appSettings file="Local.config">

无需检入两个(或更多)文件,您只需检入默认配置文件,然后在每台目标机器上放置一个 Local.config,其中只有 appSettings 部分具有该特定机器的覆盖。

如果您使用的是配置部分,则等效为:

configSource="Local.config"

当然,从其他机器制作所有 Local.config 文件的备份副本并将它们检查到某个地方是一个好主意,但不是作为实际解决方案的一部分。每个开发人员都在 Local.config 文件上放置一个“忽略”,这样它就不会被签入,这会覆盖其他所有人的文件。

(您实际上不必将其称为“Local.config”,这正是我使用的)

于 2008-09-25T10:57:29.060 回答
14

从我正在阅读的内容来看,听起来您正在使用 Visual Studio 进行构建过程。您是否考虑过改用 MSBuild 和Nant

Nant 的 xml 语法有点奇怪,但是一旦你理解了它,做你提到的事情就变得很简单了。

<target name="build">
    <property name="config.type" value="Release" />

    <msbuild project="${filename}" target="Build" verbose="true" failonerror="true">
        <property name="Configuration" value="${config.type}" />
    </msbuild>

    <if test="${config.type == 'Debug'}">
        <copy file=${debug.app.config}" tofile="${app.config}" />
    </if>

    <if test="${config.type == 'Release'}">
        <copy file=${release.app.config}" tofile="${app.config}" />
    </if>

</target>
于 2008-09-25T11:12:24.890 回答
11

在我看来,您似乎可以从Visual Studio 2005 Web 部署项目中受益。

有了它,您可以告诉它根据构建配置更新/修改 web.config 文件的部分。

请查看Scott Gu 的这篇博客文章,以获得快速概述/示例。

于 2008-09-25T10:57:02.540 回答
8

我们曾经使用 Web 部署项目,但后来迁移到了 NAnt。我们目前直接在构建脚本中嵌入配置值并通过 xmlpoke 任务将它们注入到我们的配置文件中,而不是分支和复制不同的设置文件:

  <xmlpoke
    file="${stagingTarget}/web.config"
    xpath="/configuration/system.web/compilation/@debug"
    value="true"
  />

无论哪种情况,您的配置文件都可以具有您想要的任何开发人员值,并且它们可以在您的开发环境中正常工作,而不会破坏您的生产系统。我们发现开发人员在测试时不太可能随意更改构建脚本变量,因此与我们尝试过的其他技术相比,意外的错误配置很少见,尽管仍然有必要在过程的早期添加每个变量,以便默认情况下,dev 值不会被推送到 prod。

于 2008-09-25T11:36:25.130 回答
7

我现在的雇主通过首先将开发级别(调试、阶段、实时等)放入 machine.config 文件中解决了这个问题。然后他们编写代码来获取并使用正确的配置文件。这解决了应用程序部署后连接字符串错误的问题。

他们最近刚刚编写了一个中央 web 服务,它从 machine.config 值中的值发送回正确的连接字符串。

这是最好的解决方案吗?可能不是,但它适用于他们。

于 2008-09-25T10:46:20.460 回答
5

对我有用的解决方案之一是使用 WebDeploymentProject。我的站点中有 2/3 个不同的 web.config 文件,并且在发布时,取决于所选的配置模式(发布/暂存/等),我将复制 Web.Release.config 并将其重命名为 web.config。在 AfterBuild 事件中配置,并删除我不需要的那些(例如 Web.Staging.config)。

<Target Name="AfterBuild">
    <!--Web.config -->
    <Copy Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " SourceFiles="$(SourceWebPhysicalPath)\Web.Release.config" DestinationFiles="$(OutputPath)\Web.config" />
    <Copy Condition=" '$(Configuration)|$(Platform)' == 'Staging|AnyCPU' " SourceFiles="$(SourceWebPhysicalPath)\Web.Staging.config" DestinationFiles="$(OutputPath)\Web.config" />
    <!--Delete extra files -->
    <Delete Files="$(OutputPath)\Web.Release.config" />
    <Delete Files="$(OutputPath)\Web.Staging.config" />
    <Delete Files="@(ProjFiles)" />
  </Target>
于 2008-09-25T11:14:20.113 回答
3

您会在这里找到另一个解决方案:在 ASP.NET 中的 Development/UAT/Prod 环境之间切换配置的最佳方式?它使用 XSLT 转换 web.config。

还有一些使用 NAnt 的好例子。

于 2008-09-25T12:28:17.563 回答
3

我们的项目有同样的问题,我们必须维护 dev、qa、uat 和 prod 的配置。以下是我们遵循的(仅适用于您熟悉 MSBuild):

将 MSBuild 与 MSBuild 社区任务扩展一起使用。它包括“XmlMassUpdate”任务,一旦你给它正确的节点开始,它就可以“大规模更新”任何 XML 文件中的条目。

实施:

1) 您需要有一个配置文件,其中包含您的开发环境条目;这是您的解决方案中的配置文件。

2)您需要有一个“Substitutions.xml”文件,其中仅包含每个环境不同的条目(主要是 appSettings 和 ConnectionStrings)。不会在环境中更改的条目不需要放在此文件中。它们可以存在于解决方案的 web.config 文件中,不会被任务触及

3) 在您的构建文件中,只需调用 XML 批量更新任务并提供正确的环境作为参数。

请参见下面的示例:

    <!-- Actual Config File -->
    <appSettings>
        <add key="ApplicationName" value="NameInDev"/>
        <add key="ThisDoesNotChange" value="Do not put in substitution file" />
    </appSettings>

    <!-- Substitutions.xml -->
    <configuration xmlns:xmu="urn:msbuildcommunitytasks-xmlmassupdate">
      <substitutions>
        <QA>
           <appSettings>
            <add xmu:key="key" key="ApplicationName" value="NameInQA"/>
           </appSettings>            
        </QA>
        <Prod>
          <appSettings>
            <add xmu:key="key" key="ApplicationName" value="NameInProd"/>
          </appSettings>            
        </Prod>
     </substitutions>
    </configuration>


<!-- Build.xml file-->

    <Target Name="UpdateConfigSections">
            <XmlMassUpdate ContentFile="Path\of\copy\of\latest web.config" SubstitutionsFile="path\of\substitutionFile" ContentRoot="/configuration" SubstitutionsRoot="/configuration/substitutions/$(Environment)" />
        </Target>

根据什么环境将“$Environment”替换为“QA”或“Prod”。你正在建设。请注意,您应该使用配置文件的副本而不是实际的配置文件本身,以避免任何可能的不可恢复的错误。

只需运行构建文件,然后将更新的配置文件移动到您的部署环境,就完成了!

要获得更好的概述,请阅读以下内容:

http://blogs.microsoft.co.il/blogs/dorony/archive/2008/01/18/easy-configuration-deployment-with-msbuild-and-the-xmlmassupdate-task.aspx

于 2009-06-18T21:42:15.683 回答
2

和你一样,我也设置了“多”app.config - 例如 app.configDEV、app.configTEST、app.config.LOCAL。我看到了一些很好的替代方案,但如果你喜欢它适合你的方式,我会添加以下内容:


<appSettings>
<add key = "Env" value = "[Local] "/> 在标题栏中将每个应用程序都添加到 UI 中:来自 ConfigurationManager.AppSettings.Get("Env");

我只是将配置重命名为我的目标(我有一个项目有 8 个应用程序,其中有很多数据库/wcf 配置针对 4 个事件)。要通过 clickonce 部署到每个项目中,我更改了项目中的 4 个设置然后开始。(这我很想自动化)

我唯一的问题是记住在更改后“全部清除”,因为旧配置在手动重命名后“卡住”。(我认为这会解决你的 setting.setting 问题)。

我发现这真的很好用(有一天我会有时间看看 MSBuild/NAnt)

于 2009-02-26T12:32:22.540 回答
0

它上面写着 asp.net,那么为什么不将您的设置保存在数据库中并使用自定义缓存来检索它们呢?

我们这样做的原因是(对我们而言)更新连续数据库比获得连续更新生产文件的权限更容易。

自定义缓存示例:

public enum ConfigurationSection
{
    AppSettings
}

public static class Utility
{
    #region "Common.Configuration.Configurations"

    private static Cache cache = System.Web.HttpRuntime.Cache;

    public static String GetAppSetting(String key)
    {
        return GetConfigurationValue(ConfigurationSection.AppSettings, key);
    }

    public static String GetConfigurationValue(ConfigurationSection section, String key)
    {
        Configurations config = null;

        if (!cache.TryGetItemFromCache<Configurations>(out config))
        {
            config = new Configurations();
            config.List(SNCLavalin.US.Common.Enumerations.ConfigurationSection.AppSettings);
            cache.AddToCache<Configurations>(config, DateTime.Now.AddMinutes(15));
        }

        var result = (from record in config
                      where record.Key == key
                      select record).FirstOrDefault();

        return (result == null) ? null : result.Value;
    }

    #endregion
}

namespace Common.Configuration
{
    public class Configurations : List<Configuration>
    {
        #region CONSTRUCTORS

        public Configurations() : base()
        {
            initialize();
        }
        public Configurations(int capacity) : base(capacity)
        {
            initialize();
        }
        public Configurations(IEnumerable<Configuration> collection) : base(collection)
        {
            initialize();
        }

        #endregion

        #region PROPERTIES & FIELDS

        private Crud _crud; // Db-Access layer

        #endregion

        #region EVENTS
        #endregion

        #region METHODS

        private void initialize()
        {
            _crud = new Crud(Utility.ConnectionName);
        }

        /// <summary>
        /// Lists one-to-many records.
        /// </summary>
        public Configurations List(ConfigurationSection section)
        {
            using (DbCommand dbCommand = _crud.Db.GetStoredProcCommand("spa_LIST_MyConfiguration"))
            {
                _crud.Db.AddInParameter(dbCommand, "@Section", DbType.String, section.ToString());

                _crud.List(dbCommand, PopulateFrom);
            }

            return this;
        }

        public void PopulateFrom(DataTable table)
        {
            this.Clear();

            foreach (DataRow row in table.Rows)
            {
                Configuration instance = new Configuration();
                instance.PopulateFrom(row);
                this.Add(instance);
            }
        }

        #endregion
    }

    public class Configuration
    {
        #region CONSTRUCTORS

        public Configuration()
        {
            initialize();
        }

        #endregion

        #region PROPERTIES & FIELDS

        private Crud _crud;

        public string Section { get; set; }
        public string Key { get; set; }
        public string Value { get; set; }

        #endregion

        #region EVENTS
        #endregion

        #region METHODS

        private void initialize()
        {
            _crud = new Crud(Utility.ConnectionName);
            Clear();
        }

        public void Clear()
        {
            this.Section = "";
            this.Key = "";
            this.Value = "";
        }
        public void PopulateFrom(DataRow row)
        {
            Clear();

            this.Section = row["Section"].ToString();
            this.Key = row["Key"].ToString();
            this.Value = row["Value"].ToString();
        }

        #endregion
    }
}
于 2011-05-24T17:38:22.727 回答
0

网络配置:

当您想在 IIS 上托管应用程序时,需要 Web.config。Web.config 是 IIS 的强制配置文件,用于配置它在 Kestrel 前如何作为反向代理运行。如果你想在 IIS 上托管它,你必须维护一个 web.config。

应用设置.json:

对于与 IIS 无关的所有其他内容,您可以使用 AppSetting.json。AppSetting.json 用于 Asp.Net Core 托管。ASP.NET Core 使用“ASPNETCORE_ENVIRONMENT”环境变量来确定当前环境。默认情况下,如果您在未设置此值的情况下运行应用程序,它将自动默认为生产环境并使用“AppSetting.production.json”文件。当您通过 Visual Studio 进行调试时,它将环境设置为 Development,因此它使用“AppSetting.json”。请参阅此网站以了解如何在 Windows 上设置托管环境变量。

应用程序配置:

App.config 是 .NET 使用的另一个配置文件,主要用于 Windows 窗体、Windows 服务、控制台应用程序和 WPF 应用程序。当您通过控制台应用程序启动 Asp.Net Core 托管时,还会使用 app.config。


TL;博士

配置文件的选择取决于您为服务选择的托管环境。如果您使用 IIS 来托管您的服务,请使用 Web.config 文件。如果您使用任何其他托管环境,请使用 App.config 文件。请参阅使用配置文件配置服务文档 并查看ASP.NET Core 中的配置。

于 2018-09-10T07:12:46.600 回答