Comment résoudre l'erreur "Current solution contains incorrect mappings." avec Visual Studio ?

Peut-être avez-vous déjà été confronté à un bandeau présent dans la parti haute de Visual Studio, et affichant le message :

Current solution contains incorrect configurations mappings. It may cause projects to no work correctly. Open Configuration Manager to fix them.

Si tout se passe bien, le projet concerné est mis en évidence par un pictogramme d'avertissement affiché devant le nom du projet :

Porjet avec un pictogramme d'avertissement

Dans le cas où vous ne disposez que de projets .net aux anciens formats :

  • le message ne sera pas visible.
  • le projet à problèmes ne sera pas mis en évidence.
  • lors de la compilation msbuild devrait remonter un message impliquant un problème de mapping.

Quel est le problème?

L'erreur remontée ici par Visual Studio concerne la gestion des configurations, et plateformes. Un ou plusieurs projets sont mal configurés. Le lien entre les configurations des projets, et celles de la solution ne se fait pas.

De ce fait, il est possible que certains projets ne soient pas compilés avec la configuration, et la plateforme courante.

Comment s'en sortir ?

Si vous suivez les indications, vous n'irez pas loin. Vous vous retrouverez la boite de dialogue configuration manager, et ensuite ?

Pas de panique, je suis là pour vous accompagner. Je vais vous présenter une approche qui fonctionne dans 100% des cas. Celle-ci tient en quatre étapes :

  • Supprimer facilement les configurations en trop.
  • Supprimer facilement les plateformes en trop.
  • Rectifier les projets.
  • Rectifier la solution.

Par habitude, on garde souvent de très nombreuses plateformes alors que l'on n'en compile toujours qu'une. Personnellement, j'ai pris l'habitude inverse : ne garder qu'un profile.

Dans le cas présent, je vous propose d'opter pour la stratégie suivante :

  • Ne conserver que les configurations Debug et Release.
  • Ne conserver que le profile Any CPU au niveau de la solution
  • Seuls les exécutables cibleront x86 ou x64 (site web, consoles .. Etc)

De la sorte aucun développeur ne s'emmêlera les pinceaux avec les profils. L'erreur de mapping sera d'autant plus facile à résoudre.

Supprimer facilement les configurations en trop

Commençons donc par utiliser Configuration Manager pour faire le ménage. Pour rappel, celui-ci se cache dans le menu Configuration.

Menu d'accès à Configuration Manager

À partir de l'écran Configuration Manager, il convient d'ouvrir la liste déroulante des Configurations, et de sélectionner "Edit".

Menu d'accès à la liste des configurations

Ceci permet d'afficher la boite de dialogue dédiée à la gestion des configurations. Avant de toucher à quoi que ce soit, il faut cocher la case "Remove deleted configuration from all projects where it is unused". Ensuite on peut supprimer les configurations qui n'ont plus d'intérêt.

Liste des configuration Debug, et Release

Supprimer facilement les plateformes en trop.

Après validation de la liste des configurations, on peut maintenant s'occuper des environnements. Cela passe à nouveau par la boite de dialogue Configuration Manager. Cette fois si, il faut choisir l'option Edit présente en fin de liste des plateformes.

Menu d'accès à la liste des plateformes

Ici aussi, avant de faire quoi que ce soit, il faut penser à cocher l'option "Remove deleted platforms from all projects where it is unused". On peut ensuite supprimer les plateformes qui ne seraient pas utiles.

Liste des plateformes

En peu enfin fermer Configuration Manager, et enregistrer les fichiers modifiés par Visual Studio. Il peut y avoir quelques projets, en plus du fichier de la solution.

Rectifier les projets

On peut maintenant s'attaquer aux projets. L'idée ici, est de limiter ceux-ci au strict minimum. On en profite donc pour ne garder que là où les plateformes utiles (AnyCPU, x86, x64…).

Exemple pour un projet qui n'est compilé qu'en 64 bits, je limite la liste des profiles :


<Platforms>x64</Platforms>
<Platform>x64</Platform>

Rectifier la solution

Pour finir, il ne nous reste plus qu'à nettoyer la solution. Pour cela, il vous faudra ouvrir le fichier sln avec l'éditeur de votre choix.

Pour commencer, il faut trouver l'id du projet en défaut. Celui-ci se trouve en début de fichier, en toute fin de ligne.

Exemple pour un projet portant le nom MonProjet, l'id est {A3307DAA-4B1F-4D05-B465-9F82DB3D0034}.


