Webconfiguration转换不起作用
在.NET MVC 3.0应用程序中,我在appSettings
有以下configuration:
web.config中
<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>
为了debugging,我定义了以下configuration转换:
web.Debug.config
<appSettings> <add key="SMTPPort" value="58" xdt:Transform="Replace" xdt:Locator="Match(key)" /> </appSettings>
我以debugging模式运行应用程序,但是我的SMTP端口仍然从web.config
获取值,而不是web.Debug.config
。
任何人都可以提出什么可能是错误的这种configuration?
Web.config转换仅作为发布操作的一部分应用。
如果您希望将其作为构build操作的一部分来完成,那么您可以使用SlowCheetah – XML转换Visual Studio插件:
http://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5
不幸的是, Visual Studio(2010 – 2017)在debugging时不直接支持它,它仅用于发布 – 即使使用扩展SlowCheetah(标记答案),它也不适用于我(仅适用于使用app.config的项目,而不适用于web.config中)。
请注意 , 在codeproject中描述了一个解决方法 。
它描述了如何修改.msproj文件以通过转换的版本覆盖当前的web.config。
我将首先描述解决方法,如选项1 ,但我最近发现了另一个选项2 ,它更容易使用(所以你可以直接滚动到选项2,如果你喜欢):
选项1:我添加了原始代码项目文章 (请参阅上面的链接)中的说明,因为那里的屏幕截图已经消失了,我不想丢失整个信息:
VS.Net在开发和debugging本地环境时不会做任何转换。 但是,如果您愿意,还可以采取一些措施来实现这一目标。
- 首先,在VS.Net中创build你想要的configuration,假定默认的debugging和发布不足以完成你想要完成的任务。
- 右键单击你的
web.config
并selectAdd Config Transforms – 这将为你定义的每个configuration创build一个相关的转换configuration。 - 现在你可以将你的
web.config
重命名为web.base.config
。 - 添加一个
web.config
到你的项目。 无关紧要,因为每次构build时它都会被覆盖,但我们希望它是项目的一部分,所以VS.Net不会给我们“你的项目没有configuration为debugging”popup窗口,向上。 - 编辑您的
.csproj
项目文件 ,并将下面的TransformXml
任务添加到AfterBuild目标中。 在这里你可以看到我将使用web.[configuration].config
来转换web.base.config
文件,并将其保存为web.config
。 有关详细信息,请查看此 Microsoft Q&A。
选项2:
基于这个答案,我开发了一个简单的控制台应用程序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,旧版本用适当的版本号replacepath中的v14.0
,例如v11.0
)。
对于Visual Studio 2017,path的命名架构已经更改:例如,对于企业版本,它位于: C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\VisualStudio\v15.0\Web
。
我认为,对于专业版本,您需要用专业版replacepath中的Enterprise
。 如果您正在使用预览版本,请另外通过Preview
取代2017
。
编译它并将.exe文件放到一个目录中,例如C:\MyTools\
。
用法:您可以在后期构build事件中使用它(在项目属性中 ,select构build事件 ,然后编辑后期构build事件命令行 )。 命令行参数是(示例):
“C:\ MyTools \ TransformConfig.Exe”/d:Web.config /t:Web.$(ConfigurationName).config /s:Web.Template.config / b:“$(ProjectDir)\”
即首先configuration文件的名称,然后是转换configuration文件,然后是可选的模板configuration,然后是包含这两个文件的项目的path。
我已经添加了可选的模板configuration参数,否则您的原始完整的configuration将被覆盖转换,这可以通过提供一个模板来避免。
通过简单地复制原始的Web.config来创build模板,并将其命名为Web.Template.config。
注意:
-
如果您愿意,也可以将
TransformConfig.exe
文件复制到上面提到的Microsoft.Web.XmlTransform.dll
所在的Visual Studiopath中,并在需要转换configuration的所有项目中引用它。 -
对于那些想知道为什么我添加了
Environment.ExitCode = x;
任务:简单地返回一个来自Main的int没有帮助build立事件。 在这里看到细节。 -
如果您正在发布您的项目并且正在使用Web.Template.config,请确保在发布之前使用正确的configuration(通常为发行版)对解决scheme进行了重build 。 原因是Web.Config在debugging过程中被覆盖,否则最终可能会转换错误的文件。
回答你的问题并不简单,因为它带来了问题 – 如果你想用Web.debug.config来转换Web.config – 应该存储转换效果吗? 在Web.config本身? 这将覆盖转换源文件! 可能这就是为什么Visual Studio不在构build过程中进行转换的原因。
以前的马特答案是有效的,但你可能想混合他们有一个通用的解决scheme,当你实际上改变活动解决schemeconfiguration从debugging到发布等。这里有一个简单的解决scheme:
- 为configuration创buildconfiguration转换(Debug,Release等)
- 将
Web.config
文件重命名为Web.base.config
– 转换应相应地自动重命名(Web.base.Debug.config
等) - 将下面的transformWebConfig.proj XML文件添加到您的项目文件夹中:
<?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>
- 导航到您的项目属性,select构build事件 ,并将以下内容添加到Post-build事件命令行中 :
@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)
现在,当你build立你的解决scheme时,将会创build一个Web.config文件,其中包含有效的主动configuration转换。
使用Octopus Deploy (社区版是免费的),让它为你改变web.config
。 脚步:
- 设置八达通来部署您的Web应用程序
- 确保您的
Web.Release.config
将Build Action
属性设置为Content
,就像您的主web.config
文件一样。
而已! 八达通将不做任何特别的configuration。 默认的IIS网站部署将开箱即用:
显然,Visual Studio 2015有一个扩展
https://visualstudiogallery.msdn.microsoft.com/05bb50e3-c971-4613-9379-acae2cfe6f9e
这个包使您能够根据构buildconfiguration来变换您的app.config或任何其他XML文件
你的直接问题已经得到了回答 – 解释是这个转换应用于发布,而不是构build。
但是,我认为它不提供如何实现你想要做的解决scheme。
我一直在为这个确切的问题奋斗了几天,寻找一种方法来保持web.config清洁,并设置所有的密钥,取决于各自的转换文件中的环境。 我的结论是,最简单和最稳定的解决scheme是在原始web.config中使用debugging值,这样,当您在Visual Studio中执行debugging时,它们总是存在。
然后为您想发布的不同环境创build转换 – testing,集成,生产 – 无论您拥有什么样的环境。 现在内置的在发布上转换web.config文件的function就足够了。 无需SlowCheetah或编辑生成事件或项目文件。 如果你只有web项目是。
如果你愿意,你也可以在你的解决scheme中使用web.debug.config文件,只保留一个单独的文件,其中包含与开发环境相关的所有值。 请务必在其中注释,在Visual Studio中运行时不会应用这些值,以防其他人尝试将其用于此目的!