Tech Days 2011 : OData

OData part du problème que, même si on abstrait les formats et les protocoles, il reste que des données ne partagent pas les mêmes schémas.

SQL Azure permet d’exposer les données sous forme OData. http://odata.org/producers/ pour plus de fournisseurs.

Des conventions d’URL permettent d’avoir des appels REST standard, et un format standard d’affichage en JSON ou en XML sont utilisés. Du coup, OData n’est pas une technologie, mais plutôt un ensemble de convention d’exposition des données.

Pour s’abstraire des schémas, il faut exposer un sommaire, sous forme de service, puis de workspaces, puis de collections. Bref, on est très proche de TJS dans l’esprit. Tous les services exposent leur metadonnées.

OData peut être utilisé pour exposer de la donnée bien formatée, de manière relativement agnostique, mais sans atteindre la richesse syntaxique d’une ontologie.

Il y a des outils génériques pour requêter du OData : OData Explorer fait en Silverlight, et puis Sesame (développé par Fabrice Marguerie), également en Silverlight. Ca serait intéressant d’avoir une application mobile sur le même type, de façon à pouvoir exposer facilement de la donnée typée.

Sharepoint expose également ses données au format OData (listdata.svc/MaListe pour l’URL).

WCF Data Services est un SDK qui peut requêter ou exposer de la donnée en OData. Le produit s’appelait anciennement Astoria, pour rappel. Il y a aussi des implémentations pour Windows Phone, iOS. LinqPad et PowerPivot peuvent également aller chercher de la donnée OData.

Pour exposer un entity framework, il suffit de créer un WCF Data Service dans VS.NET.

Dans l’autre sens, on peut ouvrir le svc en référence web pour fournir un modèle entity qu’on pourra utiliser comme contexte pour une interrogation Linq. Le SaveChange fonctionnera, car WCF DataServices enverra un POST de modification correspondant. Les ordres seront bien cumulés en envoyés en un seul message.

Il y a aussi tout ce qu’il faut pour la pagination des résultats, avec les mots clés top et skip.

Une autre démo fait voir comment on peut récupérer du JSON depuis JQuery. JSONP permet d’éviter les problèmes de cross-domain, si le serveur le supporte. On rajoute à l’appel &fomat=json&callback=callbackChargementDonnees. Le deuxième paramètre est nécessaire pour que le mode simplifié JSONP fonctionne. Pas bien compris cette partie là, je ne connais pas assez les problèmes de cross domains et AJAX en général.

Le framework de template créé par Microsoft et adopté par l’équipe JQuery permet de réaliser des choses sympas, comme par exemple un tag de fusion de type {{html }} qui vont prendre une donnée de fragment HTML et l’afficher non pas comme du texte, mais avec son contenu riche.

La démo suivante se fait en Silverlight sur Windows Phone 7, avec une source de données SQL Azure. Il y a une fonction d’exposition sous forme OData dans l’interface de gestion de SQL Azure.

Codeplex fournit le DataSvcUtil.exe qui permet de générer les classes qu’il faut pour WP7.

Comme d’habitude, par contre, et la remarque peut se faire aussi pour la session suivante, la technologie ne fait rien de particulier pour la gestion du versioning et c’est toujours au développeur de se coltiner la totalité du problème… Bref, la solution restera certainement la même pour longtemps, à savoir d’assurer la compatibilité côté serveur. Freebase le fait par exemple avec un timestamp qui permet de requêter la donnée comme elle était à une date dans le passé, y compris en terme de schémas, etc. Logique : de la donnée de dix ans serait trop différente en terme de schéma et ne serait potentiellement même pas transférable dans le nouveau schéma du serveur, sans même parler du client !

Pour la sécurité, on peut utiliser des QueryInterceptor<T>. On peut utiliser aussi OAuth WRAP de ACS sous Azure.

Posted in Retours | Tagged | Leave a comment

Tech Days 2011 : The future of F# : Data & Services at Your Finger Tips

La présentation est faite par Don Syme, le pape de F#, accompagné de Robert Pickering et Adam Granicz.

L’adoption de F# est faible, mais existante dans le monde de la finance. Typiquement, la librairie F# parmi 20 autres en C# est celle qui gère le moteur de calcul (IA dans un jeu, calcul de risque dans une application financière, etc.)

x |> f1
|> f2 : pipelining de x dans la fonction f1 puis dans la fonction f2

Dans une classe, let va pré-calculer le champ, tandis que member va définir le calcul qui sera réalisé lors de l’appel éventuel du champ, ou plutôt de la propriété dans ce cas, même si je ne suis pas sûr que la notion prend le même nom en F#.

Une personne utilisant F# en production évoque le fait, peu connu même des créateurs du langage, que les tests unitaires sont très faciles à réaliser.

Robert Pickering montre un projet sur l’accéléromètre dans un Windows Phone 7. Ce capteur envoie 50 événements à la seconde, avec à chaque fois un vecteur 3D correspondant à l’accélération du composant.

Un service WCF a été créé pour récupérer les événements du capteur, puis les analyses sont faites sur le serveur. www.strangelights.com/blog/ pour plus de détails, mais honnêtement la démo n’était pas renversante, car elle n’a pas fait voir ce que F# apportait de plus par rapport à un autre langage.

Adam Granicz fait ensuite voir son produit WebSharper qui crée des applications web en F#. La démo en particulier fait voir de la composition de HTML5.

Une template de page HTML est représentée par un moteur sous forme de fonction F#. Du coup, on se retrouve avec des remplissages réalisés par du code qui est type safe.

Le concept de sitelet est une association entre une requête et un contenu quelconque. On peut ensuite intégrer dans une sitelet plus grande. Du coup, ça ressemble un peu de l’extérieur à un système de widgets.

Une autre demo montre un site autocontenu réalisé en une centaine de lignes de F#.

Don Syme reprend ensuite la main pour parler des Type Providers, qu’il présente comme de la magie pour régler les problèmes de trop forte adhérence aux types dans les langages typés. L’idée derrière est que le web sémantique définit déjà des organisations de données. L’intellisense vient de FreeBase et il n’y a pas de DLL avec les types montrés, qui reprennent des données sur les éléments, la biologie, etc.

Une ligne de code suffit à montrer un tas de données sous forme de grille. Les Type Providers peuvent venir de données extérieures, dans le cloud, etc. La seule DLL adaptée à la source est très simple et ne sert qu’à la communication, et pour mettre en place l’intellisense (elle ne sert même pas à la runtime).

Azure Market Place est d’après Don Syme un excellent endroit pour trouver de la donnée, car les sociétés qui sont sur Dallas (l’ancien nom d’Azure Market Place) sont surtout des fournisseurs de données.

Pour continuer dans cette direction, une autre démo montre une extension de Linq pour aller chercher ces données, en utilisant un context nommé DataMarket car il tire ses données du Market Place Azure.

On peut évidemment étendre cette approche à tous les fournisseurs de données, comme par exemple WMI.

Livre : Professional F# 2.0 chez Wrox

