我正在使用这个问题的解决方案,以便App.config
在 Winforms 项目中应用配置更改。我还有一个用于创建可安装 *.msi 文件的项目的安装程序项目。问题是,安装程序中捆绑的配置文件是原始的、未转换的配置文件。因此,即使构建的 winforms 项目的配置文件应用了所有正确的转换,我们也没有在生产安装程序中获取生产连接字符串。
有没有办法强制安装程序项目使用项目构建的输出?
我正在使用这个问题的解决方案,以便App.config
在 Winforms 项目中应用配置更改。我还有一个用于创建可安装 *.msi 文件的项目的安装程序项目。问题是,安装程序中捆绑的配置文件是原始的、未转换的配置文件。因此,即使构建的 winforms 项目的配置文件应用了所有正确的转换,我们也没有在生产安装程序中获取生产连接字符串。
有没有办法强制安装程序项目使用项目构建的输出?
首先:app.config
使用该Primary output
选项不可能使安装项目指向另一个文件。所以我的解决方案将是一个解决方法。我希望你发现它对你的情况有用。
概述:
基本思想是:
app.config
从设置项目中删除强制;app.config
;vdproj
文件,并更改它以匹配转换后的 app.config 的实际输出。一些缺点是:
开始干活:
1) 转到您的安装项目,然后选择主输出对象,右键单击并转到属性。在那里你会发现Exclude Filter
... 添加一个过滤器*.config
,所以它会删除硬编码的 app.config。
2) 在解决方案资源管理器中右键单击您的安装项目 -> 添加 -> 文件...选择任何以 . 结尾的文件.config
。
3) 下载MSBuild 社区任务项目,我推荐 msi 安装程序。
4)卸载你的项目(csproj)并用这个替换另一个问题的代码:
代码:
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<Target Name="AfterCompile" Condition="exists('app.$(Configuration).config')">
<!-- Generate transformed app config in the intermediate directory -->
<TransformXml Source="app.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="app.$(Configuration).config" />
<!-- Force build process to use the transformed configuration file from now on. -->
<ItemGroup>
<AppConfigWithTargetPath Remove="app.config" />
<AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
<TargetPath>$(TargetFileName).config</TargetPath>
</AppConfigWithTargetPath>
</ItemGroup>
<PropertyGroup>
<SetupProjectPath>$(MSBuildProjectDirectory)\$(IntermediateOutputPath)$(TargetFileName).config</SetupProjectPath>
</PropertyGroup>
<!-- Change the following so that this Task can find your vdproj file -->
<FileUpdate Files="$(MSBuildProjectDirectory)\..\Setup1\Setup1.vdproj"
Regex="(.SourcePath. = .8:).*\.config(.)"
ReplacementText="$1$(SetupProjectPath.Replace(`\`,`\\`))$2" />
<FileUpdate Files="$(MSBuildProjectDirectory)\..\Setup1\Setup1.vdproj"
Regex="(.TargetName. = .8:).*\.config(.)"
ReplacementText="$1$(TargetFileName).config$2" />
</Target>
5)必须更改之前的代码,以便它可以找到您的vdproj文件。我在代码中添加了注释,指出您需要在哪里进行更改。
现在,每次构建主项目时,MSBuild 都会更改安装项目,以便它使用正确的 app.config 文件。它可能有缺点,但这种解决方案可以改进并变得更好。如果您需要发表评论,我会尽快回复。
我使用的资源
需要 MSBuild 4.0,因为我需要使用 String 的 Replace 函数,将路径中的单个“\”替换为双“\”。有关在 MSBuild 中使用函数的详细信息,请参阅 MSBuild 属性函数。
我在另一个问题中了解了FileUpdate 任务。官方项目是MSBuild 社区任务项目。
这两个主题对我的发现很重要:
我发现的另一个解决方案是不使用转换,而只使用一个单独的配置文件,例如 app.Release.config。然后将此行添加到您的 csproj 文件中。
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<AppConfig>App.Release.config</AppConfig>
</PropertyGroup>
这将强制部署项目在打包时使用正确的配置文件。
我结合了以下最佳答案以获得完全有效的解决方案,而根本不使用任何外部工具:
1. 设置 App.Config 转换
来源:https ://stackoverflow.com/a/5109530
简而言之:
为每个构建配置手动添加额外的 .config 文件并编辑原始项目文件以包含它们,类似于:
<Content Include="App.config" />
<Content Include="App.Debug.config" >
<DependentUpon>App.config</DependentUpon>
</Content>
<Content Include="App.Release.config" >
<DependentUpon>App.config</DependentUpon>
</Content>
然后在项目文件的末尾包含以下 XML,就在结束</project>
标记之前:
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterCompile" Condition="exists('app.$(Configuration).config')">
<TransformXml Source="app.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="app.$(Configuration).config" />
<ItemGroup>
<AppConfigWithTargetPath Remove="app.config" />
<AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
<TargetPath>$(TargetFileName).config</TargetPath>
</AppConfigWithTargetPath>
</ItemGroup>
</Target>
最后编辑附加的 .config 文件以包含每个构建配置的相应转换:
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!-- transformations here-->
</configuration>
2.在安装项目中包含适当的.config
首先,在主项目的 postbuild 事件中添加一个命令,将适当的转换后的 .config 文件移动到中性位置(例如主bin\
目录):
copy /y "$(TargetDir)$(TargetFileName).config" "$(ProjectDir)bin\$(TargetFileName).config"
(来源:https ://stackoverflow.com/a/26521986 )
打开安装项目并单击“主要输出...”节点以显示属性窗口。在那里,添加一个 ExludeFilter"*.config"
以排除默认(未转换的).config 文件。
(来源:https ://stackoverflow.com/a/6908477 )
最后将转换后的 .config 文件(来自 postbuild 事件)添加到安装项目(添加 > 文件)。
完毕。
您现在可以自由添加构建配置和相应的配置转换,并且您的安装项目将始终包含活动配置的适当 .config。
我在没有外部工具的情况下以不同的方式完成了这项工作:
我添加了一个将目标文件复制到“中性”目录(项目中 /bin 文件夹的根目录)的构建后事件,然后将此文件添加到 .vdproj。部署项目现在选择最新构建的版本:
后期构建命令:
copy /y "$(TargetDir)$(TargetFileName).config" "$(ProjectDir)bin\$(TargetFileName).config"
这在没有任何外部工具的情况下可以满足我的需要,并且可以很好地与 SlowCheetah 转换一起使用。
在部署/设置项目中,上述解决方案或任何文章都不适合我。花了很多天来找出正确的解决方案。最后,这种方法对我有用。
先决条件
我使用名为cct.exe的实用程序来显式转换文件。您可以从这里下载 http://ctt.codeplex.com/
我在安装项目中使用了自定义安装程序来捕获安装事件。
按照以下步骤实现应用配置转换
1)将您想要的配置文件添加到您的项目中并像这样修改您的 .csproj 文件
<Content Include="app.uat.config">
<DependentUpon>app.config</DependentUpon>
</Content>
<Content Include="app.training.config">
<DependentUpon>app.config</DependentUpon>
</Content>
<Content Include="app.live.config">
<DependentUpon>app.config</DependentUpon>
</Content>
我已将它们添加为内容,以便可以将它们复制到输出目录。
2) 将cct.exe添加到您下载的项目中。
3)将自定义安装程序添加到您的项目中,应该如下所示
[RunInstaller(true)]
public partial class CustomInstaller : System.Configuration.Install.Installer
{
string currentLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string[] transformationfiles = Directory.GetFiles(Path.GetDirectoryNam(Assembly.GetExecutingAssembly().Location), "app.*.config");
public CustomInstaller()
{
InitializeComponent();
// Attach the 'Committed' event.
this.Committed += new InstallEventHandler(MyInstaller_Committed);
this.AfterInstall += new InstallEventHandler(CustomInstaller_AfterInstall);
}
void CustomInstaller_AfterInstall(object sender, InstallEventArgs e)
{
try
{
Directory.SetCurrentDirectory(currentLocation);
var environment = Context.Parameters["Environment"];
var currentconfig = transformationfiles.Where(x => x.Contains(environment)).First();
if (currentconfig != null)
{
FileInfo finfo = new FileInfo(currentconfig);
if (finfo != null)
{
var commands = string.Format(@"/C ctt.exe s:yourexename.exe.config t:{0} d:yourexename.exe.config ", finfo.Name);
using (System.Diagnostics.Process execute = new System.Diagnostics.Process())
{
execute.StartInfo.FileName = "cmd.exe";
execute.StartInfo.RedirectStandardError = true;
execute.StartInfo.RedirectStandardInput = true;
execute.StartInfo.RedirectStandardOutput = true;
execute.StartInfo.UseShellExecute = false;
execute.StartInfo.CreateNoWindow = true;
execute.StartInfo.Arguments = commands;
execute.Start();
}
}
}
}
catch
{
// Do nothing...
}
}
// Event handler for 'Committed' event.
private void MyInstaller_Committed(object sender, InstallEventArgs e)
{
XmlDocument doc = new XmlDocument();
var execonfigPath = currentLocation + @"\yourexe.exe.config";
var file = File.OpenText(execonfigPath);
var xml = file.ReadToEnd();
file.Close();
doc.LoadXml(FormatXmlString(xml));
doc.Save(execonfigPath);
foreach (var filename in transformationfiles)
File.Delete(filename);
}
private static string FormatXmlString(string xmlString)
{
System.Xml.Linq.XElement element = System.Xml.Linq.XElement.Parse(xmlString);
return element.ToString();
}
}
在这里,我使用了两个事件处理程序CustomInstaller_AfterInstall,我在其中加载正确的配置文件并转换 . 在MyInstaller_Committed 中,我正在删除应用后在客户端机器上不需要的转换文件。我也在缩进转换后的文件,因为 cct 只是将元素转换为丑陋的对齐方式。
4) 打开您的安装项目并添加项目输出内容文件,以便安装程序可以将 app.uat.config、app.live.config 等配置文件复制到客户端计算机中。
在上一步中,此代码段将加载所有可用的配置文件,但我们需要提供正确的转换文件
string[] transformationfiles = Directory.GetFiles(Path.GetDirectoryNam
(Assembly.GetExecutingAssembly().Location), "app.*.config");
为此,我在安装项目中添加了 UI 对话框以获取当前配置。该对话框为用户提供了选择环境的选项,例如“Live”“UAT”“Test”等。现在将选定的环境传递给您的自定义安装程序并过滤它们。
如果我解释如何添加对话框,如何设置参数等,这将成为冗长的文章,所以请谷歌它们。但想法是改变用户选择的环境。这种方法的优点是您可以在任何环境中使用相同的设置文件。
这是摘要:
添加配置文件
添加cct exe文件
添加自定义安装程序
在安装事件后对 exe.config 应用转换
从客户的机器上删除转换文件
以这样的方式修改安装项目
set up should copy all config files(project output content) and cct.exe into output directory
configure UI dialog with radio buttons (Test,Live,UAT..)
pass the selected value to custom installer
解决方案可能看起来很长,但别无选择,因为 MSI 总是复制 app.config 并且不关心项目构建事件和转换。slowcheetah 仅适用于 clickonce 而不是设置项目
根据 Alec 的回答,这里有一个类似的元素,您可以将其与转换一起使用,并且仍然可以获得它们的全部好处:
<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Content Include="$(OutputPath)$(AssemblyName).dll.config">
<InProject>false</InProject>
<Link>$(AssemblyName).dll.config</Link>
</Content>
</ItemGroup>
这样,您可以使用 SlowCheetah 转换或内置转换来转换您的 .config 文件,然后进入您的 Visual Studio 部署项目(或其他)并将受影响项目的内容包含在您的 Add -> Project Output ... 页面轻松,更改最少。
这个问题很老,但以下内容仍然可以帮助很多人。
我会简单地使用Wix WiFile.exe 以这种方式替换 msi 中的相关文件(为了这个示例,我们将您的 msi称为 yourPackage.msi):
步骤 1. 从命令提示符运行: WiFile.exe "yourPackage.msi" /x "app.exe.config." 以上将从 msi 中提取“错误”的 app.exe.config 文件并将其放置在与您的 msi 相同的目录中;
步骤 2. 将新的 (prod) 配置文件(必须与提取的文件同名:app.exe.config)放在与您的 msi 相同的位置; 这意味着您正在用新的(生产配置文件)覆盖刚刚在上述步骤 1 中提取的 app.exe.config;
第 3 步。从命令提示符运行: WiFile.exe "yourPackage.msi" /u "app.exe.config"。
就这样!
以上可以在几秒钟内完成。如果需要,您可以自动执行任务,例如,将其作为批处理或其他方式运行。
运行上述第 3 步后,您的 msi 将包含新的配置文件,该文件现在将在您的客户端运行安装程序时安装。