为每个生产环境发布带有web.config的MVC应用程序

时间:2015-04-07 14:31:45

标签: asp.net-mvc visual-studio-2013 web-deployment msdeploy web-config-transform

我的MVC应用程序包含开发暂存生产环境。开发和暂存基本上是一回事(相同的VM,IIS,DB等);但是,生产托管在负载均衡器后面的4个VM上。每个VM都有自己的DB。例如,部署到VM1的实例与PROD1 DB,VM2-> PROD2等进行通信。

为了部署到Dev和Staging,我使用Debug / Release web.config转换从VS2013到VM进行简单的文件系统部署。对于生产部署,SysAdmin会将在暂存中部署和测试的位复制到每个生产VM。这是为了确保QA在分段中经过测试和验证的内容是我们向生产推广的内容 - 我不想在分段和生产之间进行另一次构建。因此,我们的SysAdmin负责(使用DevOps指导)编辑Staging和Production之间的每个web.config。这基本上包括将connectionString值从"Data Source=STAGINGDB"更改为"Data Source=PROD1"(以及PROD2,PROD3,PROD4)。

我最终想要的是当我发布到Staging时,我想使用标准的Release web.config转换来部署我的web.config;但是,除了这个文件,我还要创建并删除4个附加文件(web.config.PROD1,.PROD2等)。这将允许我们创建忽略现有web.config的脚本(使用Staging设置)并复制/重命名相应的.PROD配置。

我能够(有点)用MSBuild来实现这个目标:

<Project ToolsVersion="12.0" DefaultTargets="Build">
    ...
    <Target Name="Build">
        <TransformXml Source="Web.config" Transform="Web.PROD1.config" Destination="Web.config.PROD1" />
        <TransformXml Source="Web.config" Transform="Web.PROD2.config" Destination="Web.config.PROD2" />
        ...
    </Target>
</Project>

这种方法的主要问题是我必须创建4个基本上冗余的解决方案配置来连接到Transform。除了DB connectionString之外,每个设置都相同。似乎应该有一种更有效的方式。

我可以通过MSBuild调用适当的转换来执行没有解决方案配置的单个转换,例如:

<add name="connectionString" connectionString="PROD1" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />

我应该完全使用其他流程吗?如果我可以坚持下去,我宁愿不使用第三方nuget解决方案。我应该使用.wpp.targets文件吗? XmlPoke?

我想要的工作流程

  1. 右键单击我的MVC应用,然后选择&#34;发布&#34; (文件系统)
  2. 让Release转换完成它们并生成web.config。我有基本的配置。 Debug = Dev,Release = Staging。
  3. WebConfigs

    1. 添加一个自定义步骤,生成另外4个web.config文件
    2. 将所有内容打包,然后发布到Staging服务器,所以我在VM上看到了这一点:
    3. Publish

      我读过的所有内容都让我相信我应该编写自定义的MSBuild步骤,但我不知道我应该做什么(或如何)。这是一些伪代码:

      <Project ToolsVersion="12.0" DefaultTargets="Build">
          ...
          <Target Name="Build">
              <TransformXml Source="Web.config" Transform="[Do-Basic-Transform-On-Conection-String]" Destination="Web.config.PROD1" />
              <TransformXml Source="Web.config" Transform="[Do-Basic-Transform-On-Conection-String]" Destination="Web.config.PROD2" />
              <IncludeFilesInPublish>
                  <FileToInclude>Web.config.PROD1</FileToInclude>
                  <FileToInclude>Web.config.PROD2</FileToInclude>
              </IncludeFilesInPublish>
          </Target>
      </Project>
      
      • 我可以在没有解决方案配置的情况下[Do-Basic-Transform-On-Connection-String]内联吗?我只会更改2 connectionString个值。如果我需要创建一个解决方案配置,这很好......我只是觉得它是完全必要的,特别是如果我可以内联。也许我错了?
      • 如何完成<IncludeFilesInPublish>位,以便在发布期间打包我所做的任何事情,因此我的暂存部署有我的候选发布代码和web.configs可以进行促销。

2 个答案:

答案 0 :(得分:2)

我认为你的问题有两个:1)如何将环境变量或参数(即PROD1)传递到我的xdt转换文件中,所以我只需要使用一个转换文件?和2)< em>如何让MSBuild迭代一组已知的命名项目以产生由此集合中的每个项目区分的输出?

对于第一部分,我断言你的唯一原因可能是问这个是因为你说&#34;我必须创建4个基本上冗余的解决方案配置来连接到变换&#34;,所以如果你的变换采取&#34; PROD1&#34;作为参数,您可以理想地使用一个变换。但是我不确定如果不创建自己的XmlTransform任务就可以做到这一点。 xdt转换工具非常有限。但是关于MSBuild的好处在于它足够灵活,理论上你可以提出自己的转换任务,扩展/子类或行为就像开箱即用。

using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Web.Publishing.Tasks;

namespace Thanks.IllWriteMyOwnTasks
{
    public class MyCustomTransformXml : TransformXml // no idea if you can do this
    {
        public override bool Execute()
        {
            // do stuff here, 
            // maybe declare parameters that you can pass down to base.Execute()
            return true;
        }
    }
}

...

<!--<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.Tasks.dll" />-->
<UsingTask TaskName="MyCustomTransformXml" AssemblyFile="Thanks.IllWriteMyOwnTasks.dll" />

对于第二部分,我认为你可以使用ItemGroup。

<ItemGroup>
    <MyEnvironments Include="PROD1" />
    <MyEnvironments Include="PROD2" />
    <MyEnvironments Include="PROD3" />
    <MyEnvironments Include="PROD4" />
</ItemGroup>  
<Target Name="BeforeBuild">
    <TransformXml Source="Web.config" 
                  Transform="Web.%(MyEnvironments.Identity).config" 
                  Destination="Web.config.%(MyEnvironments.Identity)" />
</Target>

我还没有对此进行过测试,但我认为基于我看到的内容over here,它会自动重复相同的任务,因为它会在此MyEnvironments上进行迭代示例

答案 1 :(得分:1)

您可以在不添加新解决方案配置的情况下将额外的转换文件添加到解决方案中,并按照您自己的示例运行转换(目标除外。&#39; Build&#39;没有工作我):

<Project ToolsVersion="12.0" DefaultTargets="Build">
    ...
    <Target Name="BeforeBuild">
        <TransformXml Source="Web.config" Transform="Web.PROD1.config" Destination="Web.config.PROD1" />
        <TransformXml Source="Web.config" Transform="Web.PROD2.config" Destination="Web.config.PROD2" />
        ...
    </Target>
</Project>

如果您只是更改连接字符串,则转换文件将非常小:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <connectionStrings>
      <add name="MyDB" 
        connectionString="Data Source=PROD1SQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True" 
        xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
    </connectionStrings>
</configuration>

添加上述内容并进行编译后,您需要将新生成的Web.config.PRODX文件添加到您的解决方案中。添加它们之后,只需打开每个文件的属性,并确保其编译操作设置为“内容”。这意味着它们包含在您的部署中。

由于web.PRODX.config转换文件不是解决方案配置的一部分,您可以将它们粘贴在文件夹中以减少混乱。