web-dev-qa-db-fra.com

La transformation de configuration Web ne fonctionne pas

Dans une application .NET MVC 3.0, j'ai la configuration suivante dans 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>

Pour le débogage, j'ai la transformation de configuration suivante définie:

web.Debug.config

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

Et j'exécute l'application en mode débogage, mais mon port SMTP prend toujours la valeur de web.config, ne pas web.Debug.config.

Quelqu'un peut-il suggérer ce qui pourrait mal se passer dans cette configuration?

80
HaBo

Les transformations Web.config ne sont appliquées que dans le cadre d'une opération de publication.

Si vous souhaitez que cela se fasse dans le cadre d'un app.config opération de génération, vous pouvez alors utiliser le plug-in SlowCheetah - XML ​​Transforms Visual Studio:

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

143
devdigital

Visual Studio (2010-2017) ne prend malheureusement pas directement en charge tout en vous déboguez, il est uniquement destiné à la publication - même avec l'extension SlowCheetah (réponse marquée) cela ne fonctionne pas pour moi (uniquement pour les projets utilisant app.config plutôt que web.config).

Notez qu'il existe une solution de contournement décrite au codeproject .

Il décrit comment modifier le fichier .msproj pour remplacer le fichier web.config actuel par la version transformée.

Je vais d'abord décrire cette solution de contournement comme Option 1 , mais j'ai récemment découvert une autre Option 2 , qui est plus facile à utiliser (vous pouvez donc faire défiler directement jusqu'à l'option 2 si vous le souhaitez):


Option 1: J'ai ajouté les instructions tirées de l'article de projet de code original (voir le lien ci-dessus), car les captures d'écran sont déjà parties et je ne veux pas perdre toutes les informations:

VS.Net ne fait aucune transformation lorsque vous développez et déboguez simplement votre environnement local. Mais vous pouvez prendre certaines mesures pour y arriver si vous le souhaitez.

  • Tout d'abord, créez les configurations souhaitées dans VS.Net , en supposant que le débogage et la version par défaut ne sont pas suffisants pour ce que vous essayez d'accomplir.
  • Faites un clic droit sur votre web.config Et sélectionnez Ajouter des transformations de configuration - cela créera une configuration de transformation dépendante pour chacune de vos configurations définies.
  • Vous pouvez maintenant renommer votre web.config En web.base.config.
  • Ajoutez un web.config À votre projet. Peu importe ce qu'il contient, car il sera écrasé à chaque fois que nous ferons une construction mais nous voulons qu'il fasse partie du projet donc VS.Net ne nous donne pas la fenêtre contextuelle "Votre projet n'est pas configuré pour le débogage".
  • Modifiez votre .csproj Fichier de projet et ajoutez la tâche TransformXml suivante à la cible AfterBuild. Ici, vous pouvez voir que je vais transformer le fichier web.base.config En utilisant le web.[configuration].config Et il l'enregistrera sous web.config. Pour plus de détails, veuillez vérifier this Microsoft Q&A, et pour obtenir des instructions sur la façon d'étendre la version, regardez there .

Option 2:

Sur la base de la réponse this , j'ai développé une application console simple, TransformConfig.exe (en syntaxe 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);
    }

  }
}

Assurez-vous d'ajouter la DLL "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.XmlTransform.dll" comme référence (cet exemple s'applique à VS 2015, pour les anciennes versions, remplacez le v14.0 Dans le chemin par la version appropriée) nombre, par exemple v11.0).

Pour Visual Studio 2017, le schéma de dénomination du chemin a changé: Par exemple, pour la version entreprise, il est ici: C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\VisualStudio\v15.0\Web .
Je suppose que pour la version professionnelle, vous devez remplacer Enterprise dans le chemin par Professional. Si vous utilisez la version d'aperçu, remplacez également 2017 Par Preview.

Compilez-le et placez le fichier .exe dans un répertoire, par ex. C:\MyTools\.

Utilisation: Vous pouvez l'utiliser dans votre événement post-construction (dans propriétés du projet , sélectionnez Build Events , puis modifiez le Ligne de commande d'événement post-build ). Les paramètres de ligne de commande sont (exemple):

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

c'est-à-dire d'abord le nom du fichier de configuration, suivi du fichier de configuration de transformation, suivi d'une configuration de modèle facultative, suivi du chemin d'accès à votre projet contenant les deux fichiers.

J'ai ajouté le paramètre facultatif de configuration de modèle, car sinon votre configuration complète d'origine serait écrasée par la transformation, ce qui peut être évité en fournissant un modèle.

Créez le modèle en copiant simplement le Web.config d'origine et nommez-le Web.Template.config.