Project("{.....}") = "MonProjet", "Mondossier\MonProjet.csproj", "{A3307DAA-4B1F-4D05-B465-9F82DB3D0034}"
EndProject

Cet id devrait se retrouver sur quatre lignes similaires à ceci :


{A3307DAA-4B1F-4D05-B465-9F82DB3D0034}.Debug|Any CPU.ActiveCfg = Debug|x86
{A3307DAA-4B1F-4D05-B465-9F82DB3D0034}.Debug|Any CPU.Build.0 = Debug|x86
{A3307DAA-4B1F-4D05-B465-9F82DB3D0034}.Release|Any CPU.ActiveCfg = Release|x86
{A3307DAA-4B1F-4D05-B465-9F82DB3D0034}.Release|Any CPU.Build.0 = Release|x86

S’il y a plus de lignes, ce n'est pas normal. Il doit y avoir deux lignes par configuration. L'une indique la configuration à activer, l'autre la configuration à utiliser s’il faut compiler le projet (si le projet n'est pas compilé, la ligne xxx.Build.0 est donc absente).

Dans le cadre de mon exemple, le nombre de lignes est bon. Par contre, lors de la compilation ciblant Any CPU, le sln cherche à utiliser une plateforme x86 qui n'existe pas dans le projet. Pour corriger le fichier sln, il suffit donc d'indique la plateforme x64.


{...}.Debug|Any CPU.ActiveCfg = Debug|x64
{...}.Debug|Any CPU.Build.0 = Debug|x64
{...}.Release|Any CPU.ActiveCfg = Release|x64
{...}.Release|Any CPU.Build.0 = Release|x64

Et voilà.

Jérémy Jeanson

Comment utiliser Windows Installer pour installer, et désinstaller proprement un dossier optionnel ?

L'un des aspects les plus importants quand on crée des MSI réside dans la désinstallation. Celle-ci doit respecter la maxime "Veuillez laisser cet endroit aussi propre que vous l'avez trouvé". Oui, cela fait penser à autre chose, et cela est volontaire.

Trop d'applications laissent des traces après leur passage. Cela peut être sous forme de fichiers, dossiers, ou clés dans la base de registre.

Avec Wix Toolset, les fichiers, dossiers, et clés de registre sont automatiquement supprimés lors de la désinstallation. Il y a cependant un cas problématique : les dossiers qui ne sont pas créés lors de l'installation. Windows Installer n'ayant pas connaissance de ceux-ci, il ne se permet pas de les supprimer. Si en plus, ces dossiers sont "optionnels", la gestion de leur présence, ou de leur absence lors de l'installation, et de la désinstallation se complique.

Avec Wix, il est possible de coder une action personnalisée pour l'installation, et une autre pour la désinstallation. Cette approche est un peu lourde pour ce que l'on a besoin de faire. Heureusement, il existe une solution plus simple. Il suffit de demander à Windows Installer de gérer un dossier vide comme étant l'un des composants de l'application.

Pour commencer, il faut déclarer le dossier. Pour mon exemple, je déclare un dossier MonDossierVide avec l'Id DOSSIER_VIDE.


<Fragment>
  <StandardDirectory Id="ProgramFiles6432Folder">
    <Directory Id="ManufacturerFolder" Name="!(bind.Property.Manufacturer)">
      ...
      <Directory Id="DOSSIER_VIDE" Name="MonDossierVide"/>
      ...
    </Directory>
  </StandardDirectory>
</Fragment>

Il faut ensuite déclarer un composant.


<DirectoryRef Id="DOSSIER_VIDE">
  <Component Id="ComposantDossierVide"
      Guid="{45D88591-3259-465D-AAAF-6248B7CCBD32}"
      Condition="UTILISER_DOSSIER_VIDE = 1">
      <CreateFolder />
  </Component>
</DirectoryRef>

Ce composant doit impérativement avoir :

  • une référence vers le dossier. Dans le cas présent, j'utilise un DirectoryRef pour cela, et je lui donne l'Id du dossier à créer. Exemple : DOSSIER_VIDE.
  • un Id défini. Exemple {45D88591-3259-465D-AAAF-6248B7CCBD32}.
  • un nœud CreateFolder.

Si en plus on ajoute une condition sur le composant, Windows Installer ne gérera le dossier que si la condition est respectée. Il ne créera le dossier que si la condition est vraie. Le dossier étant créé via un composant, il sera automatiquement supprimé lors de la désinstallation.

Bien évidemment, il faudra penser à référencer ComposantDossierVide dans liste des composants à installer.

