Преобразование Web Config не работает

В приложении .NET MVC 3.0 у меня есть следующая конфигурация в appSettings:

web.config

<appSettings>
<add key="SMTPHost" value="mail.domain.com"/>
    <add key="SMTPUsername" value="[email protected]"/>
    <add key="SMTPPort" value="25"/>
    <add key="SMTPPwd" value="mypassword"/>
    <add key="EmailFrom" value="[email protected]"/>
</appSettings>

Для отладки у меня есть следующее конфигурационное преобразование:

web.Debug.config

<appSettings>
    <add  key="SMTPPort" value="58" xdt:Transform="Replace" xdt:Locator="Match(key)" />
</appSettings>

И я запускаю приложение в режиме отладки, но мой SMTP-порт по-прежнему принимает значение из web.config, а не web.Debug.config.

Кто-нибудь может предположить, что может быть неправильным в этой конфигурации?

Ответ 1

Преобразования Web.config применяются только как часть операции публикации.

Если вы хотите, чтобы это было выполнено в рамках операции сборки app.config, вы можете использовать плагин SlowCheetah - XML Transforms Visual Studio:

http://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5

Ответ 2

Visual Studio (2010 - 2017), к сожалению, не поддерживает его напрямую во время отладки, он предназначен только для публикации - даже с расширением SlowCheetah (помеченный ответ) он не работает для меня (только для проектов, использующих app.config, а не web.config).

Обратите внимание, что есть обходной путь, описанный в codeproject.

Он описывает, как изменить файл .msproj для перезаписи текущего файла web.config в преобразованной версии.

Сначала я опишу этот обходной путь как вариант 1, но недавно я обнаружил другой вариант 2, который проще в использовании (поэтому вы можете прокрутить вниз до варианта 2, если хотите):


Вариант 1: я добавил инструкции, взятые из оригинальной статьи codeproject (см. Ссылку выше), потому что снимки экрана там уже пропали, и я не хочу терять всю информацию:

VS.Net не выполняет никаких преобразований, когда вы разрабатываете и просто отлаживаете свою локальную среду. Но есть некоторые шаги, которые вы можете сделать, чтобы это произошло, если хотите.

  • Сначала создайте необходимые конфигурации в VS.Net, предполагая, что отладки и выпуска по умолчанию недостаточно для того, что вы пытаетесь выполнить.
  • Щелкните правой кнопкой мыши на web.config и выберите " Добавить преобразования конфигурации" - это создаст зависимую конфигурацию преобразования для каждой из определенных конфигураций.
  • Теперь вы можете переименовать ваш web.config в web.base.config.
  • Добавьте web.config в ваш проект. Не имеет значения, что находится в нем, потому что он будет перезаписываться каждый раз, когда мы делаем сборку, но мы хотим, чтобы это было частью проекта, поэтому VS.Net не дает нам всплывающее окно "Ваш проект не настроен для отладки". вверх.
  • Отредактируйте .csproj проекта .csproj и добавьте следующую задачу TransformXml в цель AfterBuild. Здесь вы можете видеть, что я буду преобразовывать файл web.base.config используя web.[configuration].config и он сохранит его как web.config. Для получения дополнительной информации, пожалуйста, проверьте этот Microsoft Q & A, а также инструкции, как продлить сборки, посмотрите там.

Вариант 2:

