Dot.Blog

C#, XAML, WinUI, WPF, Android, MAUI, IoT, IA, ChatGPT, Prompt Engineering

Silverlight : Enum.GetValues qui n'existe pas, binding et autres considérations

Silverlight, comme vous le savez, propose dans quelques méga octets un mini framework .NET qui est tellement bien "découpé" que la plupart du temps on ne se rend même pas compte qu'il manque des dizaines de méga de code binaire... Pourtant entre une installation complète du Framework 3.5 ou 4.0 à venir et l'installation du plugin Silverlight il y a comme une énorme différence ! De deux choses l'une, soit Silverlight ne sait rien faire tellement il est diminué par ce découpage, ce qui n'est pas le cas, soit le Framework complet est juste gonflé avec des fichiers inutiles pour "faire sérieux", ce qui n'est pas le cas non plus :-)

Un découpage savant 

Donc ce n'est ni l'un ni l'autre. La troisième possibilité, qui est la bonne réponse, est que le Framework complet est d'une richesse infinie dans les moindres détails, et que le Framework Silverlight "ruse" en zappant beaucoup de détails mais sans perdre l'essentiel. Cela donne l'impression qu'on peut tout faire en Silverlight comme en WPF. C'est "presque" vrai. Assez rapidement on tombe sur les fameux petits détails qui manquent. Cela implique de les compenser par du code.

Cela dit loin d'être une critique négative de Silverlight s'en est au contraire une apologie ! Je trouve en effet le découpage savant qui a été effectué dans Silverlight particulièrement bien fait. L'approche est très sensée : il est rarissime (même impossible) qu'une application utilise et nécessite d'accéder à toutes les méthodes, toutes les propriétés de toutes les classes du Framework tellement celui-ci est riche. Du coup, en faisant des coupes bien choisies, on peut laisser les squelettes de presque tout le Framework ainsi que les principales méthodes et propriétés utilisées le plus souvent. On obtient le Framework Silverlight dans lequel un code standard trouvera 95% de tout ce qu'il lui faut pour tourner. Beaucoup d'applications simples ne verront même pas qu'il manque quelque chose. En revanche pour les autres cas, le développeur ajoutera les contournements nécessaires ce qui grossira un peu son code binaire Silverlight, mais d'une petite fraction très supportable. Rien à voir avec le coût d'une installation du Framework complet.

Il n'en reste pas moins vrai que parfois pour des choses très simples on se retrouve un peu le bec dans l'eau. "Tiens, c'est bizarre, j'aurais juré que la méthode xxx existait !" Et non, on n'a pas rêvé, elle existe bien, mais dans le Framework complet, pas dans celui de Silverlight. Un exemple tout simple : la méthode GetValues() de la classe Enum.

Enum.GetValues où es tu ?

Un cas d'utilisation très basique qui fait voir immédiatement qu'il manque quelque chose : essayez de faire un binding entre une combobox et une énumération. Truc classique par excellence.

Que le binding soit fait par Xaml ou bien par code, à un moment où un autre il faut que l'énumération sache retourner la liste de ses valeurs. C'est justement la fonction de la méthode Enum.GetValues().

Mais dans le Framework Silverlight cette méthode n'existe tout simplement pas. Victime de la cure d'amaigrissement évoquée plus haut. Il ne s'agit donc ni d'un oubli ni d'un dommage collatéral, c'est un parti pris, assumé.

Et alors on fait comment ?

Assumé, assumé... comme il y va ! Non, je vous l'assure, c'est assumé. Par l'équipe qui développe le Framework Silverlight en tout cas. Mais pas forcément par les développeurs qui l'utilisent ! Car pour eux c'est une autre histoire puisque, en effet, il va falloir réinventer cette méthode.

A l'aide d'un peu de Linq to Object et de Reflexion, on peut s'en sortir.

Linq et Reflexion

Il existe en effet un moyen d'obtenir les valeurs d'une Enum par la réflexion, en utilisant la méthode GetFields() sur le type de l'Enum dont on souhaite obtenir les valeurs. 

GetFields() retourne un tableau de FieldInfo. Une Enum présente alors ses différentes valeurs comme un tableau de champs. En plus de ces champs, GetFields() retournera aussi des éléments qui ne sont pas des valeurs de l'énumération mais d'autres champs de la classe. Au sein de FieldInfo vous trouverez un ensemble de méthodes nommées Isxxx(), l'une d'entre elles nous intéresse plus particulièrement ici; c'est IsLiteral. Toutes les valeurs de l'énumération retournent True. La solution est alors simple en ajoutant à la Réflexion un peu de Linq to Object :

   1:  var enumType = typeof(monEnumeration);
   2:  var fields =  from field in enumType.GetFields()
   3:                where field.IsLiteral
   4:                select field.GetValue(null).ToString();
   5:  LaCombobox.ItemsSource = fields;

A partir du type de l'énumération (ligne 1) on construit une requête Linq to Object qui filtre tous les champs ayant IsLiteral à vrai et qui sélectionne la valeur de ce champ sous la forme d'une string.

Ne reste plus qu'à faire le binding entre cette requête Linq et ItemsSource de la combo box.

Il faudra ajouter un peu de code pour transformer la chaîne sélectionnée dans la combo en une valeur de l'énumération grâce à un appel à Enum.Parse().

C'est la version simple et courte. Bien entendu dans le cas où on souhaite faire du binding plus automatisé, notamment directement en Xaml, la solution donnée ici est un peu trop simple. L'esprit est le bon mais il manque des petites choses comme un convertisseur de valeurs.

D'autres versions plus sophistiquées

