Transformacja Web Config nie działa

88

W aplikacji .NET MVC 3.0 mam następującą konfigurację w 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>

Do debugowania mam zdefiniowaną następującą transformację konfiguracji:

web.Debug.config

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

Uruchamiam aplikację w trybie debugowania, ale mój port SMTP nadal pobiera wartość z pliku web.config, nie web.Debug.config.

Czy ktoś może podpowiedzieć, co może być nie tak w tej konfiguracji?

HaBo
źródło

Odpowiedzi:

156

Transformacje Web.config są stosowane tylko jako część operacji publikowania.

Jeśli chcesz, aby zostało to zrobione w ramach app.configoperacji kompilacji, możesz użyć wtyczki SlowCheetah - XML ​​Transforms Visual Studio:

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

devdigital
źródło
1
Dziękuję bardzo, że zaoszczędziłeś mi dużo czasu.
HaBo
3
wow zajęło mi 2 godziny, aby znaleźć tę odpowiedź. Dzięki za opublikowanie tego, wyrywałabym sobie włosy.
Peanut
Wygląda na to, że w programie Visual Studio 2015 (Web) transformacje .config są teraz funkcją wbudowaną, więc nie potrzebujesz już SlowCheetah. Ale wbudowane transformacje zostaną zastosowane tylko wtedy, gdy opublikujesz aplikację, a nie, jeśli ją uruchomisz. Tutaj możesz zobaczyć , jak to rozwiązałem.
Matt
1
Nie wiem, dlaczego tego używać, podczas gdy odpowiedź @ komsky zapewnia proste i przejrzyste rozwiązanie.
Csaba Toth
1
SlowCheetah jest świetny, ale z własnej dokumentacji: „W przypadku projektów internetowych pliki są przekształcane podczas publikowania lub pakowania aplikacji”. Innymi słowy, nie podczas debugowania.
Doug,
31

Visual Studio (2010-2019) niestety nie obsługuje go bezpośrednio podczas debugowania, jest przeznaczony tylko do publikacji - nawet z rozszerzeniem SlowCheetah (zaznaczona odpowiedź) nie działa dla mnie (tylko dla projektów korzystających z app.config zamiast web.config).

Zauważ, że istnieje obejście opisane w codeproject .

Opisuje, jak zmodyfikować plik .msproj, aby nadpisać bieżący plik web.config przekształconą wersją.

Najpierw opiszę to obejście jako opcję 1 , ale niedawno odkryłem inną opcję 2 , która jest łatwiejsza w użyciu (więc możesz przewinąć bezpośrednio w dół do opcji 2, jeśli chcesz):


Opcja 1: Dodałem instrukcje zaczerpnięte z oryginalnego artykułu codeproject (patrz link powyżej), ponieważ zrzuty ekranów już tam nie ma, a nie chcę stracić całej informacji:

VS.Net nie dokonuje żadnych zmian podczas programowania i debugowania lokalnego środowiska. Ale jest kilka kroków, które możesz zrobić, aby tak się stało, jeśli chcesz.

  • Najpierw utwórz żądane konfiguracje w VS.Net , zakładając, że domyślne debugowanie i wydanie nie wystarczą do tego, co próbujesz osiągnąć.
  • Kliknij prawym przyciskiem myszy web.configi wybierz Dodaj konfigurację transformacji - spowoduje to utworzenie zależnej konfiguracji transformacji dla każdej zdefiniowanej konfiguracji.
  • Teraz możesz zmienić nazwę web.configna web.base.config.
  • Dodaj web.configdo swojego projektu. Nie ma znaczenia, co w niej jest, ponieważ będzie nadpisany za każdym razem robimy build ale chcemy to część projektu tak VS.Net nie dają nam „Twój projekt nie jest skonfigurowany do debugowania” Pop- w górę.
  • Edytuj .csprojplik projektu i dodaj następujące TransformXmlzadanie do elementu docelowego AfterBuild. Tutaj możesz zobaczyć, że będę przekształcał web.base.configplik przy użyciu web.[configuration].configi zapisze go jako web.config. Aby uzyskać szczegółowe informacje, proszę sprawdzić to Microsoft Q & A, i instrukcje Jak przedłużyć build, spójrz tam .