Posted in .NET, F#, Retours | Tagged | Leave a comment

Tech Days 2011 : Développer efficacement vos applications parallèles en C# 4.0

Après avoir encore fait la queue pendant 20 minutes et avoir tout de même failli passer la session assis par terre (alors qu’il y a toujours un rang réservé complètement libre devant), on va enfin commencer la conférence. C’est Bruno Boucard, MVP indépendant, qui s’y colle. http://blogs.msdn.com/devpara/ pour plus d’information.

Avant de commencer, petit sondage pour savoir qui utilise TPL ou Parallel Linq, et comme souvent, très peu de gens utilisent : une dizaine maximum sur une salle de 300 environ. C’est plutôt une constante, et du coup certainement une justification aux grands moyens que Microsoft met dans les TechDays ; les technologies de pointe sont bien connues, mais 90% des développements utilisent la techno n-1, quand ce n’est pas la n-2.

B.B. prévient que ce n’est pas une session d’introduction, mais plutôt des bonnes pratiques sur la parallélisation, même si visiblement peu de gens en font vraiment.

Pourquoi doit-on abandonner les threads ?

La division du travail pour préparer la parallélisation nécessite un surcoût, et si on a beaucoup de cores, on finit par prendre plus de temps à diviser qu’à calculer de manière effective. Le framework 4.0 a été pensé pour optimiser ces mécanismes même avec de nombreux cores.

En .NET 3.5, on avait un système de pool de threads. A chaque fois qu’on ajoute un thread dans la file, on locke le gestionnaire. Du coup, si des threads en créent beaucoup d’autres, on est limité par la pile globale. Il y a une détection de famine et de threads inactifs, mais c’est tout.

En .NET 4.0, on a une file sans lock pour les threads demandés, mais en plus des queues locales pour chacun des cores, qui vont prendre en charge les threads spawnés sous forme de fils par les threads. Ces piles de second niveau sont LIFO pour utiliser au mieux le mécanisme de cache des processeurs. Une file peut faire du vol de tâche, pour occuper au mieux les processeurs. Il y a apprentissage par le mécanisme en .NET 4.0.

Les résultats sont présents, avec un exemple de passage de 10 à 1,6 secondes en passant simplement d’une version 3.5 à une version 4.0, même si B.B. reconnait que le code est fait exprès pour montrer la différence.

Des exemples plus complets vont être fait sur les threads, puis le ThreadPool, puis l’API Tasks (qui est encore plus évoluée). L’emprunt mémoire d’un thread est en gros de 1 Mo. Du coup, si on crée ses threads à la main, on en a 1000 dans l’exemple donnée, alors qu’on n’utilise que 17 Mo de RAM pour le ThreadPool et l’API Tasks qui se base dessus. Attention, il faut faire un WaitOne dans le contenu pour pouvoir mesurer l’empreinte mémoire.

Si on veut composer, annuler, attendre des items, il est beaucoup plus facile d’utiliser l’API Tasks. Par contre, si on veut simplement faire du Fire & Forget, le ThreadPool suffit.

Outils pour la parallélisation

Collections ThreadSafe, Coordination (Barrier, BlockingCollection<T>, etc.), Partition (découpage des données pour plus de performance), Lazy initialization (Lazy<T>, ThreadLocal<T> pour éviter de partager des données), Verrou (…Slim pour la version optimisée, et …Spin lorsqu’on sait que l’attente sur une ressource sera très faible : il reste alors en attente active et non pas sur le noyau, donc plus efficient), Annulation centralisé dans .NET 4.0 (CancellationToken), Gestion des exceptions (AggregateException pour traiter le cas des tâches qui émettent des exceptions simultanées pour rendre compte au global en fin de traitement)

On continue sur une autre démo, qui montre un cas particulier d’utilisation des tâches avec l’énumération LongRunning, qui signifie qu’on souhaite utiliser un thread. FromCurrentSynchronizationContext permet de dire qu’on veut que la tâche se déroule sur le thread de la GUI, pour éviter les problèmes de modification des contrôles cross-threading. Par contre, il ne faut évidemment pas le faire si on est sur une boucle, pour ne pas bloquer la GUI.

Comment repérer les anti-patterns en parallélisation ?

Première méthode montrée ; utiliser le CPU Sampling pour voir déjà ce qui prend le plus de ressource. Il est essentiel, comme pour l’optimisation, de partir de mesures précises de ce qui prend le plus de CPU, et ne pas se fier à son intuition.

On voit dans l’exemple que c’est sur un traitement d’image qu’on prend le plus de temps. Du coût, c’est dans cette partie du pipeline qu’on va mettre en place une parallélisation. Dans un premier temps, on va faire une liste de Tasks, et on va boucler sur Environment.ProcessorCount, en lançant toutes les tâches d’un coup, et en utilisant ensuite une instruction ContinueWhenAll sur la liste pour spécifier qu’on veut que toutes les tâches soit finies pour clore notre buffer.

Une autre méthode est ensuite montrée. Si on attend une tâche et qu’elle est annulée, on va avoir une exception au niveau de l’attente. Par contre, si on ne l’attend pas, l’exception sera levée, mais au niveau du finaliseur. Sur le TaskScheduler, il y a un événement UnobservedTaskException, équivalent du UnhandledException sur un AppDomain.

Parallel Linq

La mise en place avec AsParallel() n’est pas obligatoire. Il faut bien vérifier ce qui se passe, car dès qu’une requête est complexe, le résultat ne sera pas nécessairement effectivement parallélisé.

WithCancellation et WithDegreeOfParallelism sont aussi disponibles en Linq.

Visualisation des problèmes

Visualisation des deadlocks intégrée dans Visual Studio, mais B.B. ne dit pas comment activer la fonctionnalité, où la trouver, si elle n’est que dans l’Ultimate, etc.

Oversubscription quand le nombre de tâches est trop elevé. Dans la visualisation du temps d’exécution des threads dans VS.NET, on ne doit pas voir trop de vert clair qui correspond à de la préemption.

Un ordonnancement dynamique permet de mieux utiliser les ressources, en ne mettant pas deux tâches lourdes sur un thread et deux petites sur une autre. Le graphe d’utilisation du CPU en escalier est révélateur de ce type de problème.

Le lock convoy se passe lorsqu’une ressource est lockée par une tâche seulement, et ce à chaque instant : du coup, toutes les tâches s’attendent et ne peuvent s’exécuter que lorsque les autres ne tournent pas. Du coup, c’est une erreur de design.

Profiling method = concurrency dans Visual Studio. Encore une fois, il faudra voir si le profileur existe dans la version Pro ou seulement dans l’Ultimate.

Pro .NET Parallel Programming in C# par Apress.

Patterns for Parallel Programming.

Guide “Parallel Programming with Microsoft .NET” dans la collection Patterns and Practices de Microsoft.

Posted in .NET, C#, Parallélisation, Retours | Leave a comment

Tech Days 2011 : Introduction à Azure

Il va falloir faire les TechDays en plein air !

