我有一个.NET应用程序,它有不同的Debug和Release版本配置文件。例如。 debug 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,然后提示我设置已更改,因此我接受更改,保存设置。设置并且必须重建以使其使用正确的设置。
是否有更好/推荐/首选的方法来达到类似的效果?或者同样,我是否接近这个完全错误并且有更好的方法吗?
答案 0 :(得分:60)
任何可能因环境而异的配置应存储在计算机级别,而不是应用程序级别。 (More info on configuration levels.)
这些是我通常在机器级别存储的配置元素类型:
当每个环境(开发人员,集成,测试,阶段,实时)在 c:\ Windows \ Microsoft.NET \ Framework64 \ v2.0.50727 \ CONFIG 目录中都有自己的唯一设置时,则您可以在环境之间宣传应用程序代码,而无需进行任何构建后修改。
显然,机器级CONFIG目录的内容在不同的存储库或与您的应用程序不同的文件夹结构中进行版本控制。通过智能使用configSource,您可以使.config文件更加源代码控制。
我已经这样做了7年,在超过25家不同公司的200多个ASP.NET应用程序上。 (不要试图吹嘘,只是想让你知道我从未见过这种方法不工作的情况。)
答案 1 :(得分:50)
这可能对处理Settings.settings和App.config的人有所帮助:在编辑Visual Studio中的Settings.settings网格中的任何值时,在“属性”窗格中注意GenerateDefaultValueInCode属性(在我的案例中为Visual Studio 2008) )。
如果将GenerateDefaultValueInCode设置为True(默认值为True!),则默认值将编译到EXE(或DLL)中,当您在纯文本编辑器中打开它时,可以在文件中找到它。
我正在使用控制台应用程序,如果我在EXE中有默认值,应用程序总是忽略同一目录中的配置文件位置!相当噩梦,在整个互联网上没有关于此的信息。
答案 2 :(得分:33)
这里有一个相关的问题:
配置文件可以覆盖设置:
<appSettings file="Local.config">
您只需检入默认配置文件,然后在每台目标计算机上放置一个Local.config,而不是检入两个文件(或更多),而只放置具有该特定计算机覆盖的appSettings部分
如果您使用的是配置部分,则等效于:
configSource="Local.config"
当然,从其他计算机制作所有Local.config文件的备份副本并在某处检查它们是个好主意,但不能作为实际解决方案的一部分。每个开发人员在Local.config文件上放置一个“忽略”,因此不会检入,这会覆盖其他人的文件。
(你实际上不必称之为“Local.config”,这正是我所使用的)
答案 3 :(得分: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>
答案 4 :(得分:11)
对我而言,您似乎可以从Visual Studio 2005 Web Deployment Project获益。
有了这个,您可以告诉它根据构建配置更新/修改web.config文件的各个部分。
请查看this blog entry from Scott Gu以获取快速概览/样本。
答案 5 :(得分:8)
我们过去常常使用Web部署项目,但后来迁移到了NAnt。我们目前将配置值直接嵌入到构建脚本中,并通过xmlpoke任务将它们注入到我们的配置文件中,而不是分支和复制不同的设置文件:
<xmlpoke
file="${stagingTarget}/web.config"
xpath="/configuration/system.web/compilation/@debug"
value="true"
/>
在任何一种情况下,您的配置文件都可以包含您想要的任何开发人员值,并且它们可以在您的开发环境中正常工作,而不会破坏您的生产系统。我们发现开发人员在测试时不太可能随意更改构建脚本变量,因此偶然的错误配置比我们尝试过的其他技术更少见,尽管仍然需要在过程的早期添加每个var,以便默认情况下,dev值不会被推送到prod。
答案 6 :(得分:7)
我当前的雇主首先将dev级别(debug,stage,live等)放在machine.config文件中解决了这个问题。然后他们编写代码来选择并使用正确的配置文件。这解决了部署应用程序后错误连接字符串的问题。
他们最近写了一个中央Web服务,它从machine.config值中的值发回正确的连接字符串。
这是最好的解决方案吗?可能不是,但它适用于他们。
答案 7 :(得分:5)
其中一个对我有用的解决方案是使用WebDeploymentProject。 我在我的站点中有2/3个不同的web.config文件,并且在发布时,取决于所选的配置模式(发布/暂存/等...),我将复制Web.Release.config并将其重命名为web。在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>
答案 8 :(得分:3)
你会在这里找到另一个解决方案:Best way to switch configuration between Development/UAT/Prod environments in ASP.NET?它使用XSLT转换web.config。
使用NAnt也有一些很好的例子。
答案 9 :(得分:3)
我们的项目有同样的问题,我们必须维护dev,qa,uat和prod的配置。以下是我们遵循的内容(仅适用于您熟悉MSBuild):
将MSBuild与MSBuild社区任务扩展一起使用。它包括“XmlMassUpdate”任务,一旦您为其提供正确的节点,就可以“批量更新”任何XML文件中的条目。
实施:
1)你需要有一个配置文件,它将包含你的dev env条目;这是解决方案中的配置文件。
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>
根据env将'$ Environment'替换为'QA'或'Prod'。你正在建设。请注意,您应该处理配置文件的副本而不是实际的配置文件本身,以避免任何可能的不可恢复的错误。
只需运行构建文件,然后将更新的配置文件移动到部署环境即可完成!
要获得更好的概述,请阅读:
答案 10 :(得分:2)
和我一样,我也设置了'multi'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个seetings并继续。 (我喜欢自动化)
我唯一的想法是在更改后记住'全部清理',因为旧的配置在手动重命名后被“卡住”了。 (我认为会解决你的设置问题。)
我发现这个效果非常好(有一天我会抽空看看MSBuild / NAnt)
答案 11 :(得分: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
}
}
答案 12 :(得分:0)
Web.config。 Web.config是IIS的必需配置文件,用于配置它在Kestrel之前作为反向代理的行为。如果要在IIS上托管它,则必须维护一个web.config。
对于与IIS不相关的其他所有内容,请使用AppSetting.json。 AppSetting.json用于Asp.Net Core托管。 ASP.NET Core使用“ ASPNETCORE_ENVIRONMENT”环境变量来确定当前环境。默认情况下,如果您在不设置此值的情况下运行应用程序,它将自动默认为生产环境并使用“ AppSetting.production.json”文件。通过Visual Studio调试时,它将环境设置为“开发”,因此它使用“ AppSetting.json”。请访问此网站以了解如何在Windows上设置托管环境变量。
App.config是.NET使用的另一个配置文件,主要用于Windows窗体,Windows服务,控制台应用程序和WPF应用程序。当您通过控制台应用程序app.config启动Asp.Net Core托管时。
配置文件的选择取决于您为服务选择的托管环境。如果使用IIS承载服务,请使用Web.config文件。如果使用任何其他托管环境,请使用App.config文件。 参见Configuring Services Using Configuration Files documentation 并查看Configuration in ASP.NET Core.