TFS Build未按预期转换web.config

时间:2011-01-20 18:43:33

标签: visual-studio-2010 msbuild web-config tfs2010 tfsbuild

目标是让TFS构建并部署2个以上的不同配置,并让web.config转换文件在其输出中包含预期内容。这是在ASP.NET MVC项目中。

alt text

Web.Debug.Config - see on PasteBin
Web.Release.Config - see on PasteBin

2个已转换的配置文件将构建操作设置为无。这是因为所有3个web。*。配置文件都包含在部署中。

正确配置TFS以构建和部署这两种配置。它按预期部署到2个丢弃位置。在构建定义中没有指定MSBuild Arguments。

alt text

问题:2个构建和部署的网站具有相同的web.config文件。基本上就好像转换的文件不存在一样。

预期:指定的更改(xdt:Transform="Replace"xdt:Transform="Remove")将出现在web.config文件中。

如何配置项目或TFS以确保处理web.config转换并将其输出部署到正确的部署位置?我还可以检查/修改什么?

  • 确认转换正常 - Vishal's Joshit's tutorial with the MSBuild on the command line输出正确的转换!
  • 对于任何后期构建或部署,都没有对.csproj进行任何修改。
  • 是否有任何xdt属性被滥用或遗失?
  • 构建定义中没有指定MSBuild参数。
  • 是否正确设置了web.config Build Actions?
  • 我们没有使用Web部署包或任何其他内容。只需要在以后将这些输出复制到各个网络服务器位置。

如果我遗漏了任何重要信息,请发表评论,我会提供更多相关信息!

5 个答案:

答案 0 :(得分:20)

以前我一直在做与其他答案类似的事情。但是,我刚刚发现了解决这个问题的更好方法。只需添加" / p:UseWPP_CopyWebApplication = true / p:PipelineDependsOnBuild = false"到您的MSBuild参数。我刚刚在我的一个TFS版本上尝试过它,它运行得很好。

我在这里找到了一个很棒的提示:http://www.andygeldman.com/index.php/2011/10/web-and-app-config-transformations-with-tfs-build

答案 1 :(得分:8)

TFS Team Build 2010不会自动转换您的Web.configs。您需要向构建过程模板添加自定义工作流活动才能完成此任务。

Edwald Hofman有一个很好的博客,解释了如何修改TFS 2010构建过程模板,所以我不会在这里深入探讨。

http://www.ewaldhofman.nl/post/2010/04/29/Customize-Team-Build-2010-e28093-Part-4-Create-your-own-activity.aspx

在弄清楚如何将自定义活动添加到构建过程模板后,将以下活动添加到工作流程中,我在“将文件丢弃到删除位置”之后添加了活动。它利用Microsoft.Web.Publishing.Tasks程序集(位于:C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web)来执行转换:

/// <summary>
/// Transforms configuration files using TransformXml
/// </summary>
[BuildActivity(HostEnvironmentOption.All)]
public sealed class WebConfigTransform : CodeActivity
{
    #region Public Properties

    /// <summary>
    /// The binaries folder
    /// </summary>
    [RequiredArgument]
    public InArgument<string> BinariesLocation { get; set; }

    #endregion

    #region Overrides of CodeActivity

    /// <summary>
    /// When implemented in a derived class, performs the execution of the activity.
    /// </summary>
    /// <param name="context">The execution context under which the activity executes.</param>
    protected override void Execute(CodeActivityContext context)
    {
        var binariesFolder = context.GetValue(BinariesLocation);

        foreach (var sourceFolder in Directory.GetDirectories(Path.Combine(binariesFolder, "_PublishedWebsites")))
        {
            var sourceFile = Path.Combine(sourceFolder, "Web.config");
            if (File.Exists(sourceFile))
            {
                var filesToTransform = Directory.GetFiles(sourceFolder, "Web.*.config");


                foreach (var fileToTransform in filesToTransform)
                {

                    var tempSourceFile = Path.GetTempFileName();
                    var tempTransformFile = Path.GetTempFileName();

                    File.Copy(sourceFile, tempSourceFile, true);
                    File.Copy(fileToTransform, tempTransformFile, true);

                    var transformation = new TransformXml
                    {
                        BuildEngine = new BuildEngineStub(),
                        Source = tempSourceFile,
                        Transform = tempTransformFile,
                        Destination = fileToTransform
                    };

                    transformation.Execute();
                }
            }
        }
    }

    #endregion
}

您需要在工作流程中传递droplocation。当您添加工作流程时,右键单击活动,然后转到属性,并将“DropLocation”(VB表达式)粘贴到属性“BinaryLocation”

注意:您需要创建一个实现IBuildEngine接口的BuildEngineStub类,以便使用MSBuild任务。这是我用过的东西

public class BuildEngineStub : IBuildEngine
{
        #region IBuildEngine Members

        public bool BuildProjectFile(string projectFileName, string[] targetNames,
                                     IDictionary globalProperties,
                                     IDictionary targetOutputs)
        {
            throw new NotImplementedException();
        }

        public int ColumnNumberOfTaskNode
        {
            get { return 0; }
        }

        public bool ContinueOnError
        {
            get { return false; }
        }

        public int LineNumberOfTaskNode
        {
            get { return 0; }
        }

        public string ProjectFileOfTaskNode
        {
            get { return ""; }
        }

        public void LogCustomEvent(CustomBuildEventArgs e)
        {
            Console.WriteLine("Custom: {0}", e.Message);
        }

        public void LogErrorEvent(BuildErrorEventArgs e)
        {
            Console.WriteLine("Error: {0}", e.Message);
        }

        public void LogMessageEvent(BuildMessageEventArgs e)
        {
            Console.WriteLine("Message: {0}", e.Message);
        }

        public void LogWarningEvent(BuildWarningEventArgs e)
        {
            Console.WriteLine("Warning: {0}", e.Message);
        }

        #endregion
    }

答案 2 :(得分:4)

这是我一直在使用的。当前的TransformXml任务有一个文件打开的错误。阅读更多here

您可以调用此任务并为您正在使用的每个配置进行部署。

<Target Name="TransformWebConfig">

    <PropertyGroup>
        <_tempSourceFile>$([System.IO.Path]::GetTempFileName())</_tempSourceFile>
        <_tempTransformFile>$([System.IO.Path]::GetTempFileName())</_tempTransformFile>
    </PropertyGroup>

    <Copy SourceFiles="$(_websiteDirectory)\Web.config" DestinationFiles="$(_tempSourceFile)"/>
    <Copy SourceFiles="$(_websiteDirectory)\Web.$(_transformConfiguration).config" DestinationFiles="$(_tempTransformFile)"/>

    <MSBuild.Community.Tasks.Attrib Files="$(_websiteDirectory)\Web.config" ReadOnly="false" />

    <TransformXml Source="$(_tempSourceFile)"
                  Transform="$(_tempTransformFile)"
                  Destination="$(_websiteDirectory)\Web.config"
                  StackTrace="false" />
</Target>

答案 3 :(得分:0)

Drop实际上并没有进行任何转换。您需要的是将/p:DeployOnBuild=True添加到MSBuild参数。

这将创建一个包,然后可以通过命令行或使用IIS导入应用程序向导来安装网站。

如果你想要的是直接发布多个配置,这是另一个故事,那就是我偶然发现这篇文章。

答案 4 :(得分:0)

尝试不设置构建平台 - 基本删除ItemToBuild中的“任何CPU”并选择MSBuild平台为“自动”