Bon, ça devient de pire en pire pour avoir accès aux petites salles. Les sessions sont prises d’assaut, et malgré mon avance, j’ai vu la porte se fermer devant mon nez. Alors on tente de foncer en courant à l’autre bout du bâtiment, et même chose, vu qu’on est encore plus tard. Bref, on se retrouve bredouille, et bien obligé de se rabattre sur une session en amphi où il y a toujours à peu près de la place…

Utilité d’Azure

Du coup, j’arrive un peu en retard à la conférence dans l’amphi bleu. Dommage, car je ne vois que la fin de l’explication d’un graphique très intéressant, montrant de manière bien visuelle la variation entre le sous-dimensionnement et le gâchis au fur et à mesure de l’évolution des besoins, si on achète des serveurs pour une application donnée. Azure permet de lisser les coûts en fonction de l’usage au lieu d’acheter des serveur pour les pics et de les sous-utiliser pendant les périodes de moins forte charge.

Dublin et Amsterdam en relai pour les DataCenters Azure en Europe, plus deux aux USA et deux en Asie.

PaaS = Windows Azure / SQL Azure.

SaaS = 70% des logiciels serveurs de Microsoft qui seront disponibles en mode Azure.

Valeur d’Azure

Une animation PowerPoint bien réalisée fait voir les gros avantages qu’on peut tirer d’Azure, à savoir ne pas se soucier de la sécurité, du réseau, des bases de données, etc. mais seulement se concentrer sur son application, c’est-à-dire sur ce qui fait la valeur d’une entreprise.

AppFabric peut servir de bus de services, agit en tant que cache distribué, etc.

Windows Azure

Windows Azure s’occupe des services suivants :

Compute : services de calcul.

Storage : Azure tables pour le stockage noSQL, Azure BLOB pour stocker les fichiers dans des containers, et enfin Azure Queues pour gérer les files d’attente afin d’échanger des requêtes entre le Cloud et les serveurs On Premise.

CDN : accélérer les accès par un mode de cache.

Management : tout par un simple navigateur.

SQL Azure

SGBD-R, avec capacité de DataSync, de reporting et de gestion.

AppFabric

Apporte des services de plus haut niveau, à savoir surtout le bus de service, et la gestion des accès. Pas très clair lorsque les orateurs parlent d’ “héberger” le bus dans le Cloud. Ca ne correspond pas du tout à l’idée d’un vrai bus distribué. Il y a également le service de cache (anciennement Velocity) en CTP pour l’instant. Enfin, on peut utiliser le service de VPN pour établir un canal sécurisé pour revenir sur une base de données On Premise.

Les orateurs répètent plusieurs fois que le déplacement des applications sur le Cloud sera totalement transparent. Vu la différence entre la bande passante réseau et l’internet, cette affirmation n’aura de sens que si une attention particulière est prêtée aux échanges si on veut réaliser ces requêtes d’une base de données locale par le Cloud.

MarketPlace

L’accroche est d’utiliser Microsoft comme nos commerciaux. Les orateurs ne développent quasiment pas.

Mode de développement Azure

Là, la conférence dérive carrément au panégyrique pour Azure, qui va résoudre tous les problèmes existants, avec une migration à coût nul, etc.

La tarification peut être faite sur un mode journalier, avec moins de serveurs pendant la nuit, et plus pendant le jour, et ce de manière automatique.

Coût

Traitement : 0.085 € / heure sur un monocore 1,6 GHz avec 1 Go RAM

Stockage : 0,11 € le Go / mois + 0,007 € / 10K transactions

Bande passante : 0,11 € / Go en entrant, et 0,14 € / Go sortant

SQLAzure : 7 € / Go et par mois pour la base de donnée

AppFabric : 1,4 € / 100K contrôle d’accès + 2,8 € / 10K messages de bus

SLA globalement autour de 99,9%, avec un pic à 99,95% pour le réseau

Exemple d’une base de 10 Go avec 1 Go entrant et 10 Go sortants par mois : 101,7 $ (taux de change mois par mois).

www.microsoft.com/windowsazure/tco/ propose un mode de calcul du coût d’une application sur Azure.

Les abonnés MSDN ont 750 heures de compute par mois et du SQL Azure mis à disposition.

Conclusion

Un peu décevant comme session : vraiment TRES TRES introductif, et des orateurs pas excellents, utilisant sans arrêt des expressions anglaises hors contexte, expliquant que tout est simple et facile et qu’il n’y a aucun problème. Des collègues à moi ont d’ailleurs ressenti la même chose : l’impression que le discours devait être celui de la facilité, quitte à finalement le surjouer.

Posted in Retours | Tagged | Leave a comment

Tech Days 2011 : Architecture des applications et des services fondés sur la fédération d’identité et les revendications

C’est reparti pour quelques sessions de blogging intensif : comme chaque année, je suis aux TechDays Microsoft, et je vais vous faire partager mes notes sur les sessions que j’irai voir. On commence par cette session à l’intitulé long, mais pourtant pas explicite. J’espère ne pas m’être trompé en venant y chercher des informations sur comment fédérer des identités dans des environnements hétérogènes. D’après ce que j’ai lu, il me semble que les revendications dont il est question sont un moyen technique correspondant aux “claims”, à savoir la présentation des droits requis par le client, et la validation de ce “claim” par le serveur en comparant ceci à son propre contexte, et en demandant au besoin la confirmation par un serveur tiers. On verra…

Introduction

La session est présentée par Philippe Beraud, Benjamin Guinebertière (un co-auteur dans le dernier Programmez! si je me rappelle bien) et Stéphane Goudeau, tous trois architectes à Microsoft France. Dommage qu’il n’y ait pas un intervenant extérieur : ça apporte souvent beaucoup de clairvoyance dans une session.

Le but de la session telle que présenté par P.B. est de montrer quelques architectures de référence sur la fédération d’identité, qui a maintenant plusieurs années derrière elle, avec des standards à peu près reconnus désormais.

Les technos Microsoft derrière la fédération d’identité sont Active Directory Federation Services 2.0, Windows Identity Foundation 1.0 et Azure AppFabric Access Control Services 2. Ce dernier supporte la fédération des identités de réseaux sociaux. La session n’est pas technique sur ces produits, mais montre plutôt comment ils peuvent être utilisés dans des scénarios standards.

Revendication est bien la traduction adoptée par Microsoft France pour la notion de Claim-Based Identity. On parlera de WebSSO, voire de WebSSO fédéré, y compris avec des services web sur lequel on tape en interne ou dans un domaine externe.

Les orateurs recommandent pour une approche plus théorique le “Guide to Claims-Based Identity and Access Controls” dans la collection Patterns and Practices de Microsoft.