Opcja 2:

Na podstawie tej odpowiedzi opracowałem prostą aplikację konsolową TransformConfig.exe (w składni C # 6.0):

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

namespace TransformConfig
{

  class Program
  {
    static int Main(string[] args)
    {
        var myDocumentsFolder = $@"C:\Users\{Environment.UserName}\Documents";
        var myVsProjects = $@"{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)
                                    ? $@"{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);
    }

  }
}

Upewnij się, że dodano bibliotekę DLL "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.XmlTransform.dll"jako odwołanie (ten przykład dotyczy programu VS 2015, w przypadku starszych wersji należy zastąpić v14.0w ścieżce odpowiedni numer wersji, np v11.0.).

Dla Visual Studio 2017, schemat nazewnictwa dla ścieżki nie zmieniło: Na przykład dla wersji Enterprise jest tutaj: C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\VisualStudio\v15.0\Web.
Zakładam, że dla wersji profesjonalnej trzeba Enterprisew ścieżce wymienić wg Professional. Jeśli używasz wersji zapoznawczej, dodatkowo zamień 2017na Preview.

Oto omówienie, jak zmieniła się ścieżka dla różnych wersji programu Visual Studio (jeśli nie masz wersji Enterprise, może być konieczne zastąpienie Enterpriseprzez Professionalw ścieżce):

        Ścieżka do Microsoft.Web.XmlTransform.dllwersji VS (dla )
2015                   C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\Web
2017                   C:\Program Files (x86)\Microsoft Visual Studio\2017\
                          Enterprise\MSBuild\Microsoft\VisualStudio\v15.0\Web
2019                  C:\Program Files (x86)\Microsoft Visual Studio\2019\
                          Enterprise\MSBuild\Microsoft\VisualStudio\v16.0\Web

Skompiluj go i umieść plik .exe w katalogu np C:\MyTools\.

Użycie: Możesz go użyć w zdarzeniu po kompilacji (we właściwościach projektu wybierz Zdarzenia kompilacji , a następnie edytuj wiersz poleceń zdarzenia po kompilacji ). Parametry wiersza poleceń to (przykład):

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

tj. najpierw nazwa pliku konfiguracyjnego, następnie plik konfiguracyjny transformacji, następnie opcjonalna konfiguracja szablonu, a następnie ścieżka do projektu zawierającego oba pliki.

Dodałem opcjonalny parametr konfiguracji szablonu, ponieważ w przeciwnym razie oryginalna kompletna konfiguracja zostałaby nadpisana przez transformację, czego można uniknąć, udostępniając szablon.

Utwórz szablon, po prostu kopiując oryginalny plik Web.config i nadaj mu nazwę Web.Template.config.

Uwaga:

  • Jeśli wolisz, możesz również skopiować TransformConfig.exeplik do wspomnianej powyżej ścieżki programu Visual Studio, w której Microsoft.Web.XmlTransform.dllznajduje się plik, i odwoływać się do niego we wszystkich projektach, w których musisz przekształcić konfiguracje.

  • Dla tych z Was, którzy zastanawiają się, dlaczego dodałem Environment.ExitCode = x;zadania: Zwrócenie int z Main nie pomogło w zdarzeniu kompilacji. Zobacz szczegóły tutaj.

  • Jeśli publikujesz swój projekt i używasz pliku Web.Template.config, upewnij się, że przed opublikowaniem dokonałeś przebudowy rozwiązania z odpowiednią konfiguracją (zwykle Release). Powodem jest to, że plik Web.Config jest nadpisywany podczas debugowania iw przeciwnym razie może skończyć się przekształceniem niewłaściwego pliku.

Matt
źródło
1
Wygląda na to, że post CodeProject jest sfałszowany. Użył zrzutów ekranu do swoich próbek kodu, a teraz, odkąd jego blog nie działa, przeszły one do historii.
Eric Lloyd,
3
Tak, niestety zrzuty ekranu zniknęły. Ale przynajmniej tekst artykułu wciąż tam jest, opisujący podejście. Dodałem opis tekstowy do mojej odpowiedzi, aby jej nie zgubić.
Matt
1
To prawda, może można spróbować skontaktować się z autorem Jamesem Colemanem w codeproject, aby to naprawić. Nie jestem jednak pewien, czy nadal tam jest aktywny. @ThomasTeilmann
Matt
Myślę, że może to być podobne do tego, co było na utraconych zrzutach ekranu. Wydaje się, że osiąga ten sam podstawowy wynik. stackoverflow.com/a/6437192/1003916
user1003916
22

Odpowiedź na twoje pytanie nie jest prosta, ponieważ stwarza problem - jeśli chcesz przekształcić Web.config za pomocą Web.debug.config - gdzie powinien być przechowywany efekt transformacji? W samym Web.config? Spowoduje to nadpisanie pliku źródłowego transformacji! Prawdopodobnie dlatego Visual Studio nie wykonuje transformacji podczas kompilacji.

Poprzednia odpowiedź Matta jest prawidłowa, ale możesz chcieć je wymieszać, aby uzyskać ogólne rozwiązanie, które działa, gdy faktycznie zmienisz konfigurację aktywnego rozwiązania z debugowania na wydanie itp. Oto proste rozwiązanie:

  1. Utwórz transformacje konfiguracji dla konfiguracji (debugowanie, wydanie itp.)
  2. Zmień nazwę Web.configpliku na Web.base.config- transformacje powinny automatycznie odpowiednio zmienić nazwę ( Web.base.Debug.configitp.)
  3. Dodaj następujący plik XML transformWebConfig.proj do folderu projektu:
<?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. Przejdź do właściwości projektu, wybierz zdarzenia kompilacji i dodaj następującą zawartość do wiersza poleceń zdarzenia po kompilacji :
@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)