Remarque:

  • Si vous préférez, vous pouvez également copier le fichier TransformConfig.exe Dans le chemin Visual Studio mentionné ci-dessus où réside Microsoft.Web.XmlTransform.dll Et y faire référence dans tous vos projets où vous devez transformer vos configurations.

  • Pour ceux d'entre vous qui se demandent pourquoi j'ai ajouté des affectations Environment.ExitCode = x;: Le simple retour d'un int de Main n'a pas aidé dans l'événement de génération. Voir les détails ici.

  • Si vous publiez votre projet et que vous utilisez un Web.Template.config, assurez-vous d'avoir reconstruit sur votre solution avec la bonne configuration (généralement Release) avant de publier. La raison en est que le Web.Config est écrasé pendant le débogage et vous pourriez finir par transformer le mauvais fichier autrement.

23
Matt

Répondre à votre question n'est pas simple, car cela pose un problème - si vous voulez transformer Web.config avec Web.debug.config - où l'effet de transformation doit être stocké? Dans Web.config lui-même? Cela écraserait le fichier source de transformation! C'est probablement pourquoi Visual Studio ne fait pas de transformations lors des builds.

La réponse précédente de Matt est valide, mais vous voudrez peut-être les mélanger pour avoir une solution générique qui fonctionne lorsque vous changez réellement la configuration de la solution active de débogage en version etc. Voici une solution simple:

  1. Créez vos transformations de configuration pour les configurations (débogage, version, etc.)
  2. Renommer Web.config fichier vers Web.base.config - les transformations doivent automatiquement être renommées en conséquence (Web.base.Debug.config, etc)
  3. Ajoutez ce qui suit fichier XML transformWebConfig.proj dans votre dossier de projet:
<?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. Accédez aux propriétés de votre projet, choisissez Build Events et ajoutez le contenu suivant à ligne de commande d'événement post-build:
@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)

Maintenant, lorsque vous générez votre solution, un fichier Web.config sera créé avec des transformations valides pour la configuration active.

21
komsky

Votre question immédiate a été répondue - l'explication est que la transformation est appliquée à la publication, pas à la génération.

Cependant, je pense qu'il n'offre pas de solution sur la façon de réaliser ce que vous voulez faire.

Je me bats avec ce problème exact depuis quelques jours maintenant, à la recherche d'un moyen de garder web.config propre et de définir toutes les clés qui varient en fonction de l'environnement dans les fichiers de transformation respectifs. Ma conclusion est que la solution la plus simple et la plus stable consiste à utiliser les valeurs de débogage dans le web.config d'origine, de cette façon, elles sont toujours présentes lorsque vous effectuez des débogages dans Visual Studio.

Créez ensuite des transformations pour les différents environnements que vous souhaitez publier - test, intégration, production - tout ce que vous avez. La fonctionnalité désormais intégrée pour transformer les fichiers web.config lors de la publication suffit pour cela. Pas besoin de SlowCheetah ou d'éditer des événements de build ni des fichiers de projet. Si vous n'avez que des projets Web.

Si vous le souhaitez, vous pouvez également avoir le fichier web.debug.config dans votre solution, juste pour conserver un fichier séparé avec toutes les valeurs relatives à l'environnement de développement. Assurez-vous de noter que les valeurs ne sont pas appliquées lors de l'exécution dans Visual Studio, au cas où quelqu'un d'autre essaierait de l'utiliser à cette fin!

4
Carolina Persson

pour VS 2017, j'ai trouvé la réponse ici je ne sais pas pourquoi personne ne l'a référencé ci-dessus car il semble que ce soit une solution très populaire. Très facile aussi. Assurez-vous de voir le commentaire de IOrlandoni le 5 mars 2019 pour le faire fonctionner dans VS 2017 et toutes les versions.

Fondamentalement, c'est un pas à pas. Tout d'abord, vous modifiez le fichier .csproj en ajoutant le code ci-dessous. Deuxièmement, vous créez une nouvelle configuration web.base.config et y copiez le fichier web.config existant. Après cela, n'importe quelle version écrasera votre web.config avec la transformation souhaitée.

    <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>  
3
Tom McDonald

Utilisez Octopus Deploy (l'édition communautaire est gratuite) et laissez-la transformer le web.config pour toi. Pas:

  1. Configurer Octopus pour déployer votre application Web
  2. Assurez-vous que votre Web.Release.config a la Build Action propriété définie sur Content comme votre principal web.config fichier.

C'est ça! Octopus fera le reste sans aucune configuration spéciale. Un déploiement par défaut IIS Site Web le fera hors de la boîte: enter image description here

1
Matt Kocaj

Apparemment, il existe une extension pour Visual Studio 2015

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

Ce package vous permet de transformer votre app.config ou tout autre fichier XML basé sur la configuration de construction

0

Récemment, j'ai eu le même problème avec un fichier web.config plus ancien basé sur .NET Framework 2.0. La solution consistait simplement à supprimer l'espace de noms du web.config (xmlns attibute dans configuration nœud racine):

AVANT: <configuration xmlns="http://schemas.Microsoft.com/.NetConfiguration/v2.0">

APRÈS: <configuration>

0
Rafael Neto