Oasis a créé un standard WS-Federation. Il y en a d’autres, mais le modèle de base est une triplette entre Identity Provider, Resource et Requester. Mais il y a bien sûr de nombreuses architectures potentielles pour mettre ceci en place. Ce type de modèle existe depuis AD : un ticket Kerberos fourni par le serveur de domaine est fourni par le client à un serveur qui fait confiance au domaine, et accepte donc le client. On est clairement dans le schéma standard. Le jeton est appelé le TGS. Ce schéma fonctionne bien avec toutes les applications Kerberos, et depuis une dernière version, il y a possibilité de déléguer la contrainte Kerberos, en demandant à un serveur web distant de réclamer une identification Kerberos. Par contre, ce mode est limité, car enfermé dans la forêt AD. Du coup, ça ne passe pas sur le Cloud, sur des applications Kerberos, sur des domaines étrangers…

Bref, il fallait quelque chose de supplémentaire. L’idée de l’authentification fédérée est de remplacer le serveur Kerberos par un service de jeton de sécurité (STS), avec lequel les serveurs de ressources vont établir également un cadre de confiance, et le client récupérer un jeton, la différence étant uniquement au niveau du contenu du jeton : les protocoles et contenus sont différents, mais la cinématique est toujours exactement la même. Par contre, un STS va pouvoir valider un jeton, en prendre un pour en émettre un second sous une forme différente, de façon à être agnostique par rapport au format du jeton.

Nous abordons ensuite des scénarios d’utilisation :

Fournisseur d’identité interne

Le service de jeton est simplement connecté à l’annuaire. Il y a des nouveaux projets Visual Studio notés comme “Claims-Aware”. L’exemple est fait sur un site web pour être plus visuel qu’avec un service.

Au niveau des références, on voit Microsoft.IdentityModel, ce qui correspond à WIF. Ensuite, on ajoute une “Référence STS”, de la même manière qu’on ajoute par exemple une référence web. Le fichier de configuration est modifié pour charger les librairies nécessaires, et un certificat par défaut a été créé.

On voit du coup bien le site web ainsi que le site web créé pour STS, qui contient une page de login, sur laquelle le site web d’origine redirige. La tringlerie est donc bien cachée, et on peut modifier le code par défaut avec les API de sécurité pour rajouter des rôles, etc. Si on avait besoin de partager la sécurité avec un site web complètement extérieur, il suffirait alors de pointer l’autre site web sur le STS qui a été créé par défaut avec la première.

La question qui se pose alors est de savoir qu’est-ce qu’on met dans le jeton STS : on met des données applicatives, mais aussi des applications liées à l’entreprise. L’important étant bien sûr de ne pas trop faire grossir le jeton. Donc, typiquement un numéro de matricule, mais surtout pas les détails complets de l’utilisateur. Si on en a besoin, on se servira du contenu pour aller chercher dans des référentiels externes les données supplémentaires nécessaire, application par application.

Ce scenario reposait sur WS-Federation. ADFS est par contre capable de faire en plus de la transition de fédération entre du WS-Federation et du SAML 2.0, et ce dans les deux sens. Cette transition de protocoles supporte d’ailleurs d’autres méthodes. ADFS a également un intérêt en termes de configuration fine des autorisations de création de jetons.

Le sous-scénario suivant utilise justement ADFS comme STS. On voit alors la feuille de redirection proposer plusieurs modes d’authentification, puis IE affichant la nouvelle boîte de login, telle que celle lorsqu’on souhaite enregistrer son MDP sur le client TSE en Windows 7. Les groupes AD sont transformés en rôles de sécurité par une règle. Une autre règle, par exemple, associe l’adresse e-mail extraite du LDAP d’AD à un attribut supplémentaire du token.

Pour la mobilité, ADFS peut être exposé sous forme d’un proxy, qui aura une gestion de sécurité périmétrique différente. La communication entre ADFS et son proxy est chiffrée par certificats partagés.

STS-Resource

L’idée du STS-Resource est que le cadre de confiance du serveur n’a pas à être lié au STS qui est potentiellement plus proche du client, mais à un STS correspondant qui est plutôt dans son domaine. Le STS-Resource va émettre des données spécifiquement applicatives qu’il rajoute au token reçu et qui ne comportait que de l’identité.

On peut chaîner les STS-Resource, et même utiliser un STS-Resource qui se trouve dans un domaine Azure. La démo montre un SharePoint qui donne le choix entre l’authentification AD, et un STS à lui. On choisit cette deuxième possibilité, et on arrive ensuite à la page STS montrant les différents modes d’authentification. Bref, on a bien vu le relai opéré…

Fédération avec des partenaires

Le problème avec l’authentification partagée avec des partenaires est que si on traite au niveau applicatif, on est obligé de supporter tous les formats de tous les partenaires. ADFS peut alors être plutôt utilisé pour fédérer les partenariats, et réaliser de manière transparente la transformation de format.

Par contre, il faut alors que le ADFS soit capable d’aller retrouver les fournisseurs d’identités vers lesquelles elle peut avoir de la confiance. Une façon relativement simple de faire peut être de demander l’adresse email, et se servir du nom de domaine après le signe @ pour retrouver le serveur auquel on demandera de valider le token envoyé en claim.

L’exemple montré est de se rediriger vers la page Shibboleth du réseau Renater pour se connecter en retour sur un SharePoint.

Logiciel en tant que service

Conceptuellement, on est proche du scénario précédent, mais pour avoir une approche multi-tenant, il va falloir être le plus intégré possible avec les systèmes d’identité. La vraie difficulté est que seules des entreprises de taille suffisante pourront avoir un STS pour être fournisseur d’identité à destination d’une application Cloud. Pour les petites structures, l’idée peut être d’avoir un fournisseur d’identité dédié sur le Cloud.

Mais une autre approche peut être de faire confiance à des services comme ACS pour établir le cadre de confiance entre ADFS et des fournisseurs d’identités de réseau sociaux dans le nuage. Par exemple, on peut chaîner le STS sur un relai GoogleID, ou Facebook.

www.fabrikamshipping.com est une application de démo de ces modes de fonctionnement.

Solutions pour le Cloud

Sur le Cloud, le problème n’est pas sur la fédération, relativement bien maîtrisée, mais plutôt sur la présence de serveurs relais.

En démo, on déclare un domaine de confiance d’entreprise sur un site web envoyé sur le Cloud. On peut bien sûr optimiser les échanges, en faisant en sorte qu’une personne authentifié sur le domaine AD utilisé passe directement sur le site web dans le cloud.

WS-Trust, OpenID, WS-Federation sont supportés par ACS, qui est l’équivalent de ADFS mais sur le Cloud. En seconde démo, on passe donc par ACS, qui délègue à OpenID. Lui-même, qui se trouve dans le Cloud, avait été délégué par l’ADFS de l’entreprise pour accéder à une application dans le Cloud. On voit bien le chaînage dont on nous parlait au début de la session.

Sur ACS, on peut utiliser une interface web pour sélectionner les types d’authentification internet auxquelles on fait confiance.

La dernière démo se fait en utilisant une authentification Facebook sur téléphone mobile. Plus visuel, mais les concepts étaient bien les plus importants : le relai d’authentification, la transformation de protocole, et la capacité à réaliser ceci de manière automatique sur le Cloud.

Conclusion