Teraz podczas budowania rozwiązania zostanie utworzony plik Web.config z poprawnymi przekształceniami dla aktywnej konfiguracji.

komsky
źródło
Najczystsza i najlepsza odpowiedź. Kilka pytań: 1. Dlaczego walidacja XML mówi, że element TransformXml jest nieprawidłowy w elemencie docelowym? (przy okazji kompilacja działa). 2. Teraz, gdy wygeneruje to prawdziwy Web.Config, nadal dodaję Web.Config do projektu. Teraz za każdym razem, gdy przełączam się między debugowaniem / wydaniem, plik web.config ulegnie zmianie, ale niekoniecznie chcę wprowadzać to cały czas do repozytorium źródłowego.
Csaba Toth
1. Nie bardzo wiem, jak VS sprawdza poprawność tego XML ze schematem, ale to ostrzeżenie jest częste, więc możesz je zignorować. 2. To zależy od używanego repozytorium, ale możesz na przykład użyć wpisu w pliku git.ignore.
komsky
4
To zadziałało dobrze dla mnie - po prostu zmieniłem 12 w pliku zdarzenia kompilacji i pliku proj na bieżącą wersję. W przypadku zdarzenia post-build, którego użyłem: '"$(MSBuildBinPath)\msbuild.exe" $(ProjectDir)TransformWebConfig.proj /t:TransformWebConfig /p:CurrentConfig=$(ConfigurationName) /p:TargetProjectName=$(TargetPath) i zaktualizowałem v12.0do v14.0w pliku .proj.
Jovie
1
Dla VS 2017 modyfikuj co 12.0do14.0
Csaba Toth
1
1) nie zapomnij dołączyć wygenerowanego pliku web.config do projektu internetowego, w przeciwnym razie nie zostanie on skopiowany do folderu docelowego po opublikowaniu. 2) jeśli serwer kompilacji nie ma tych dwóch plików, po prostu skopiuj je na serwer „Microsoft.Web.Publishing.Tasks”, „Microsoft.Web.XmlTransform”
phiree
8

w przypadku VS 2017 znalazłem tutaj odpowiedź , nie jestem pewien, dlaczego nikt nie wspomniał o niej powyżej, ponieważ wydaje się, że jest to bardzo popularne rozwiązanie. Bardzo łatwe. Upewnij się, że widzisz komentarz IOrlandoni z 5 marca 2019 r., Aby działał w VS 2017 i we wszystkich wersjach.

