TFS Build не преобразует web.config, как ожидалось
Цель состоит в том, чтобы TFS собирала и развертывала более 2 различных конфигураций, а файлы преобразования web.config включали в свои выходные данные предполагаемый контент. Это в проекте ASP.NET MVC.
Web.Debug.Config - см. На PasteBin.
Web.Release.Config - см. На PasteBin
Для 2 преобразованных файлов конфигурации их действие сборки установлено на "Нет". Это было изменено, потому что все 3 файла web.*. Config были включены в развертывание.
TFS настроен правильно для построения и развертывания обеих конфигураций. Он разворачивается в 2 места сброса, как и ожидалось. В определении сборки не указаны аргументы MSBuild.
Проблема: 2 встроенных и развернутых веб-сайта имеют один и тот же файл web.config. По сути, это как если бы преобразованные файлы не существовали.
Ожидаемые: указанные изменения (xdt:Transform="Replace"
а также xdt:Transform="Remove"
) будет присутствовать в файлах web.config.
Как вы можете сконфигурировать свой проект или TFS, чтобы обеспечить обработку преобразований web.config и развертывание их выходных данных в правильных местах развертывания? Что еще я могу проверить / изменить?
- Подтвердили, что преобразования хороши - учебник Джошита Вишала с MSBuild в командной строке выдает правильные преобразования!
- В.csproj не было внесено никаких изменений для пост-сборки или развертывания.
- Есть какие-нибудь
xdt
атрибуты используются неправильно или отсутствуют? - В определении сборки не указаны аргументы MSBuild.
- Правильно ли настроены действия по сборке web.config?
- Мы не используем пакеты веб-развертывания или что-то еще. Просто ожидаем, что позже скопируем эти результаты в их различные местоположения веб-сервера.
Если мне не хватает какой-либо важной информации, пожалуйста, оставьте комментарий, и я добавлю любую более важную информацию!
5 ответов
Ранее я делал что-то похожее на другие ответы. Тем не менее, я только что нашел лучшее решение этой проблемы. Просто добавьте "/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.
TFS Team Build 2010 не преобразует автоматически ваши Web.configs. Для этого необходимо добавить настраиваемое действие рабочего процесса в шаблон процесса сборки.
Эдвальд Хофман (Edwald Hofman) имеет хороший блог, в котором объясняется, как модифицировать шаблоны процессов сборки TFS 2010, поэтому я не буду подробно останавливаться на этом здесь.
После того, как вы выяснили, как добавить пользовательские действия в шаблон процесса сборки, добавьте следующее действие в рабочий процесс, я добавил действие после "Перенести файлы в папку размещения". Он использует сборку 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 Expression) в свойство "BinaryLocation".
ПРИМЕЧАНИЕ. Вам необходимо создать класс BuildEngineStub, который реализует интерфейс IBuildEngine, чтобы использовать задачу 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
}
Вот что я использовал. В текущей задаче TransformXml есть ошибка, из-за которой файлы остаются открытыми. Узнайте больше здесь.
Вы можете вызвать эту задачу и развернуть ее для каждой конфигурации, с которой вы работаете.
<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>
Старайтесь не устанавливать платформу сборки - просто удалите "Любой процессор" в ItemToBuild и выберите платформу MSBuild как "Авто"
Падение на самом деле не делает никакого преобразования. Что вам нужно, это добавить /p:DeployOnBuild=True
к аргументам MSBuild.
Это создаст пакет, который затем можно будет использовать для установки веб-сайта либо с помощью командной строки, либо с помощью мастера импорта приложений IIS.
Если вам нужно напрямую опубликовать более одной конфигурации, которая является совершенно другой историей, и именно так я наткнулся на этот пост.