Le passage vers des technologies sur Claims devrait se faire relativement en douceur. Les démos ont effectivement bien montré ce point : l’identité est facilement portable, en augmentant les cadres de confiance avec des partenaires.

http://tinyurl.com/claimsguide pour le guide Microsoft.

Posted in Retours, Sécurité | Tagged | Leave a comment

Ne gâche pas mon écran !

Bon, je ne suis certainement pas une référence en ergonomie, et d’habitude je ne me permets pas de faire des remarques sur des applications ou des pages web. Mais là, c’est trop…

Voici le problème :

DontWasteMySpace

Entre les bandes monstrueuses de chaque côté, le fait que le sommaire de l’article ne laisse pas la place au code, que la pub prend trop de place et que les retours à la ligne sont mal gérés dans le code, avec un ascenseur horizontal, on n’utilise plus que 20% de mes 1600 pixels de large !

Je n’ai pas acheté un écran 20 pouces pour lire sur la taille d’un téléphone portable !

Posted in Uncategorized | Leave a comment

Utilisation de la grammaire M d’OSLO pour créer des arbres d’expression lambda

Contexte

Dans le cadre d’une étude sur la prévalence, un besoin a été émis de générer de la requête ad-hoc sur les ensembles de données. La demande émerge souvent des discussions sur la prévalence, et la question m’a été posée à chacune des trois conférences AgileTour dernièrement.

Ma réponse habituelle est de montrer l’utilité de Linq To Objects pour le requêtage des objets prévalents, et un précédent article a déjà montré le mécanisme et ses excellentes performances. Mais il reste deux points à traiter…

Le premier est le SQL historique. Quand on a 30 000 requêtes pour du reporting, il serait intéressant de pouvoir transformer automatiquement ceci en requêtes Linq sur la base prévalente. Je suis en train de créer un parseur de SQL en lien avec du Linq To Objects et j’espère pouvoir vous en parler dans quelques mois. Evidemment, le but ultime sera d’avoir un provider ADO.NET branchable sur un serveur prévalent, mais il y a beaucoup de travail. Au passage, si quelqu’un est intéressé par un projet OpenSource autour de ceci, merci de me contacter.

Le second est un peu plus simple, heureusement : lorsque des requêtes étaient créées à la volée par des mécanismes de requêteur comme il en existe dans de nombreuses applications de gestion, il est intéressant de pouvoir générer automatiquement le Linq To Objects correspondant. Je pense que le projet VisualLinq de Mitsuru Furuta peut donner de bonnes idées, mais dans un premier temps, voici une proposition de résolution basée sur la grammaire M d’Oslo, ainsi qu’une construction dynamique des arbres d’expression lambda.

OSLO et la grammaire M

OSLO est une technologie Microsoft orientée vers la programmation des modèles. On pourrait longuement parler sur son intérêt pour le Domain Driven Development et les DSL, mais on va se concentrer pour cet article sur la grammaire M que ce framework propose, en partant d’un exemple simplissime.

Pour cela, je renvoie sur l’excellent blog http://www.techheadbrothers.com/Articles.aspx/evaluation-expressions-mathematiques-mgrammar-page-1 à partir duquel j’ai repris l’exemple ci-dessous. Mais la source la plus complète pour des informations sur M est le blog de référence, à savoir http://blogs.msdn.com/b/modelcitizen/

La grammaire M que nous allons étudier est la suivante :

module MCalc
{
    language MCals
    {
        // Options principales
        syntax Main = Expression;
        interleave Inutile = Espace;
        token Espace = ‘\r’ | ‘\n’ | ‘ ‘;

        // Définition des nombres
        token Integer = Digits+;
        token Digits = ‘0’ .. ‘9’;
        token Number = Integer? ‘.’? Integer;
           
        // Gestion des enchaînements
        syntax Expression
            = x:Number => x
            | g:Expression left(1) ‘+’ d:Expression => Plus {g,d}
            | g:Expression left(1) ‘-‘ d:Expression => Minus {g,d}
            | g:Expression left(2) ‘*’ d:Expression => Times {g,d}
            | g:Expression left(2) ‘/’ d:Expression => Divide {g,d}
            | g:Expression right(3) ‘^’ d:Expression => Power {g,d}
            | left(4) ‘(‘ g:Expression ‘)’ => g;
    }
}

Le principe de la grammaire M est de définir d’autres grammaires. En ce sens, M est un méta-langage. Ici, on est simplement en train de définir une expression comme étant un ensemble complexe d’expressions arithmétiques, avec en fin de récursion un nombre composé de digits, à savoir des symboles compris entre 0 et 9. Il y a bien sûr d’autres détails intéressants qui font toute la force de M, à savoir la gestion automatique des espaces (au sens large, c’est-à-dire tout caractère n’entrant pas dans la définition de l’expression), la prise en charge de la cardinalité, l’écriture sous forme fonctionnelle, etc.

Comment utiliser cette grammaire

Maintenant, il faut bien avouer que c’est un peu aride, comme ça. Donc, première chose à faire : télécharger OSLO. Ce lien donnera le download, ainsi que des détails supplémentaires sur ce qu’est OSLO.

Lors de l’installation d’OSLO, ne vous embêtez pas avec les autres options que le SDK : il contient le langage M et cela nous suffira.

image

Une fois qu’on a installé le produit, on a dans le menu démarrer accès à un éditeur de grammaire M.

image

Attention : pour les utilisateurs d’une CTP plus ancienne, veillez à le lancer en mode exemple. A mon avis, c’est un bug, mais le lancement normal ne permet pas d’ouvrir des fichiers pré-existants correctement.

Par contre, la difficulté pour ouvrir une session de test de grammaire est bien restée de l’ancienne CTP à la nouvelle. Si vous copiez-collez l’exemple, c’est bon, par contre, si vous souhaitez ensuite repartir du fichier .mg que vous aurez sauvegardé, le raccourci clavier est CTRL-SHIFT-T. Oui, c’est compliqué, mais c’est le principe des CTP…

Bref, une fois chargée la grammaire, vous vous retrouvez avec quelque chose comme ceci :

image

On commence mal, avec une erreur qu’il n’y avait pas sur la CTP précédente. Pour régler ça de manière rapide et brutale, on vire simplement le signe ? qui pose problème. OSLO considère visiblement qu’il y a un problème de cardinalité. Du coup, ça passe mieux, et on peut taper un premier exemple, montrant que la décomposition fonctionne correctement :

image

Rien que ce qui apparaît sur la droite est déjà très intéressant. Je peux penser à de nombreux cas d’analyse de SQL complexe où j’aurais bien aimé avoir ce système de décomposition arborescente pour retrouver la trame de la requête…

Générer l’API correspondante

Mais le plus intéressant est que vous allez pouvoir générer du code C# qui va effectuer la même décomposition sous la forme d’API, et vous renvoyer des classes générées pour vous et qui représentent les différents concepts que vous aurez créés dans la grammaire. En l’occurence, vous aurez accès à des instances de Expression, Plus, Minus, etc. tels que la grammaire les définit.