Zasadniczo jest to dwustopniowy. Najpierw edytuj plik .csproj, dołączając poniższy kod. Po drugie, tworzysz nową konfigurację web.base.config i kopiujesz tam istniejący web.config. Po wykonaniu tej czynności każda kompilacja nadpisze plik web.config żądaną transformacją.

<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>  
Tom McDonald
źródło
To prawdopodobnie najlepsza odpowiedź, ale IMO brakuje sztuczki. Jeśli zmienisz Web.configz Contentna None, możesz użyć Source="Web.config" Destination="$(TargetPath).config"(lub być może w przypadku niektórych typów projektów Destination="$(TargetDir)Web.config"). Przeniosłem również przekształcenie do AfterBuild, ponieważ nie trzeba już tego robić przed skopiowaniem plików.
Peter Taylor
Ok, właściwie to nie działa, ponieważ z jakiegoś powodu nie mogę go skonfigurować do uruchamiania bin.
Peter Taylor
4

Odpowiedź na Twoje bezpośrednie pytanie została udzielona - wyjaśnienie jest takie, że transformacja jest stosowana podczas publikowania, a nie kompilacji.

Uważam jednak, że nie oferuje rozwiązania tego, jak osiągnąć to, co chcesz.

Od kilku dni zmagam się z tym właśnie problemem, szukając sposobu na utrzymanie porządku w pliku web.config i ustawienie wszystkich kluczy, które różnią się w zależności od środowiska w odpowiednich plikach transformacji. Mój wniosek jest taki, że najłatwiejszym i najbardziej stabilnym rozwiązaniem jest użycie wartości debugowania w oryginalnym pliku web.config, dzięki czemu są one zawsze obecne podczas debugowania uruchomień w programie Visual Studio.

Następnie utwórz transformacje dla różnych środowisk, w których chcesz publikować - testowanie, integracja, produkcja - cokolwiek masz. Do tego wystarczy wbudowana funkcja przekształcania plików web.config podczas publikowania. Nie ma potrzeby używania SlowCheetah ani edytowania wydarzeń kompilacji ani plików projektów. Jeśli masz tylko projekty internetowe, to znaczy.

Jeśli chcesz, możesz również mieć w swoim rozwiązaniu plik web.debug.config, aby zachować oddzielny plik ze wszystkimi wartościami dotyczącymi środowiska programistycznego. Pamiętaj, aby skomentować w nim, że wartości nie są stosowane podczas uruchamiania w programie Visual Studio, na wypadek, gdyby ktoś inny próbował go użyć do tego celu!

Carolina Persson
źródło
1

Użyj Octopus Deploy (edycja społecznościowa jest bezpłatna) i pozwól jej przekształcić web.configza Ciebie. Kroki:

  1. Skonfiguruj Octopus, aby wdrożyć swoją aplikację internetową
  2. Upewnij się Web.Release.config, że Build Actionwłaściwość jest ustawiona Contenttak, jak w przypadku web.configpliku głównego .

Otóż ​​to! Octopus zrobi resztę bez specjalnej konfiguracji. Domyślne wdrożenie w witrynie sieci Web usług IIS wykona to po wyjęciu z pudełka:wprowadź opis obrazu tutaj

Matt Kocaj
źródło
Numer 2 jest kluczem :)
Reza
0

Najwyraźniej istnieje rozszerzenie dla programu Visual Studio 2015

https://visualstudiogallery.msdn.microsoft.com/05bb50e3-c971-4613-9379-acae2cfe6f9e

Ten pakiet umożliwia przekształcenie pliku app.config lub dowolnego innego pliku XML na podstawie konfiguracji kompilacji

Amir Astaneh
źródło
SlowCheeta nie jest nowa. był tam od dawna. Ich wydanie 1.1 miało miejsce 8.09.2011
HaBo
@HaBo Dziękuję za uwagę, usunąłem newświat jako zdanie.
Amir Astaneh
0

Ostatnio miałem ten sam problem ze starszym plikiem web.config opartym na .NET Framework 2.0. Rozwiązaniem było po prostu usunięcie przestrzeni nazw web.config ( atrybut xmlns w węźle głównym konfiguracji ):

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

PO: <configuration>

Rafael Neto
źródło