Jérémy Jeanson

Pourquoi la fin du support de .net 7 est-elle un jalon important pour vos applications .net core, .net 6, ou 8 ?

En 2024, les développeurs .net commencent à être habitués aux acronymes STS/LTS associés aux différentes versions de .net. Mais tous ne saisissent pas forcément les implications de ceux-ci. Le plus souvent la réponse apportée peu se résume dans le tableau suivant :

DéfinitionAcronymeIdentificationDurée du support
Long Term SupportLTSVersion paire de .net3 ans
Standard Term SupportSTSVersion impaire de .net1 an et demi

Alors, oui certaines personnes peuvent confondre le premier S de STS avec Short, mais la vraie méprise n'est pas là.

Le statut "Maintenance support", cela vous parle ?

Il s'agit de la situation dans laquelle se trouve toute version de .net quand elle arrive dans ses 6 derniers mois de support. Durant cette période, vous ne recevrez que des correctifs de sécurités. Cela signifie que si un bug venait à être découvert durant cette période, il ne serait pas corrigé. Il vous serait juste recommandé de passer à une version supérieure.

Tout cela est expliqué sur la page ".NET and .NET Core Support Policy".

Maintenant, vous voyez peut-être où je souhaite en venir. La version 7 de .net arrive en fin de vie le 14 mai 2024, cela signifie que :

  • .net 7 est déjà limité à un support de type maintenance depuis novembre 2023.
  • .net 6 sera limité à un support de type maintenance en mai 2024.
  • .net 8 sera la seule version avec un support actif passé mai 2024.

Moralité

La fin de support de .net 7 est un jalon très important. Il est fortement recommandé de passer à .net 8 avant cette date. Voilà pourquoi les développeurs .net doivent migrer leurs applications dans les 6 mois qui suivent la publication d'une nouvelle version LTS. Considérer que vous avez davantage de temps pour le faire est une erreur. Que vous utilisiez une version LTS ou STS.

Jérémy Jeanson

Comment supprimer le pool récalcitrant d'une application inexistante dans IIS?

Voici une situation peu ragoutante que j'ai rencontrée il y a déjà quelque temps. IIS ne permettait pas la suppression d'un pool.

Heureusement, tout IIS est pilotable via PowerShell. Il suffit de connaitre les bonnes commandes.

L'application bloquant la suppression du pool n'était pas visible via la console. Dans un tel cas, il faut donc commencer par identifier les sites, et les applications que IIS ne semble pas vouloir afficher. Pour cela, il y a deux commandes à connaitre :


Get-Website
Get-WebApplication

Pour l'exemple, imaginons que je trouve une application app1 qui se trouvait dans le site web site1. Pour pouvoir supprimer cette application, il faut donc utiliser la commande :


Remove-WebApplication -Name app1 -Site site1 

Pour finir, le pool nommé pool1 dans mon exemple peut être supprimé via cette commande :


Remove-WebAppPool –Name pool1

Jérémy Jeanson

Comment réaliser des tests unitaires sur l'input d'un composant Blazor ?

L'une des choses que je préfère avec Blazor, consiste dans la possibilité de tester intégralement un composant via bUnit. Un bon exemple valant toujours mieux que de long discourt, voici un cas simple permettant de résoudre deux problématiques :

  • Le besoin de modifier un input.
  • Le besoin de consulter le contenu d'un input.

Pour commencer, on peut initialiser un contexte de test, et effectuer un rendu d'un composant :


// Création du context de test 
using var context = new TestContext();

// Création du composent et rendu
var obj = context.RenderComponent<MonComposent>();


Pour modifier une input dont l'Id serait inputId, on peut utiliser le code :


obj.Find("#inputId").Change("Ma valeur");


Pour consulter le contenu d'un input dont l'ID serait inputId, on peut utiliser le code :


var actual  = obj.Find("#inputId").GetAttribute("value");


Pour finir, voici un exemple complet :


[Theory] 
[InlineData("Foo")] 
public void Exemple(String value) 
{
  // Création du context de test 
  using var context = new TestContext(); 

  // Création du composent et rendu 
  var obj = context.RenderComponent<MonComposent>(); 

  // Modification
  obj.Find("#inputId").Change(value); 

  // … ajouter des interactions avec le composant ici 

  // Vérifier la valeur de l'input 
  var actual= obj.Find("#inputId").GetAttribute("value"); 
  actual.Should().BeEquivalentTo(value);  
} 

Conclusion

Voici du code simple et efficace. Tout ce que j'aime!

Jérémy Jeanson