Pour cela, il suffit de lancer en ligne de commande mg.exe, que vous trouverez dans C:\Program Files\Microsoft Oslo\1.0\bin ou quelque chose approchant en fonction de vos paramètres système. Comme seul paramètre, mettez /t:source [votre fichier .mg]. Sur la nouvelle CTP, l’utilitaire a apparemment été renommé en m.exe, et on peut passer directement le fichier de grammaire en paramètre de ligne de commande, sans code d’argument. Par contre, j’ai eu un peu de mal à trouver les options pour générer du code : il semble qu’il y ait eu beaucoup de changement dans le mode d’utilisation de l’utilitaire. Bref, pour continuer ce post, je me baserai sur la CTP d’Octobre 2008, et je renvoie le lecteur à la doc. Si quelqu’un va au bout de l’exercice, je lui serais très reconnaissant de mettre un commentaire en expliquant la nouvelle grammaire d’appel.

Le résultat est un fichier source complexe, dans lequel vous allez trouver ce type d’entrées :

[System.Dataflow.TokenAttribute(((System.Dataflow.TokenModifiers)(0)), "__AnonymousToken2", "")]
internal class @__AnonymousToken2 {
    
    public static System.Dataflow.ParseTokenReference @__ReturnType;
    
    public class @__Production0 {
        
        [System.Dataflow.TermAttribute(0)]
        internal static @__lit7 Term0;
    }
}

[System.Dataflow.LiteralAttribute("*")]
internal class @__lit7 {
}

Ces deux classes internes servent par exemple pour la décomposition des expressions autour du symbole “*”. Si on se place un peu plus haut, on voit la définition de la classe principale, à savoir la classe spécialisant le parseur :

public class MCals : System.Dataflow.ParserBase {
        
    static System.Dataflow.ParserFactory @__parserFactory = System.Dataflow.ParserBase.LoadParser(typeof(MCalc.MCals), null);
        
