在.NET MVC 3.0应用程序中,我在appSettings
中有以下配置:
<appSettings>
<add key="SMTPHost" value="mail.domain.com"/>
<add key="SMTPUsername" value="user@gmail.com"/>
<add key="SMTPPort" value="25"/>
<add key="SMTPPwd" value="mypassword"/>
<add key="EmailFrom" value="notific@gmail.com"/>
</appSettings>
为了进行调试,我定义了以下配置转换:
<appSettings>
<add key="SMTPPort" value="58" xdt:Transform="Replace" xdt:Locator="Match(key)" />
</appSettings>
我在调试模式下运行应用程序,但我的SMTP端口仍然从web.config
获取值,而不是web.Debug.config
。
有人能说出这种配置可能出错吗?
答案 0 :(得分:142)
Web.config转换仅作为发布操作的一部分应用。
如果您希望这是app.config
构建操作的一部分,那么您可以使用SlowCheetah - XML Transforms Visual Studio插件:
http://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5
答案 1 :(得分:23)
Visual Studio(2010 - 2017)很遗憾不在您调试时直接支持它,它仅用于发布 - 即使扩展名为SlowCheetah(标记为答案),它也是不适用于我(仅适用于使用app.config而非web.config的项目)。
注意有解决方法 described at codeproject。
它描述了如何修改.msproj文件以通过转换后的版本覆盖当前的web.config。
我首先将该解决方法描述为选项1 ,但我最近发现了另一个选项2 ,这更容易使用(因此您可以向下滚动到选项如果你愿意,直接2:
选项1:我添加了原始代码项目文章中的说明(请参阅上面的链接),因为那里的屏幕截图已经消失,我不知道我不想丢失所有信息:
在开发和调试本地环境时,VS.Net不会进行任何转换。但是,如果你愿意,你可以采取一些措施来实现这一目标。
web.config
并选择添加配置转换 - 这将为您定义的每个配置创建一个从属转换配置。web.config
重命名为web.base.config
。web.config
。它的内容并不重要,因为每次我们进行构建时它都会被覆盖,但我们希望它是项目的一部分,所以 VS.Net 不会给我们“你的项目未配置为调试“弹出窗口。.csproj
项目文件,并将以下TransformXml
任务添加到AfterBuild目标。在这里,您可以看到我将使用web.base.config
转换web.[configuration].config
文件,并将其保存为web.config
。有关详细信息,请查看this Microsoft Q&amp; A,有关如何扩展构建的说明,请查看there。选项2:
基于this回答,我开发了一个简单的控制台应用程序,TransformConfig.exe(使用C#6.0语法):
using System;
using System.Linq;
using Microsoft.Web.XmlTransform;
namespace TransformConfig
{
class Program
{
static int Main(string[] args)
{
var myDocumentsFolder = $@"C:\Users\{Environment.UserName}\Documents";
var myVsProjects = $@"{myDocumentsFolder}\Visual Studio 2015\Projects";
string srcConfigFileName = "Web.config";
string tgtConfigFileName = srcConfigFileName;
string transformFileName = "Web.Debug.config";
string basePath = myVsProjects + @"\";
try
{
var numArgs = args?.Count() ?? 0;
if (numArgs == 0 || args.Any(x=>x=="/?"))
{
Console.WriteLine("\nTransformConfig - Usage:");
Console.WriteLine("\tTransformConfig.exe /d:tgtConfigFileName [/t:transformFileName [/s:srcConfigFileName][/b:basePath]]");
Console.WriteLine($"\nIf 'basePath' is just a directory name, '{basePath}' is preceeded.");
Console.WriteLine("\nTransformConfig - Example (inside PostBuild event):");
Console.WriteLine("\t\"c:\\Tools\\TransformConfig.exe\" /d:Web.config /t:Web.$(ConfigurationName).config /s:Web.Template.config /b:\"$(ProjectDir)\\\"");
Environment.ExitCode = 1;
return 1;
}
foreach (var a in args)
{
var param = a.Trim().Substring(3).TrimStart();
switch (a.TrimStart().Substring(0,2).ToLowerInvariant())
{
case "/d":
tgtConfigFileName = param ?? tgtConfigFileName;
break;
case "/t":
transformFileName = param ?? transformFileName;
break;
case "/b":
var isPath = (param ?? "").Contains("\\");
basePath = (isPath == false)
? $@"{myVsProjects}\" + param ?? ""
: param;
break;
case "/s":
srcConfigFileName = param ?? srcConfigFileName;
break;
default:
break;
}
}
basePath = System.IO.Path.GetFullPath(basePath);
if (!basePath.EndsWith("\\")) basePath += "\\";
if (tgtConfigFileName != srcConfigFileName)
{
System.IO.File.Copy(basePath + srcConfigFileName,
basePath + tgtConfigFileName, true);
}
TransformConfig(basePath + tgtConfigFileName, basePath + transformFileName);
Console.WriteLine($"TransformConfig - transformed '{basePath + tgtConfigFileName}' successfully using '{transformFileName}'.");
Environment.ExitCode = 0;
return 0;
}
catch (Exception ex)
{
var msg = $"{ex.Message}\nParameters:\n/d:{tgtConfigFileName}\n/t:{transformFileName}\n/s:{srcConfigFileName}\n/b:{basePath}";
Console.WriteLine($"TransformConfig - Exception occurred: {msg}");
Console.WriteLine($"TransformConfig - Processing aborted.");
Environment.ExitCode = 2;
return 2;
}
}
public static void TransformConfig(string configFileName, string transformFileName)
{
var document = new XmlTransformableDocument();
document.PreserveWhitespace = true;
document.Load(configFileName);
var transformation = new XmlTransformation(transformFileName);
if (!transformation.Apply(document))
{
throw new Exception("Transformation Failed");
}
document.Save(configFileName);
}
}
}
确保添加DLL "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.XmlTransform.dll"
作为参考(此示例适用于VS 2015,旧版本使用相应的版本号替换路径中的v14.0
,例如v11.0
)。
对于 Visual Studio 2017,,路径的命名架构已更改:例如,对于企业版,它位于:C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\VisualStudio\v15.0\Web
。
我假设对于专业版,您需要在Enterprise
路径中替换Professional
。如果您使用的是预览版,请另外将2017
替换为Preview
。
编译它并将.exe文件放入目录,例如C:\MyTools\
。
<强>用法:强> 您可以在发布后事件中使用它(在项目属性中,选择构建事件,然后编辑构建后事件命令线强>)。命令行参数是(示例):
“C:\ MyTools \ TransformConfig.Exe”/d:Web.config /t:Web.$(ConfigurationName).config /s:Web.Template.config / b:“$(ProjectDir)\”
即。首先是配置文件的名称,然后是转换配置文件,后跟可选的模板配置,后跟包含这两个文件的项目的路径。
我添加了可选的模板配置参数,否则您的原始完整配置将被转换覆盖,这可以通过提供模板来避免。
只需复制原始Web.config并将其命名为Web.Template.config即可创建模板。
注意:
如果您愿意,还可以将TransformConfig.exe
文件复制到上面提到的Microsoft.Web.XmlTransform.dll
所在的Visual Studio路径中,并在需要转换的所有项目中引用它CONFIGS。
对于那些想知道我为什么添加Environment.ExitCode = x;
作业的人:简单地从Main返回一个int对构建事件没有帮助。详情请见here.
如果您要发布项目并且正在使用Web.Template.config,请确保在解决方案中使用正确的配置(通常是Release)执行重建你发表。原因是在调试期间会覆盖Web.Config,否则你最终可能会转换错误的文件。
答案 2 :(得分:21)
回答你的问题并不简单,因为它会带来问题 - 如果你想用Web.debug.config转换Web.config - 应该存储转换效果?在Web.config本身?这会覆盖转换源文件!可能这就是为什么Visual Studio在构建期间不进行转换的原因。
以前的Matt答案是有效的,但您可能希望将它们混合在一起,以便在您将实际的解决方案配置从调试更改为发布等时使用通用解决方案。这是一个简单的解决方案:
Web.config
文件重命名为Web.base.config
- 转换应自动重命名(Web.base.Debug.config
等)<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0" DefaultTargets="TransformWebConfig" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="TransformWebConfig">
<TransformXml Source="Web.base.config" Transform="Web.base.$(CurrentConfig).config" Destination="Web.config" />
</Target>
</Project>
@if exist "%ProgramFiles(x86)%\MSBuild\12.0\bin" set PATH=%ProgramFiles(x86)%\MSBuild\12.0\bin;%PATH%
msbuild $(ProjectDir)transformWebConfig.proj /t:TransformWebConfig /p:CurrentConfig=$(ConfigurationName) /p:TargetProjectName=$(TargetPath)
现在,在构建解决方案时,将创建一个Web.config文件,其中包含有效配置的有效转换。
答案 3 :(得分:4)
您的直接问题已得到解答 - 解释是转换应用于发布,而不是构建。
但是,我认为它没有提供如何实现您想要的目标的解决方案。
我几天来一直在努力解决这个问题,寻找一种方法来保持web.config干净,并根据相应转换文件中的环境设置所有不同的密钥。我的结论是,最简单和最稳定的解决方案是在原始web.config中使用调试值,这样在Visual Studio中进行调试运行时它们总是存在。
然后为您要发布的不同环境创建转换 - 测试,集成,生产 - 无论您拥有什么。现在,在发布时转换web.config文件的内置功能就足够了。无需SlowCheetah或编辑构建事件或项目文件。如果您只有Web项目。
如果您愿意,您还可以在解决方案中使用web.debug.config文件,只是为了保留一个单独的文件,其中包含与开发环境相关的所有值。请确保在Visual Studio中运行时注释不会应用这些值,以防其他人尝试将其用于此目的!
答案 4 :(得分:1)
使用Octopus Deploy(社区版免费),让它为您转换web.config
。步骤进行:
Web.Release.config
Build Action
属性设置为Content
,就像您的主web.config
文件一样。答案 5 :(得分:0)
显然,Visual Studio 2015有一个扩展
https://visualstudiogallery.msdn.microsoft.com/05bb50e3-c971-4613-9379-acae2cfe6f9e
使用此程序包,您可以根据构建配置
转换app.config或任何其他XML文件答案 6 :(得分:0)
最近,基于.NET Framework 2.0的旧版 web.config 存在同样的问题。解决方案是删除web.config的命名空间(配置根节点中 xmlns attibute):
之前:<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
之后:<configuration>
答案 7 :(得分:0)
对于VS 2017,我发现答案here不确定为什么上面没有人引用它,因为它似乎是一个非常受欢迎的解决方案。也很容易。确保您在IOrlandoni于2019年3月5日看到了有关使其在VS 2017和所有版本中都能正常运行的评论。