Основываясь на этом ответе, я разработал простое консольное приложение TransformConfig.exe (в синтаксисе С# 6.0):

using System;
using System.Linq;
using Microsoft.Web.XmlTransform;

namespace TransformConfig
{

  class Program
  {
    static int Main(string[] args)
    {
        var myDocumentsFolder = [email protected]"C:\Users\{Environment.UserName}\Documents";
        var myVsProjects = [email protected]"{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)
                                    ? [email protected]"{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, для более старых версий замените v14.0 в пути на соответствующий номер версии, например v11.0).

Для Visual Studio 2017 схема именования пути изменилась: например, для корпоративной версии она находится здесь: C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\VisualStudio\v15.0\Web.
Я предполагаю, что для профессиональной версии вам нужно заменить Enterprise в пути на Professional. Если вы используете предварительную версию, дополнительно замените 2017 на Preview.

Скомпилируйте его и поместите файл .exe в каталог, например, C:\MyTools\.

Использование: Вы можете использовать его в своем событии после сборкисвойствах проекта выберите " Создать события", затем отредактируйте командную строку события после сборки). Параметры командной строки (пример):

"C:\MyTools\TransformConfig.Exe"/d:Web.config/t:Web.$(ConfigurationName).config/s:Web.Template.config/b: "$ (ProjectDir) \"

то есть сначала имя файла конфигурации, затем файл конфигурации преобразования, затем необязательный шаблон конфигурации, а затем путь к вашему проекту, содержащему оба файла.

Я добавил необязательный параметр конфигурации шаблона, потому что в противном случае исходная полная конфигурация будет перезаписана преобразованием, чего можно избежать, предоставив шаблон.

Создайте шаблон, просто скопировав исходный файл Web.config и назовите его Web.Template.config.

Замечания:

  • При желании вы также можете скопировать файл TransformConfig.exe в указанный выше путь Visual Studio, где находится файл Microsoft.Web.XmlTransform.dll и обращаться к нему во всех ваших проектах, где вам необходимо преобразовать свои конфигурации.

  • Для тех из вас, кому интересно, почему я добавил Environment.ExitCode = x; назначения: Простой возврат int из Main не помог в событии сборки. Подробности здесь.

  • Если вы публикуете свой проект и используете Web.Template.config, перед публикацией убедитесь, что вы выполнили перестройку своего решения с правильной конфигурацией (обычно Release). Причина в том, что Web.Config перезаписывается во время отладки, и в противном случае вы можете преобразовать неправильный файл.

Ответ 3

Ответ на ваш вопрос непрост, потому что он создает проблему - если вы хотите преобразовать Web.config с Web.debug.config - где должен сохраняться эффект преобразования? В самом Web.config? Это заменит исходный файл преобразования! Вероятно, именно поэтому Visual Studio не делает преобразований во время сборки.

Предыдущий ответ Matt действителен, но вы можете смешать их с общим решением, которое работает, когда вы фактически меняете конфигурацию активного решения от отладки до выпуска и т.д. Вот простое решение:

  • Создайте конфигурационные конфигурации для конфигураций (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>
  1. Перейдите к свойствам вашего проекта, выберите Сборка событий и добавьте следующий контент в Командная строка событий после сборки:
@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)

Теперь, когда вы создадите свое решение, файл Web.config будет создан с действительными преобразованиями для активной конфигурации.

Ответ 4

На ваш вопрос был дан ответ - объяснение заключается в том, что преобразование применяется для публикации, а не для сборки.

Однако я думаю, что он не предлагает решения о том, как добиться того, что вы хотите сделать.

Я уже несколько дней борюсь с этой точной проблемой, пытаясь сохранить чистоту web.config и установить все ключи, которые зависят от среды в соответствующих файлах преобразования. Я пришел к выводу, что самым простым и стабильным решением является использование отладочных значений в исходном файле web.config, поэтому они всегда присутствуют, когда вы выполняете отладки в Visual Studio.

Затем создайте преобразования для разных сред, которые вы хотите опубликовать, - тест, интеграция, производство - все, что у вас есть. Для этого достаточно встроенных функций для преобразования файлов web.config в публикации. Нет необходимости в SlowCheetah или редактировании событий сборки или файлов проекта. Если у вас есть только веб-проекты.

Если вы хотите, вы также можете иметь файл web.debug.config в своем решении, просто чтобы сохранить отдельный файл со всеми значениями, относящимися к среде разработки. Обязательно укажите в нем, что значения не применяются при работе в Visual Studio, хотя, если кто-то попытается использовать его для этой цели!

Ответ 5

Используйте Octopus Deploy (версия сообщества бесплатна) и пусть он преобразует web.config для вас. Шаги:

Что это! Осьминог сделает все остальное без какой-либо специальной конфигурации. Развертывание веб-сайта IIS по умолчанию сделает это из коробки: введите описание изображения здесь

Ответ 7

Недавно у меня была такая же проблема со старым файлом web.config, основанным на .NET Framework 2.0. Решением было просто удалить пространство имен web.config(xmlns attibute в корневом узле конфигурации):

ДО: <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">

ПОСЛЕ: <configuration>

Ответ 8

для VS 2017 я нашел ответ здесь, не уверенный, почему никто не ссылался на него выше, поскольку это, кажется, очень популярное решение. Очень легко тоже. Убедитесь, что вы видите комментарий от IOrlandoni о Mar5 2019 для того, чтобы заставить его работать в VS 2017 и всех версиях.

В основном это два степпера. Вы редактируете csproj с помощью приведенного ниже кода, а затем создаете новый файл web.config.base. После этого любая сборка перезапишет ваш web.config с преобразованием.

    <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\WebApplications\Microsoft.WebApplication.targets" />
<Target Name="BeforeBuild">
  <TransformXml Source="Web.Base.config" Transform="Web.$(Configuration).config" Destination="Web.config" />
</Target>