    static System.Dataflow.ILexer @__lexer = System.Dataflow.ParserBase.LoadLexer(typeof(MCalc.MCals));

En appelant la fonction publique Parse de cette classe (détails sur le blog TechHeadBrothers dont j’ai donné le lien plus haut), vous obtiendrez un objet spécialisé que vous pourrez parcourir à l’aide d’un GraphBuilder. C’est là qu’on va pouvoir passer aux choses sérieuses…

Génération d’expression lambda

Pour revenir à notre problème initial, il s’agissait de pouvoir créer dynamiquement un prédicat de restriction sur une expression Linq To Objects.

Typiquement, en dur on a quelque chose comme suit :

List<Personne> Liste = new List<Personne>();
Liste.Add(new Personne() { Nom = "Gouigoux", Prenom = "JP" });
Liste.Add(new Personne() { Nom = "Lagaffe", Prenom = "Gaston" });

var Resultat = Liste.Where(p => p.Nom == "Gouigoux");

Mais on souhaite pouvoir créer dynamiquement l’expression lambda passée à Where. Pour cela, la solution est de créer un expression lambda en utilisant la classe System.Linq.Expressions.Expression. Dans notre exemple, cela donnerait :

var param = Expression.Parameter(typeof(Personne), "p");
var lambda = Expression.Lambda<Func<Personne, bool>>(
    Expression.Equal(
        Expression.Property(param, "Nom"),
        Expression.Constant("Gouigoux")),
    param);

Et c’est là que ça devient intéressant : ces enchainements d’appels à des méthodes peuvent s’étendre à l’infini. Supposons par exemple que l’on souhaite désormais générer l’expression lambda associée à la condition p.Nom.StartsWith(“Gouigoux”). On aura le code suivant :

lambda = Expression.Lambda<Func<Personne, bool>>(
        Expression.Call(
            Expression.Property(param, "Nom"), 
            typeof(string).GetMethod("StartsWith", new [] { typeof(string) }),
            Expression.Constant("Gouigoux")),
    param);

Utiliser l’API issue de M pour générer des expressions lambda à destination de Linq

Bref, on peut à peu près tout faire, et surtout, on peut facilement adapter ceci à un parcours récursif d’une grammaire M avec des patterns de type visiteur. Lorsqu’on tombe sur un opérateur NON, par exemple, on peut simplement appeler une fonction renvoyant la négation d’une expression comme ceci :

static Expression RenvoieNegation(Expression Exp)
{
    return Expression.Not(Exp);
}

Si on crée autant de ce type de fonctions que de concepts dans la grammaire M, il suffit ensuite de créer l’expression en partant comme point de départ de l’objet issu du parsing.

Enfin, c’est le plus important et j’avais failli l’oublier, il faut bien compiler l’expression lambda en un prédicat adapté pour pouvoir l’appliquer sur un Where de Linq, par exemple :

List<Personne> Liste = new List<Personne>();
Liste.Add(new Personne() { Nom = "Gouigoux", Prenom = "JP" });
Liste.Add(new Personne() { Nom = "Lagaffe", Prenom = "Gaston" });

lambda = Expression.Lambda<Func<Personne, bool>>(
        Expression.Call(
            Expression.Property(param, "Nom"), 
            typeof(string).GetMethod("StartsWith", new [] { typeof(string) }),
            Expression.Constant("Gouigoux")),
    param);
Predicat = lambda.Compile();
ResultatLambda = Liste.Where<Personne>(Predicat);
foreach (Personne p in ResultatLambda)
    Console.WriteLine(p.Nom);

Note : on n’est pas obligé de préciser <Personne> sur le Where : .NET serait capable de l’inférer, mais je trouve ça un peu plus clair de le préciser lorsqu’on fait de la contrainte dynamique.

Conclusion

En mélangeant l’usage de grammaire M et de la composition dynamique d’expressions lambda, il est tout à fait possible de générer des requêtes Linq ad-hoc en fonction d’une grammaire entrante. Cette grammaire peut très bien être du SQL, ce qui répond à de nombreuses problématiques en prévalence, mais elle peut également correspondre à une grammaire propriétaire.

Supposons qu’une grammaire “COMMENCE_PAR(NOM, CONSTANTE(GOUIGOUX))” existe sous forme arborescente ou même textuelle dans une base de données, on pourra définir une grammaire M réalisant le parsing de cette expression, puis mettre en place une récursion de génération d’expression lambda remplaçant COMMENCE_PAR par un appel lambda à StartsWith et créant une constante avec Expression.Constant. Enfin, la compilation et l’intégration dans une requête Linq par le Where générique permettront d’exécuter cette contrainte sur une liste existante.

[Edit]

A noter qu’il y a aussi la possibilité, pour les cas très simples, d’utiliser XPathObjectNavigator, qui vous permettra de parcourir les objets d’un système prévalent en utilisant du XPath. Et du coup, c’est facile de faire des requêtes dynamiques par simple concaténation de texte.

Posted in .NET, Veille | Tagged , | Leave a comment

Une excellente journée à Rennes !

J’ai fait une conférence sur la prévalence aujourd’hui à Rennes, et c’était un vrai plaisir. Merci aux personnes qui sont venues, ont été attentives, bienveillantes et surtout ont posé autant de questions intéressantes. C’est un plaisir d’avoir un tel auditoire.

Bravo aussi aux organisateurs de l’évènement : la journée était parfaitement organisée, avec des orateurs de haut niveau mais très accessibles, et vous avez trouvé le positionnement idéal pour ne pas perdre les débutants tout en fournissant de la matière aux experts.

Retour sur ma session sur la prévalence

Je n’ai pas eu le temps de répondre à toutes les questions, et surtout, je me rends compte que je n’ai pas traité le sujet pour lequel il y a eu le plus de vite. Je m’en excuse platement : je me suis laissé embarqué dans le flux des questions et j’aurais du bloquer cinq minutes pour traiter cela en priorité.

Vous trouverez dans la catégorie Prévalence plus de détail sur la gestion de la modification du modèle de données, mais voici l’explication telle que je souhaitais vous la présenter lors de la conf’ :

Vous vous rappelez qu’on avait dans la classe BaseDonnees une liste de Personne, classe définie comme ceci :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DojoPrevalence
{
    public class Personne
    {
        private string _Nom;

        public string Nom
        {
            get { return _Nom; }
            set { _Nom = value; }
        }

        private string _Prenom;

        public string Prenom
        {
            get { return _Prenom; }
            set { _Prenom = value; }
        }

        public Personne(string Nom, string Prenom)
        {
            this._Nom = Nom;
            this._Prenom = Prenom;
        }
    }
}

Imaginons que nous ayons désormais besoin d’un membre GUID dans cette classe. Nous allons arrêter l’application prévalente, modifier la classe comme ci-dessous, recompiler et relancer :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DojoPrevalence
{
    public class Personne
    {
        private string _Nom;

        public string Nom
        {
            get { return _Nom; }
            set { _Nom = value; }
        }

        private string _Prenom;

        public string Prenom
        {
            get { return _Prenom; }
            set { _Prenom = value; }
        }

        private string _Guid;

        public string Guid
        {
            get { return _Guid; }
            set { _Guid = value; }
        }

        public Personne(string Nom, string Prenom)
        {
            this._Guid = System.Guid.NewGuid().ToString("N");
            this._Nom = Nom;
            this._Prenom = Prenom;
        }
    }
}

Que va faire le moteur de sérialisation ? Planter en nous disant que la classe a changé de définition ? Non, il va réagir le plus banalement possible en considérant que comme il n’a pas de donnée GUID, celle-ci sera simplement nulle. Du coup, les objets créés avant la modification du constructeur n’auront pas de GUID (ou plutôt, afficheront un texte par défaut), et ceux créés depuis la modification auront une valeur de GUID calculée.

Notez qu’on pourrait tout à fait décider de créer un GUID à la volée pour les anciens objets. Typiquement, ceci serait réalisé en mode lazy, lors de l’accès à la propriété.

Est-ce que ça marche aussi pour la suppression d’un champ ? Oui. La modification d’un nom de champ est vraiment un cas théorique car le plus simple est évidemment de créer un champ qui pointe sur un autre, mais imaginons que vous deviez transférer de la donnée d’un champ à un autre. Vous pouvez simplement faire une migration en deux étapes : création d’un nouveau champ qui se remplit à chaque appel, puis mise en place de la nouvelle version une fois toute la donnée migrée, pour supprimer éventuellement le champ qui ne sert plus.

A nouveau, vous pouvez tout à fait décider de travailler en mode lazy : la première fois qu’une fonction lit la nouvelle donnée, elle recopie l’ancienne, la supprime de l’ancien champ, et l’objet est migré. Mais vous pouvez également décider de lancer une phase de migration sur le démarrage du moteur de prévalence, avant même que celui-ci commence à traiter des commandes. Tout dépend de votre volumétrie et de vos besoins.

Un point sur la scalabilité

L’un d’entre vous m’a posé une question supplémentaire une heure plus tard sur la scalabilité et les moyens à mettre en oeuvre pour mettre en place des serveurs distribués utilisant la prévalence.

Je conseille de choisir entre deux architectures.

La première : gérer deux piles de commandes, et balancer la charge entre les serveurs par affinité de session avec les commandes affectées au serveur en mode prioritaire, et les commandes dupliquées pour synchronisation en mode à basse priorité. Cette méthode est adaptée à des mécanismes tels que de la gestion de demandes par internet (portails ouverts au grand public, etc.) où les risques de concurrence sur la donnée sont pour ainsi dire nuls. Et n’oubliez pas que le fait de ne pas avoir une consistance ACID ne signifie pas qu’on ne traite pas les cas restants, mais simplement qu’on accepte de les traiter dans un mode légèrement dégradé (mais qui en pratique ne pose pas de problème) afin de gagner en performance.

La seconde : vous avez un risque plus fréquent de concurrence sur la donnée, et il faudra mettre en place un système plus complexe, basé sur un mécanisme de compensation. Chaque serveur traite ses commandes, et les autres serveurs envoient des commandes de mise à jour des données (synchronisation du résultat au lieu de distribution des commandes sérialisées). Si les timestamp indiquent que la donnée a été modifiée entretemps, les serveurs émettent une commande de compensation permettant d’annuler les effets de toutes les commandes jusqu’à celle posant problème incluse. Evidemment, ceci augmentera fortement le temps de traitement de cet ensemble de commandes (il faudra repartir du dernier snapshot), mais c’est le prix à payer pour garder la consistance, et les cas, en pratique, sont ridiculement rares vu les vitesses de traitement de la donnée en mémoire. Cette architecture est plus particulièrement adaptée aux commandes nécessitant des traitements métier complexes.

Pour améliorer encore les performances de cette deuxième architecture, et ainsi créer une sorte d’hybride entre les deux systèmes profitant au mieux des avantages de chacun, il serait envisageable d’avoir un niveau de direction intelligent des commandes sur les serveurs en fonction de critères interdisant a priori la concurrence. C’est d’ailleurs ce qui est fait sans intervention sur la distribution lorsqu’on sépare les moteurs de prévalence sur des métiers différents.

La scalabilité profite à plein de la prévalence, par une sorte de double-effet kisscool : les transactions BASE plutôt qu’ACID favorise fortement la mise à l’échelle, mais en plus le fait d’avoir des traitements plus rapide, en plus d’améliorer les performances, améliore également la montée en charge des serveurs et diminue encore plus les risques de concurrence.

Conclusion

J’espère pouvoir vous montrer dans quelques semaines un premier prototype d’un convertisseur SQL –> requêteur intégré de prévalence, qui pourrait être un premier pas vers un connecteur ADO.NET pour les données prévalentes. Le résultat sera publié en Open Source, très certainement sur CodePlex. Gardez un œil sur ce blog si vous êtes intéressés !

Si d’autres questions vous viennent ou si vous souhaitez expérimenter la mise en place de la prévalence, surtout n’hésitez pas à me contacter par les commentaires. Et si vous avez loupé ma session, vous pouvez la retrouver à l’AgileTour Vannes le 14 Octobre, et à l’AgileTour Nantes le 21 du même mois.

Posted in .NET, C#, Prevalence, Retours | Tagged | Leave a comment

[C#] Connaissez-vous l’opérateur de Null-coalescence ?

Commençons par un opérateur plus simple

Bon, dit comme ça, c’est sûr, ça rebute un peu son développeur. On va commencer par l’opérateur ternaire. Vous avez certainement quelque part dans votre code (ou dans le code que vous maintenez) des tas d’instructions comme celles-ci :

if (Valeur != null)
    Resultat = Valeur;
else
    Resultat = string.Empty;

Vous savez certainement que l’opérateur ternaire vous permet d’écrire ceci de manière plus concise :

Resultat = Valeur != null ? Valeur : string.Empty;

La condition peut bien sûr porter sur n’importe quelle autre variable, et même dans le cas où on traite la variable Valeur, on pourrait tester qu’elle contient une chaîne ou qu’on peut la parser pour obtenir un autre type. Mais il est très courant tout de même qu’on teste sa nullité comme dans l’exemple ci-dessus, et dans ce cas, on peut utiliser une grammaire encore plus simplifiée, à savoir :

Resultat = Valeur ?? string.Empty;

L’opérateur de null-coalescence

?? est l’opérateur de coalescence à null, c’est-à-dire qu’il va renvoyer la variable sur laquelle il s’applique si celle-ci est différente de null, et sinon la valeur par défaut qui est passée ensuite.

S’il y a un cas où ceci s’applique souvent, c’est bien sur la gestion des types Nullable. Voici un exemple de variable Nullable<int> qu’on va convertir en entier grâce à l’opérateur de null-coalescence :

int? Test = 25;
int TestEntier = Test ?? 0;

Lors des premières utilisations, la grammaire peut sembler difficile à lire, mais on s’y habitue vite. Et surtout, cette écriture a un énorme avantage, en ce sens qu’elle permet de ne plus avoir à se poser la question du code le plus expressif entre les deux versions suivantes :

Resultat = Valeur != null ? Valeur : string.Empty;
Resultat = Valeur == null ? string.Empty : Valeur;

Avec l’opérateur ??, la valeur par défaut est toujours à la fin, et on s’habitue au fur et à mesure à chercher toujours l’opérateur par défaut à la fin. De même, si on chaîne cet opérateur, on obtient une instruction très expressive :

Resultat = Valeur1 ?? Valeur2 ?? Valeur3 ?? string.Empty;

Ce code est l’équivalent de ceci :

if (Valeur1 != null)
    Resultat = Valeur1;
else if (Valeur2 != null)
    Resultat = Valeur2;
else if (Valeur3 != null)
    Resultat = Valeur3;
else
    Resultat = string.Empty

Il est indéniable que la première grammaire est beaucoup plus simple à lire : en parcourant de gauche à droite, le résultat prendra la première valeur non nulle, et sinon la toute dernière valeur.

Un dernier bout de code pour faire voir l’apport important de l’opérateur ??. Si vous utilisez cet opérateur pour supprimer le caractère Nullable d’un type, comme on l’a vu dans l’exemple plus haut, ce n’est pas seulement le code suivant que vous remplacez :

if (Test != null)
    TestEntier = Test;
else
    TestEntier = 0;

Et ce pour une bonne raison : le code précédent ne compile pas ! Il faut en effet écrire :

if (Test != null)
    TestEntier = (int)Test;
else
    TestEntier = 0;

Et oui, le cast est obligatoire, et l’opérateur de null-coalescence vous en dispense. Bref, ce n’est pas qu’un raccourci d’écriture, mais réellement un opérateur à part entière.

Digression sur les Nullable

Tant qu’on en est à parler des Nullable, vous vous êtes déjà demandés ce que renvoyait ce code ?

int? Test = 25;
Console.WriteLine(Test.GetType().FullName);

Il renvoie “System.Int32”, alors qu’on s’attendait à quelque chose comme “System.Nullable”, non ? Le code ci-dessous, par exemple, renvoie “System.Collections.Generic.List`1[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]” :

List<string> Liste = new List<string>();
Console.WriteLine(Liste.GetType().FullName);

Et du coup, il faut appeler le code ci-dessous pour obtenir le type sur lequel se base la collection générique, à savoir “System.String” dans notre exemple :

Console.WriteLine(Liste.GetType().GetGenericArguments()[0].FullName);

Les Nullable<> ne fonctionnent pas de la même manière. Si vous appelez GetType() sur une variable, vous aurez toujours le type valeur. Si vous voulez retrouver l’information comme quoi le type de la variable “Test” est Nullable, le seul moyen est de partir du type lui-même :

Console.WriteLine(typeof(int?).IsGenericType + Environment.NewLine);
Console.WriteLine(typeof(int?).FullName + Environment.NewLine);
Console.WriteLine(typeof(int?).GetGenericTypeDefinition().FullName + Environment.NewLine);
Console.WriteLine(typeof(int?).GetGenericArguments()[0].FullName + Environment.NewLine);

Ce code renverra les valeurs ci-dessous :

image

Tout ceci n’est évidemment pas sans lien avec l’inutilité du cast dont je parlais plus haut, ou avec le fait que le mot clé is fonctionne sur un Nullable<int> avec un opérateur int. Ou de manière plus technique, le code ci-dessous affichera true :

Console.WriteLine(Test is int);

Voilà une petite astuce sur quelques lignes, et qui finit par faire un article complet.

[Edit]

Je rajoute à la main les commentaires, suite migration de mon ancienne plateforme de blog à celle-ci.

Paslatek :

Très pratique ce p’tit opérateur ! Merci pour l’astuce/article.
Juste histoire de chipoter sur le dernier code avant la partie sur les nullables j’aurais plutôt fait ça pour eviter le cast :
if (Test.HasValue)
    TestEntier = Test.Value;
else
    TestEntier = 0;
mais le ?? me semble bien plus pratique effectivement !

Posted in .NET, C# | Tagged | Leave a comment

AgileTour à Rennes, Vannes et Nantes les 7, 14 et 21 Octobre

J’aurai le plaisir de vous présenter deux conférences conjointes avec Guillaume Collic d’Alt.Net lors des trois conférences AgileTour Bretagne en Octobre. La première partie traitera de manière générique du Domain Driven Design et en particulier de CQRS. La seconde sera un Dojo de type Kata (c’est à dire un exercice pratique en code) pour appliquer ceci sur un vrai projet en .NET, en utilisant le modèle de la prévalence dont j’ai déjà parlé dans ce blog.

Je serai également orateur sur une seconde session intitulée “Agilité et Architecture : comment réconcilier les frères ennemis ?”, à Vannes seulement. Il faut bien réserver un peu d’exclusivité à la ville d’où je viens 🙂

Vous pouvez retrouver toutes les informations nécessaires ainsi que le lien pour vous inscrire sur http://www.agiletour.org/fr/at2010_morbihan.html

at2010speaker

Posted in Veille | Tagged | Leave a comment