Il est bien sûr possible d'aller plus loin et de formuler une solution plus sophistiquée qui permettent de faire du binding en Xaml notamment. Je vous laisse y réfléchir, ça fait un bon excercice C# et ce n'est pas un MVP C# qui vous dira que s'entraîner mentalement de la sorte sur le langage est inutile ! :-)

Mais sachez que d'autres y ont déjà pensé et ont proposé des solutions souvent assez proches (ce problème ne peut pas être résolu de dix milles façons). En voici quelques unes dans lesquelles vous pourrez piocher matière à aller plus loin :

Silverlight c'est sympa et en plus ça fait travailler les méninges, que du bon ! 

Stay Tuned !

 

 

 

Fichiers PFX de signature de projet Visual Studio / objet déjà existant après migration Windows 7

Vous l'avez compris, l'entrée de blog d'aujourd'hui ne parle pas de Silverlight ni d'autres sujets technologiques passionnants mais d'un problème très ennuyeux intervenant après la migration sous Windows 7. Cela concerne les projets signés numériquement sous Visual Studio, ceux possédant un fichier PFX donc.

Une fois cette migration effectuée, tout semble tellement bien marcher que vous lancer fièrement Visual Studio sans vous douter du complot sournois qui se trame contre vous et qui se révèlera au moment où vous tenterez d'ouvrir une solution contenant des projets signés... Vous allez me dire, l'attente est courte. En effet, il est rare d'ouvrir VS juste pour le plaisir de le regarder, assez rapidement, même pour les plus lents d'entre nous, on finit par faire Fichier / Ouvrir (les plus créatifs préférant Fichier / Nouveau, mais ce n'est pas le sujet du jour).

A ce moment là, tous les projets signés déclenchent une importation du fichier PFX (même si vous êtes toujours sur la même machine et que rien n'a changé, n'oubliez pas que cette machine vient de migrer de Vista à 7 !). Comme vous êtes un développeur honnête, vous connaissez bien entendu les mots de passe des fichiers PFX de vos projets. Donc pas de problème vous tapez le mot de passe. Bang ! Erreur "l'objet existe déjà" (Object already exists). Et pour peu que votre solution contienne des dizaines de projets, ce qui est mon cas assez fréquemment, vous allez boucler sur cette séquence pour tous les fichiers PFX. A la fin vous pourrez travailler sur votre solution, mais à toute tentative de compilation vous vous reprendrez la même séquence : importation de la clé, demande de mot de passe, échec pour cause d'objet existant, etc pour chaque projet signé.

C'est un peu gênant... Mais il existe une raison et une solution !

La raison, en tout cas pour ce que j'en ai vu, c'est que la migration vers W7 modifie les droits du répertoire dans lequel sont cachés les clés importées. Pourquoi ? Je n'en sais rien et pour l'instant je n'ai rien trouvé sur le Web à ce sujet.

En tout cas, le problème étant identifié, il existe une solution : changer les droits et s'approprier le dit répertoire. Ca peut être plus compliqué que prévu, en tout cas j'ai galéré un peu (j'avoue franchement ne pas avoir un niveau d'expert en matière de gestion de sécurité sous Windows). En effet il faut déjà trouver le répertoire en question. (roulements de tambours) c'est... c'est... C:\Users\All Users\Microsoft\Crypto\RSA

Maintenant que faire... Clic droit sur le répertoire (dont l'image possède un petit verrou d'ailleurs, verrou qui disparaitra en fin de manip), onglet sécurité et on essaye de s'approprier tout ça. Ca plantouille car Windows répond qu'on n'a pas les droits sur xxxx (à remplacer par le nom imbuvable de chaque fichier de ce répertoire, justement ceux posant problème).

Bref, il faut y aller à la main. On entre dans le répetoire et on fait un clic droit / sécurité sur chaque fichier. Certains laissent voir la page Sécurité immédiatement. Laissez tomber. Mais un certain nombre d'autres fichiers affichent un message vous indiquant que vous n'avez pas le droit de voir l'onglet Sécurité ! Heureusement Windows vous permet de vous les approprier, donc d'en devenir le propriétaire (au passage je vois mal l'intérêt d'interdire un truc en proposant de l'autoriser, je vous l'ai dit, je ne suis pas un expert en Sécurité Windows !). C'est ce que j'ai fait pour chaque fichier. En fin de manip j'ai recommencé la modification des droits sur le répertoire lui-même, et là c'est passé. Plus de petit verrou affiché dans le symbole dossier.

Et immédiatement, Visual Studio ne redemande plus l'importation des clés. Ca remarche. Ouf !

Je suis convaincu que je m'y suis pris comme un pied pour régler le problème (il doit y avoir plus simple et plus propre que de devenir propriétaire de chaque fichier un par un), en tout cas ça règle bien le problème qui avait été bien identifié : problème de droits sur le répertoire des clés.

Pour l'instant c'est la seule surprise que j'ai eu en migrant cette machine de Vista à Windows 7. Le reste marche très bien et on ne perd rien ce qui est très appréciable (comme j'aurai aimé que cette option de migration sans douleur existe sur les anciennes versions de Windows !).

J'espère que le récit de cette mésaventure (et surtout sa solution) évitera à certains de perdre quelques heures... Si oui, n'hésitez pas à me le dire, ça fait toujours plaisir de savoir qu'un billet a été utile !

Et sir parmi vous il y en a qui sont plus doués que moi niveau sécurité Windows, qu'ils n'hésitent pas à indiquer la "bonne" manip pour arriver au résultat je modifierai en conséquence le présent billet...

Dans tous les cas, Stay Tuned !