Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Depuis déjà un an, je conseille vivement les utilisateurs de Workflow Foundation 3 à migrer vers la version 4. L'information qui va suivre ne devrait donc pas trop prendre au dépourvu les personnes qui m'ont suivi.

Je profite de ce poste, pour faire le relais d'une information qui m'a été communiquer aujourd'hui par l'équipe Workflow Foundation de Microsoft.

Avec .net 4, le namespace utilisé par WF est devenu System.Activities namespace. Les namespace de WF3 ont été conservés et inchangés. Lors de la publication de la prochaine beta de .net 4.5, ces éléments présents dans ces namespaces seront marqués comme obsolètes. Les assemblies suivantes auront donc un ou plusieurs types qui deviendront obsolètes:

  • System.Workflow.Activities.dll
  • System.Workflow.ComponentModel.dll
  • System.Workflow.Runtime.dll
  • System.WorkflowServices.dll
  • Microsoft.Workflow.DebugController.dll
  • Microsoft.Workflow.Compiler.exe
  • Wfc.exe

Les types liés aux Wrokflows dit "de règles" (ex: System.Workflow.Activities.Rules), ne seront pas dépréciées car elle n'ont pas d'équivalent dans WF4.

Concraiterement, cela signifie que si vous utiliser un des types dépréciés, vous obtiendrez un warning lors de vos compilations avec Visual Studio 11 et .net 4.5. Les warnings devraient être proche de ceci : “ Warning BC40000: X is obsolete: ‘WF 3 types are deprecated. Please use WF 4 instead.’ ”

Comme à l'accoutumé, cet encouragement est très important, car il signifie qu'après .net 4.5, les éléments obsolètes disparaitrons définitivement. Actuellement, Microsoft n'a pas encore statué sur la version de .net qui mettra fin à WF3. Seule chose certaine, on pourra encore faire du WF3. Microsoft restant dans la ligne droite de ce qui a été fait avec l'arrivée de WF4, WF3 ne va pas disparaitre instantanément. Si vous n'êtes pas encore familiarisé avec WF4, il est encore temps. Le framework .net4.5 vous laisse un petit répit.

Bien entendu, ceci ne remet pas en cause la politique de support de WF3 ( Microsoft Support Lifecycle Policy).

Conclusion

Les utilisateurs de WF3 sont donc vivement encouragés à migrer vers WF4. Afin de vous faciliter la chose, l'équipe WF vous conseil de consulter les WF 4 Migration Guidance et d'utiliser le WF Migration Kit es les informations de la page CodePlex de WF (WF CodePlex).

Je tiens à rappeler que ceux-ci ne sont que des aides à la migration progressive vers WF4. A plus long terme, il faudra envisager de se passer su kit de migration et de ne coder qu'avec WF4.

Bonsoir,

Certes, je l'annonce avec un peu de retard, mais je serai effectivement au Techdays demain.

Comme l'an dernier, je participerai au programme ATE (Ask The Expert). Si vous avez des questions Workflow, WCF, AppFabric ou plus généralement .net, n'hésitez pas à m'aborder!

Affin de faciliter les choses, je garderai on Twitter ouvert pour ceux qui veulent me retrouver @JeremyJeanson

Quand on me parle WF4, il y a une remarque qui revient souvent :

Les workflows consomment de la mémoire qu'il ne libèrent jamais.

Après avoir participé à quelques profilages d'applications, j'ai remarqué qu'il s'agissait bien trop souvent d'une erreur de conception que j'ai surnommée "Poupées russes". Le principe est simple, vous avez besoin qu'un workflow lance un second worklow, qui lui même peut lancer un troisième workflow. Ceci sans qu'aucun workflow n'attende la fin de l'exécution de celui qui l'a invoqué (son parent).

L'erreur consiste à penser que les premiers workflows sont finis et donc qu’il n’on plus rien à faire en mémoire. Malheureusement, ce n’est pas le cas. La raison en est toute simple : vous invoquer vos activités de manières séquentielles.

Afin d’imager mes propos, j’ai réalisé un petit schéma. Celui-ci représente le cycle de vie de nos 3 workflows.

 

Modelisation_wf4_poupeesrusses_01

On peut très clairement constater que :

  • Le workflow1 est présent en mémoire de l’instant T1 à T5.
  • Le workflow2 est présent en mémoire de l’instant T2 à T4+le temps pour se terminer.
  • Le workflow3 est présent en mémoire de l’instant T3 à T4.

 

Heureusement, nous sommes en mesure d’invoquer nos workflows de manière asynchrone. Ce qui permet d’avoir une représentation similaire à ceci :

Modelisation_wf4_poupeesrusses_02

On peut très clairement constater que :

  • Le workflow1 est présent en mémoire de l’instant T1 à T2+le temps pour se terminer.
  • Le workflow2 est présent en mémoire de l’instant T2 à T3+le temps pour se terminer.
  • Le workflow3 est présent en mémoire de l’instant T3 à T4.

Chaque workflow ne sera donc utile en mémoire qu’un temps réduit (sa période d’activité réelle). Le garbage collector pourra donc nous restituer la mémoire utilisée par les workflows 1 et 2 avant que le 3 ne soit terminé.

Contrairement à ce que certain peuvent penser, avec WF4 invoquer un workflow au sein d’un autre n’est pas très compliquer. Afin de présenter l’ensemble des erreurs et approches possible, je vais vous présenter ici différentes approches:

1) Utilisation des workflows dans la définition des workflows parents

Il s’agit là du cas courant, on utilise les workflows 2 et 3 directement au sein de leur workflow parent.

wf4_poupeesrusses_00

Après exécution, le résultat est sans appel.

wf4_poupeesrusses_01

On obtient le cas d’une exécution séquentiel où le workflow 1 est présent du début à la fin.

 

2) Utilisation du WorkflowInvoker

À la place des workflows, on utilise une activité chargée de l’invocation. J’utilise ici le WorkflowInvoker tel que l'on peut le voir le plus soulant avec WF4.

public sealed class Invoke<T> : CodeActivity where T:Activity
{
    protected override void Execute(CodeActivityContext context)
    {
        var workflow = Activator.CreateInstance<T>();
        WorkflowInvoker.Invoke(workflow);
    }
}

Les workflows sont ensuite modifiés comme ceci :

wf4_poupeesrusses_02

 

Malheureusement, à l’exécution on obtient la même sortie que si l’on ne disposait pas de la classe Invoke<T>.

wf4_poupeesrusses_01

Ceci est parfaitement logique, car la méthode Invoke n’est pas une méthode asynchrone. Le fait de ne pas utiliser le l’ActivityContext des workflows parents n’a donc pas d’impacte.

 

3) Utilisation du WorkflowApplication

Je modifie le code de l’activité Invoke<T> afin d’utiliser un WorkflowApplication, comme ceci:

public sealed class Invoke<T> : CodeActivity where T:Activity
{
    protected override void Execute(CodeActivityContext context)
    {
        var workflow = Activator.CreateInstance<T>();
        var invoker = new WorkflowApplication(workflow);
        invoker.Run();
    }
}

Ce qui lors de l’exécution donne enfin le résultat escompté :

wf4_poupeesrusses_03

L’exécution d’un appel asynchrone à une méthode sans attendre la fin de son exécution ne bloque donc pas le workflow parent. L’ActivityContext n’est pas non plus perturbé par cet appel.

NOTE : si vous souhaitez utiliser des variables d’un workflow parent comme argument d’un workflow enfant, il faut juste utiliser l’ActivityContext pour résoudre ces variables avant l’invocation du workflow enfant.

 

3) Utilisation une instance du WorkflowInvoker

Le WorkflowInvoker dispose d’une méthode asynchrone. Celle-ci est souvent méconnue (la faute aux démonstrations/showroom publiques qui se font toujours avec les méthodes statistiques).

Si on l’utilise dans notre classe Invoke<T> on obtient le code suivant

public sealed class Invoke<T> : CodeActivity where T:Activity
{
    protected override void Execute(CodeActivityContext context)
    {
        var workflow = Activator.CreateInstance<T>();
        var invoker = new WorkflowInvoker(workflow);
        invoker.InvokeAsync();
    }
}

Bien entendu, ceci donne le résultat escompté lors de l’exécution :

wf4_poupeesrusses_03

 

 

Pour résumer : L’invocation asynchrone d’un workflow enfant sans attendre qu’il se termine peut se faire de manière très simple. Il n’est donc pas utile de réinventer la roue sous prétexte que l’on utilise Workflow Foudation Clignement d'œil

Cela fait déjà plusieurs fois que l'on me fait remonter un bug qui n'en est pas un : votre application ne se ferme pas quand vous le lui demandez. Celle-ci a un ou plusieurs workflows en exécution constante.

Si votre application ne se ferme pas, c'est à cause de vos hôtes de worklows. Ceux-ci resteront actifs tant que vous ne leur aurez pas indiqué la marche à suivre.

Trois possibilités s'offrent à vous : décharger, terminer, annuler (méthode s Unload, Terminate et Cancel).

Un tel contrôle n'est envisageable qu'avec un WorkflowApplication ou un WorkflowServiceHost. Pour le second, cela coïncide avec la fermeture de l'hôte WCF, les blocages à ce moment sont inexistants.

Note: décharger, induira une persistance uniquement si vous avec configuré l'hôte pour qu'il fasse persister son workflow. La persistance n'est donc pas automatique.

Mais il ne faut pas croire pour autant que l'appel de ces méthodes est suffisant. Il faut aussi que l'activité en cours d'exécution accepte d'être interrompue. Pour une activité dont le temps d'exécution peut être long, il faudra impérativement coder la méthode Cancel de vos activités. Malgré son nom, celle-ci peu être utile quel que soit le motif d'interruption de l'exécution du workflow.

Pour rappel, voici un lien vers mon article MSDN : "Bonnes pratiques pour coder des activités avec WF4" qui expliquent entre autres la manière d'implémenter le cancel.

Cela fait déjà un certain nombre de fois que je tombe sur un code similaire à celui-ci :

private void DoJobs(IEnumerable<Object> data,CancellationToken token)
{
	// Option pour permettre l'annulation des jobs
	ParallelOptions options = new ParallelOptions {CancellationToken = token};
	Parallel.ForEach(
		data,
		options,
		DoJob);
}
 
private void DoJob(Object data)
{
	// ...
}

Si la méthode Cancel de la CancellationToken Source à l'origine du token est appelée avant le lancement de notre méthode DoJobs, il y aura une exception sur le Parallel.ForEach.

cancelexceptiontoken

 

Certain corrigerons le tir en remplaçant leur code par :

private void DoJobs(IEnumerable<Object> data,CancellationToken token)
{
	try
	{
		// Option pour permettre l'annulation des jobs
		ParallelOptions options = new ParallelOptions { CancellationToken = token };

		Parallel.ForEach(
			data,
			options,
			DoJob);
	}
	catch (OperationCanceledException ex)
	{
		Trace.TraceError(ex.Message);
	}
}

C'est effectivement une solution. Mais dans le cas où l'on peut savoir si une annulation est en cours avant même de lancer une autre opération, pourquoi n'utiliserions-nous pas plutôt un code tel que celui-ci?

private void DoJobs(IEnumerable<Object> data,CancellationToken token)
{
	// Annulation possible
	if (token.IsCancellationRequested) return;

	// Option pour permettre l'annulation des jobs
	ParallelOptions options = new ParallelOptions { CancellationToken = token };

	Parallel.ForEach(
		data,
		options,
		DoJob);
}

Bien entendu, les plus prudents iront peut-être vers un

private void DoJobs(IEnumerable<Object> data,CancellationToken token)
{
	// Annulation possible
	if (token.IsCancellationRequested) return;
	try
	{
		// Option pour permettre l'annulation des jobs
		ParallelOptions options = new ParallelOptions { CancellationToken = token };

		Parallel.ForEach(
			data,
			options,
			DoJob);
	}
	catch (OperationCanceledException ex)
	{
		Trace.TraceError(ex.Message);
	}
}

Et vous, comment préférez-vous, jouer vous avec les CancellationToken et leurs sources?

 

PS : j’ai voulu présenter ici un cas simple. Je ne passe donc pas de token à ma méthode DoJob dans cet exemple.

Voici un sujet qui peut sembler anodin : vous avez développé l'application du siècle et devez la déployer sur un serveur. Mais l'installation du serveur ou de votre application n'est pas de votre ressort. Il faut passer par un administrateur ou par une société tierce.

Ce cas peut vous sembler simple. On rédige un beau document, où l'on dit faites ceci, faites cela.

En théorie : oui, les choses peuvent se passer ainsi. Mais en pratique, je me suis aperçu que de nombreux développeurs ne savaient pas ce qu'ils pouvaient demander à un administrateur.

On arrive très souvent à des situations rocambolesques, où les développeurs ont besoin d'un Framework x, et ne veulent surtout pas que le Framework supérieur soit installé (il n’y a pas forcement de raison valable à un tel choix, si ce n’est peut-être, la peur de l‘inconnu).

Or, il se trouve que certains OS serveurs ne permettent pas l'installation d'une Framework sans ajouter aussi, sa version supérieure. C'est le cas des générations 2008 et supérieur qui intègrent le Framework, comme étant une fonctionnalité du serveur, devant être installée via sa console de gestion.

Afin de vous simplifier les choses, j'ai tenté de résumer en un tableau, les différentes possibilités :

.net 1.0

.net 1.1

.net 2.0

.net 3.0

.net 3.5

.net 3.5.1 (SP1)

.net 4

.net 4.0.1 (PU1)

NT4

oui

oui

non

non

non

non

non

non

2000

oui

oui

oui

oui

oui

oui

non

non

2003

oui

oui

oui

oui

oui

oui

oui

oui

2008

non

oui

Feature

3.0

Feature

3.0

oui

oui

oui

oui

2008
(mode Core)

non

non

non

non

non

non

non

non

2008 R2

non

oui

Feature 3.5.1

Feature 3.5.1

Feature 3.5.1

Feature 3.5.1

oui

oui

2008 R2 (mode Core)

non

non

Feature 3.5.1 (limité)

Feature 3.5.1

(limité)

Feature 3.5.1

(limité)

Feature 3.5.1 (limité)

oui

(limité)

oui

(limité)

Légende :

  • Non : Installation impossible, il n'existe pas de solution supportée.
  • Oui : L'installation est possible via un package de déploiement indépendant (setup.exe, .msi, windows update).
  • -Feature X.X.X : L'installation passe obligatoirement par la console de gestion du serveur et l'ajout de la fonctionnalité .net en version X.X.X. Attention : sur un serveur en mode Core, certain namespaces ne sont pas inclus (limité).

 

Étant donné, que je vise essentiellement l'usage serveur web, ce tableau n'affiche pas explicitement les services pack des OS. J'ose espérer que vos fronteaux web sont à jour. ;)

Notez aussi que je ne m'aventurerai pas à faire des plans sur la comète. Windows Server Developer Preview et .net 4.5 ne sont donc pas présent dans ce tableau. Mais ils devraient suivre la logique que 2008 et 2008 R2.

Lors d'une mission sur une plateforme LAMP, j'ai eu la chance de rencontrer des personnes fort sympathiques. Et comme toujours quand je me prends d'affection pour un projet, je sors un peu du cadre strict de celui-ci pour voir ce qui se passe autour. Je me suis donc plongé corps et âme dans la redécouverte de la communauté "Open Source Linux". Ceci, dans l’idée de voir ce que cela pourrait apporté à mon client.

Si j'utilise des guillemets autour d'Open Source Linux, c'est que mon article ne va pas être tendre. Même si, j’ai une grande affection pour Linux et L’Open Source.

Après 6 mois à me faire asséner des grandes vérités de cette communauté "maid in gros geeks pro Linux", qui parle sans vraiment savoir, j'en suis sorti vraiment déçu. Toute la communauté n’est pas à mettre dans le même sac. Mais dans sa majorité, elle contribue à désinformer le grand public sur l’Open Source. Je profite donc ce poste-ci pour rappeler quelques "grandes vérités" de ce "petit monde très prétentieux".

 

1. Il n'existe qu'un Open Source

À en croire l'écosystème Linux, il n'y a qu'un "Open Source" et il ne peut exister que dans le monde Linux.

C'est sympathique pour le reste du monde qui se travail dure pour partager des applications et leurs codes gratuitement sur Windows.

Sous Mac, il y a une petite tolérance du fait de l'historique Unix. Mais si vous êtes sur une plateforme Microsoft, vous n'existez pas!

 

2. Avec l'Open Source tu peux tout faire, tu es libre.

En théorie, oui, dans la réalité, les codes sont bien souvent :

  • Obscures, car utilisant rarement un POO propre (voir pas de POO).
  • Peu ou pas du tout documentés.
  • Les préconisations minimales ne sont que rarement présentes.
  • Monter un environnement de développement relève du parcours du combattant (quelle version de la librairie X ou Y, la configuration PHP est elle particulière?... Ce serait un minimum de l'indiquer, mais ce n'est pas toujours le cas). Hors mis la version du noyau Linux, on en sait rarement plus.

 

3. L'Open Source, c'est avant tout la liberté et la simplicité pour 0€.

La chose qui me fait le plus rire là dedans, c'est de voir le nombre de sociétés qui sont passées à Linux, par effet de mode, ou pour des raisons politiques (et donc sans réelle information). Combien de ses sociétés sont passées à Linux pour le côté gratuit et se retrouvent maintenant avec des notes astronomiques? Ceci, uniquement pour maintenir un outil qui finalement ne correspond pas au besoin de leurs utilisateurs.

Dans ces situations-là, il faut faire appel à des professionnels qui s'y connaissent vraiment en plateforme Linux et pas dans "Le copain qui s'y connait en informatique". Lui, il y a de fortes chances qu'il réinstalle son Linux tous les mois tellement il l'a bidouillé. Bien entendu, c'est ce même "Ami qui vous veut du bien" qui dira : “Windows, c'est de la M... car il faut le réinstaller tous les 6 mois!”

 

4. Ça ne plante jamais!

Linux ne plante jamais et tout ce qui est fait pour Linux est fiable, contrairement à ce qui se fait chez Microsoft.

... c'est beau, d'être aveugle à ce point. Personnellement, quel que soit l'OS, j'ai toujours fait des sauvegardes pour éviter de tout perdre à cause d'un crash.

Et ci ça ne plante jamais, pourquoi de nombreux CMS PHP recommandent de faire un graceful apache régulièrement pour pallier à la situation X ou Y?

Et sous Android, (c'est Google, donc aux yeux de certains, ça vaut toujours mieux que le diabolique Microsoft; "µ$ pour les intimes" comme ils disent)… on oublie vite les difficultés que représentent les multiples adaptations réalisées pour chaque téléphone, afin que justement, l'application ne plante pas.

 

5. Rien n'est plus solide qu'un apache sous Linux!

C'est bien "connu", un Linux n'est jamais surchargé, quoiqu'il arrive, il résistera à tout sans broncher.

... Et la marmotte...

Sans rire, un serveur mal dimensionné reste un serveur mal dimensionné, qu'il tourne sous Linux ou Windows.

 

6. On utilise moins de serveurs.

Quand on choisit de faire tourner ses sites sur Linux, on a besoin de moins de serveurs...

Pas besoin d'avoir autant de machines que si on avait du Microsoft...

Donnez-moi des preuves, pitié, des preuves! J'ai vu des applicatifs PHP tourner mieux et avec moins de serveurs sur Windows Server + IIS que sur Linux + Apache.

 

7. 100% compatibles. Pas de soucis de migration!

Si on ne change rien : oui.

Si on passe d’un KDE à une Gnome, ce n’est pas gagné. Voir même d’un KDE à un autre on perd des applications. Mais il ne fait rien dire, c’est Linux, c’est le progrès.

 

8. Pas de DLL installées partout, qui alourdissent et font planter le système.

À mes yeux, c’est de loin l’affirmation la plus drôle. D’autant plus, quand je vois le nombre de librairies installées par défaut sur un Linux. Ou la quantité délirante, qu’il faut installer dans x versions, pour faire tourner les applications sur son PC. Mais pour comprendre ma remarque, il faudrait peut-être déjà savoir ce qu’est une DLL.

 

… etc ...

Et j'en passe, des meilleurs. Personnellement, cet Open Source là, je n'en veux pas!

Mon Open Sources à moi n'est en rien lié à un outil ou à une technologie. Je veux encore croire que ceci est possible. Alors pitié, arrêtez d'étiqueter l'Open Source comme propriété de à Linux et a son écosystème (utiliser le mot propriété dans le sens "exclusivité", est déjà une erreur en soi).

Partager, échanger, apprendre et comprendre, c'est ça mon Open Sources à moi!

 

 

PS: Ceux qui me connaissent le savent : durant des années (surtout durant mes études), il n’y avait pas un Windows chez moi. Je ne critique donc pas un OS que je ne connaitrais pas, mais l’aveuglement qui existe autour, et la volonté farouche de certains pour fermer les yeux.

Cette semaine ayant été entachée par le décès de Steve Jobs, les médias ont succombé à la maladie que j'appellerai : "L'hommage au grand Homme". Que l'on ne se méprenne pas, je trouve cela normal et je n'ai aucune intention de dénigrer qui que ce soit.

Cependant, je trouve injuste que ce qui est fait aujourd'hui, ne l’ait pas été fait pour d'autres. Afin de corriger le tir, je dédie ce poste à ces personnes géniales, mais totalement inconnues, qui sont certainement à l'origine de la technologie X ou Y sans laquelle mon PC ne fonctionnerait pas.

À vous qui n'êtes plus de ce monde, et qui avez fait ce que l'informatique est, je dis MERCI!

ILoveMyPC

Suite à un transfert de disques durs, j'ai récemment commis l'erreur du siècle, en voulant faire le ménage dans le multi-boot de ma machine. Via bcdedit j'ai supprimer l'ensemble des entrées, pour ne garder que celle de mon Windows 7. J'ai ensuite ajouté une entrée vers mon VHD contenant mon 2008 R2 avec le rôle d'Hyper-V.

Jusqu'ici tout allait bien jusqu'à ce que je veuille démarre une VM. Impossible! Mon hôte me dit que l'Hyperviseur n'est pas démarré.

Heureusement, une solution simple existe (vive la documentation de bcdedit). Il suffit de démarrer le 2008 R2 et de lancer la commande suivante en tant qu'administrateur :

bcdedit /set hypervisorlaunchtype auto

Après redémarrage, tout rentre dans l'ordre ;)

Moralité : si vous jouez du sysprep ou du bcdedit sur un système ayant le rôle Hyper-V, garder cette commande de côté.

En attendant de pouvoir jouer avec la prochaine version de TFS, je me suis lancé dans une petite recherche d'outils gratuits pour TFS 2010. Je suis alors tombé sur “TFS Work Item Manager” de Telerik. Actuellement en version beta 4. J'avais un peu peur, mai j'ai tenté le l'installation.

J'en ai tiré le constat suivant...

- Ergonomies : sympathique, rien à redire. M'aime si je n'ai me le thème sombre (on aime ou n'aime pas le style office 2007...).

- Fonctionnalités de base : Tout y est pour éditer ces WorkItems. Cela aurait été un comble s’il manquait quelque chose. À mon sens l'outil reprend un peu trop le fonctionnement de Visual Studio 2010 sur ce point. Hors mis pour la sélection de l'itération courante et l"Iteration Scheduler" que l'on trouve facilement ici.

 

Dans l'ensemble, je trouve que l'on peut se passer de cet outil si l'on n’utilise pas les fonctionnalités qui font toute la différence :

- Project DashBorad : Affiche en plein écran l'état actuel du projet, ceux qui on la chance de pouvoir y dédier un grand écran, c'est top. Pour le moment cela ne semble pas encore 100% opérationnel, mais c'est prometteur (même si je trouve que c’est peut être un peut trop).

- Task Board : Un beau tableau plein de post-it (virtuels). On peut y jouer du drag & drop pour déplacer ses post-its. En ajouter ou en supprimer (tout type de WorkItem). Et surtout ou peut facilement ajouter des tâches à une user Story et les voire directement apparaitre sur le tableau (j'aime!!!)

 

J'ai testé le Task Board sur un petit projet et ça donne cela :

Itération 1 (terminée): J'ai un bug fermé, mais non reproductible (l'outil me le met bien en évidence).

Capture_01

 

Itération 2 : Elle débute à peine.

Capture_02

 

Itération 2 : une tâche est terminée (maintenant... au travail pour attaquer les autres).

Capture_03

 

Bien entendu, on peut en plus filtrer les Work Item et/ou les regrouper (par type, état...)

Et pour les fans des vrais post-its : on peut imprimer ses Work Items, et sortir ses ciseaux pour ce lancer dans le découpage.… (je ne suis pas convaincu de l’utilité de la chose,… jouer avec des ciseaux, n’étant plus forcément de mon âge)

 

Et vous, avez-vous trouvé d'autres outils gratuits pour TFS 2010?

Mon dernier article pour MSDN est disponible : "Bonnes pratiques pour coder des activités avec Windows Workflow Foundation 4".

Vous pourrez y trouver tout le nécessaire pour coder efficacement des activités WF4.

 

31 pages de pur bonheur avec Workflow Foundation 4 Clignement d'œil

Suite à la Build, le monde s'agite, et il en va de même pour la future monture de .net. Dans ce cadre, l'équipe de Microsoft en charge de Windows Workflow Foundation est à l'écoute de vos remarques et propositions d'évolutions.

Si vous pensez avoir une idée sur ce qui manque à WF, c'est le moment de vous exprimer!

Pour participer, voici quelques liens utiles :

Si vous avez un peu de mal à exprimer vos idées en anglais, passez moi votre message, je ferai suivre ;)

Certains heureux utilisateurs de l'émulateur livré avec le kit de développement WP7 sont peut-être comme moi arrivés sur ce magnifique écran.

WP7_bootnvidia00

...et si comme moi votre émulateur n'a jamais affiché autre chose... Vous avez certainement des envies de meurtre. D'autant plus qu'après votre 101e recherche vous n'avez rien trouvé d'autre sur la toile qu'une information vous disant que cet émulateur n'était pas supporté sur les machines virtuelles (VM).

Oui, mais voila, votre PC et bien réel. Tout comme le débit qui a eu lieu sur votre compte lors de son acquisition.

En relisant de plus près les raisons qui conduisaient à cette incompatibilité plus les diverses informations parlant de fichiers d'états corrompus après mise à jour de drivers vidéo, je me suis lancé sur la piste du "driver gênant". Et j'ai trouvé l'intrus qui pose tant de soucis à mon émulateur... le PC portable:

Processeur : Intel Core i7-2630QM

RAM : 8Gb de RAM

Vidéo : Nvidia GeForce GT 555M 3Gb de Ram dédiée + Intel HD intégré

Et le gagnant est : "Optimus" le driver de la carte vidéo qui a la particularité de switch la carte graphique en fonction de la puissance demandée. Bonne nouvelle, on peut facilement forcer le PC à utiliser une carte vidéo X pour une application Y. Dans le cas présent, il faut se limiter à utiliser la carte Intel intégrée.

Si votre carte vidéo est une NVIDIA, ceci peut se faire en faisant un click droit sur son bureau puis "NVIDIA Control Panel":

WP7_bootnvidia01

 

En choisissant "Manege 3D settings", on peut ajouter une application via le bouton "Add":

WP7_bootnvidia02

 

On peut alors choisir notre émulateur.

"C:\Program Files (x86)\Microsoft XDE\1.0\XDE.exe" pour un OS 64bits

et

"C:\Program Files\Microsoft XDE\1.0\XDE.exe" pour un OS 32bits

WP7_bootnvidia03

 

Il reste alors à choisir la carte graphique préférée "Integrated graphics" (la carte Intel intégrée).

WP7_bootnvidia04

 

On click sur Apply et on peut enfin ouvrir son émulateur.

WP7_bootnvidia10

 

Miracle, ça marche!

Derrière ce titre un peu provocateur, ce cache en fait une vraie question, ou plutôt un vrai problème. À force d'assister à des démonstrations utilisant WCF, de nombreux développeurs finissent par croire que le BasicHttpBinding est tellement bien qu'on doit en mettre partout.

Cette conclusion trop hâtive tiens juste dans le fait que le BasicHttpBinding est le Binding par défaut quand on créé un service. Et bien souvent, lors d'une démonstration, on ne porte pas plus attention à son Binding... on a déjà tellement de choses à montrer en si peu de temps. Mea Coulpa!

Afin de corriger le tire, je me permets de vous proposer un petit schéma (qui restera certainement plus dans vos esprits que mes longues phrases interminables).

 

WCF - Bindings

 

Celui-ci met en avant une situation courante d'un applicatif utilisant WCF. En entrée j'ai voulu représenté quelque une de technologies en mesure de consommer un service WCF exposé sur le Web (et oui WCf peut servir à pal mal de monde!). Ceci en faisant la distinction entre les clients .net (hors Silverlight) qui sont en mesure d'avoir un Binding plus optimiser et plus sécurisé par défaut que les autres Bindings http pour lesquels il faut customiser un peu plus de Binding pour qu’il soit sécurisé.

Côté réseau local, afin d'améliorer les performances j'ai voulu donner la part belle au binding Tcp dédié aux clients .net. Et bien entendu à MSMQ pour les opérations acceptant le fait d'avoir une file d'attente. Opérations lourdes et longues en général, telles que les impressions ou le transfert de fichiers.

Côté administration locale on notera la possibilité d'utiliser les canaux nommés via le NetNamePipeBinding. Binding impossible à concurrence quand il s'agit de faire communiquer les applications entre elles quand elles se trouvent sur la même machine.

Mon intension étant de vulgariser un peu plus WCF et surtout l'un des aspects qui font sa puissance, je ne m'étalerai pas davantage sur les Bindings. Pour plus d'informations sur le sujet,je vous encourage aller sur la MSDN : Liaisons fournies par le système

Cet article à l'origine n'en était pas un, mais une réponse à un commentaire sur le blog de Julien Dollon. Après m'être rendu compte que mon clavier chauffait et que les mots s'alignaient tout seuls, j'ai fini par le poster sur mon propre Blog. Désolé pour les personnes qui pourraient se sentirent égratignées par ce message, mais je ne voyais pas rester sans défendre mes convictions. Même si j'allais le faire maladroitement.

L’article initile de Julien Dollon : Papa, plus tard je veux être chef de projet !

Bonjour à tous et vive les trolls!

Je ne m'exprime pas souvent sur dotnet-france alors je me présente pour les trolls qui voudraient être plus troll que moi :

Nom : Jérémy Jeanson,

Caractère : "Vieux con" (même s'il n'en a pas trop l'âge, 34ans IRL), râleur, très exigeant quand il s'agit de code.

Expérience : Aucune, je ne connais rien à rien, mais je dirai tout sur tout.

 

Venons au sujet :

Via cet article, Julien aborde un sujet dans l'air du temps. Oui on en parle un peu tous entre nous, c'est l'un des maux du métier et je ne m'exprimerai pas personnellement sur ce sujet, car j'ai beaucoup de mal à synthétiser de manière structurée le changement (voir la crise) que subit le domaine du développement:

  • Jeunes développeurs ou chef de projets prétentieux qui se croient arrivés au sommet de la pyramide (certain anciens aussi)
  • Formations initiales peu ou pas du tout adaptées.
  • Réticences au chargement / manque de remise en cause.
  • Projets incroyablement suivis, procédures et méthodologies très poussées... et pour finir avortement du projet.
  • …etc...

Résultat : il existe maintenant un nouveau type de profil "L'expert". Aussi appelé "Pompier", "Mission impossible", "L'agence tout risque", "Mc Gyver" ou "l'homme qui tombe à pic" dans certaines sociétés. Il arrive avant, pendant ou après la période prévue pour la conduite du projet. Ce profil ne veut pas forcément être chef de projet, mais il en assume régulièrement la fonction. Il ne compte pas ses heures, mais il peut être d'une productivité surprenante. D'autant plus qu'il trouve le temps de partager ses connaissances et/ou de former votre équipe. Dans les situations les plus difficiles, il est la valeur sûre de votre projet.

Je suis l'un des produits de cette crise. Je ne vais donc pas pleurer sur ce cas. Je le dis humblement, car mes connaissances représentent ma passion et un capital que je ne cesse de faire fructifier en apprenant et pratiquant toujours plus. Ce n'est donc pas par convoitise ou cupidité que je fais cela. C'est une envie de partager, de donner sans compter pour assurer une valeur ajoutée aux projets. Voilà pourquoi j'assume ce poste.Allez voir mes clients, ils vous le diront : "Il parle et partage des astuces tout le temps! On ne peut pas tout retenir!".C'est mon job et j'adore ça!

 

Trêve de bêtises et de bavardage: Julien, bouche-toi les oreilles, car tel que je te connais tes chevilles ne vont peut-être pas tenir.

Jusqu'ici j'ai beaucoup apprécié ce qui a été écrit par tout le monde. Je retiens entre autres un commentaire de Matthieu Mezil et les articles de Thomas Jaskula et Patrice Lamarche :

Jai surtout apprécié les différentes dérives humoristiques:

  • Cycles en V
  • Dev = Jobs alimentaires
  • Chef de projet pas du tout agile, tellement il cadre sa paperasse.

Par contre ce que je n'ai pas apprécié, ce sont les différents commentaires ici et là bien souvent rédigés par des personnes qui ont oubliées d'être humbles. Se prendre pour dieu, c'est un mal franco-français et ce n'est pas parce que certains le font qu'il faut croire que c'est le cas de tout le monde. Commencer des phrases par "Toutes les SSII sont...", "Tous les développeurs sont des...", "Moi je suis chef de ....", "Moi je sais que..."c'est d'un ridicule qui m'énerve!

 

Pourquoi donc est-ce que je dis ça?

Dans le cas présent, on s'attaque à l'expérience du "petit Julien" (reprise de l'un des commentaires). Julien Dollon aborde des sujets très variés (certains diront trop). Oui, mais il s'informe et s'approche des personnes qui ont l'expérience et qui font références. Quand il parle, c'est donc souvent en nous faisant profiter de ces expériences, des pros qui lui ont communiqué leurs savoirs et qui ont fait de lui un pro. Son expérience, il l'a donc acquise en peu de temps. Il n'en a peut être même pas conscience. Il a peut-être une personnalité qui ne plait pas à tous (et ça semble lui plaire). Si vous êtes jaloux, c'est votre souci.

Si vous voulez plus d'expériences, il n'y a pas de secrets, allez en formations. Interroger les experts!... Apprenez des autres! Il y a des personnes très ouvertes qui n'ont qu'une envie : "partager". Moi je fais ça tous les jours et je ne suis jamais rassasié.

Mais, s'il vous plait, ne comptez plus en années. Sinon, oui on peut jouer à ça : 10 ans de .net, qui dit mieux? (attention, c'est un piège pour trolls de niveau 300).

Il y a des personnes qui ont 20 ou 30 années “d’expérience” et qui ont tout à apprendre de ce métier!

 

PS : …no comment …

RE-PS : PS retiré pour grosse bourde de ma part.

Petite information qui ravira les utilisateurs de Workflow Foundation 3, il est maintenant possible de migrer ses définitions de workflows utilisant la machine à état vers WF4.

Bien entendu cela passe par la CTP 2 du kit de migration WF qui se trouve sur CodePlex : WF Migration Kit CTP 2.

Pour en savoir un peu plus sur ce kit, je vous recommande de lire l’excellent article de Ron Jacobs : Windows Workflow Foundation - WF Migration Kit CTP 2 Released.

Notez qu’il s’agit bien de migrer vers la SteaMachine WF4 intégrée dans l’Update Pack 1 de .net 4, et non pas le prototype  de SateMachine de CodePlex.

Régulièrement j'entends dire que Workflow Services (WS) est moins performant que WCF. Cette belle "affirmation", qui ne devrait pas exister, montre encore à quel point Workflow Foundation est mal connu, et mal utilisé.

Pour faire simple, voici 3 arguments de poids:

1) WS utilise WCF…

2) Un service WCF classique a pour but de permettre à un utilisateur d'exécuter une méthode M() à un instant T en obtenant ou non un retour de cette méthode. On peut entrer une ou plusieurs fois dans ce service, ceci n'a pas d'importance et ne change pas la disponibilité du service.

3) Un workflow est un processus complexe évolutif et non pas une simple méthode. Utiliser WF4 comme s’il s'agissait d'une simple méthode M() est donc en soi une erreur (synonymes envisageables: infamie, abomination, branlette intellectuelle).

Pour ce qui est de WS (donc un workflow exposé via WCF) : il a pour but de permettre à un utilisateur d'exécuter une méthode M(), et de gérer côté serveur une instance de workflow en attente de l'appel d'une ou plusieurs autres méthodes. Il est clair qu'un WS est fait pour répondre à une série d'appels et non pas qu'à un seul.

Le principe de WS peut être représenté par le schéma suivant :

WF4 - workflow Services - base

L'utilisateur peut faire plusieurs appels sur le service qui fera évoluer le workflow. Ce workflow pouvant être amené à gérer de nombreuses ressources externes (voir même d'autres workflows). Et les appels pouvant être espacé d’une durée plus ou moins longues (secondes, mois, années)

Du point de vue chronologique :

  1. Le premier appel à une méthode M() du WS instanciera le workflow. M() n'est alors plus accessible. M() reste visible par le client, mais son appel déclenchera une erreur
  2. L'appel à une méthode N() ou O() fera évoluer le workflow. N() ou O() ne sont alors plus accessibles.
  3. Les appels suivants feront de même jusqu'à ce que le workflow prenne fin. (Qaund le workflow à pris fin on peut rappeler M().

WCF ne suffisant pas à lui seul pour répondre à ce genre de besoin, voici donc le scénario dans lequel il convient d’utiliser WS et non pas un simple service WCF.

 

Dans un prochain article, j'expliquerai clairement comment l'hôte WS (le WorkflowServiceHost) fait la distinction entre les différentes instances de workflow présentes côté serveur.

On m’a déjà dit une paire de fois, qu'il était impossible d'ajouter une contrainte ou de valider d'argument Result d'une Activity, CodeActivity... Il faudrait soi-disant ne pas utiliser ce type d'activité de base et utiliser les versions non génériques.

Désoler de briser ce mythe, cette opération est possible!

Comme pour toute opération de ce genre, cela passe par la réécriture de la méthode CacheMetadata().

Par exemple pour une activité que j'ai codée récemment (du type sensé être le plus complexe, car héritant de AsyncCodeActivity), cela donne ceci :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.ComponentModel;
using MyMceSleep.Common;

namespace MyMceSleep.Workflow.Activities
{
    public sealed class AskUser : AsyncCodeActivity
    {
        [RequiredArgument]
        [DefaultValue(0)]
        public InArgument TimeConfigured { get; set; }

        /// 
        /// BeginExecute Async
        /// 
        /// 
        /// 
        /// 
        /// 
        protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
        {
            Func funct = Ask;
            context.UserState = funct;

            return funct.BeginInvoke(
                context.GetExtension(),
                TimeConfigured.Get(context),
                callback,
                state);
        }

        /// 
        /// EndExecute Async
        /// 
        /// 
        /// 
        /// 
        protected override EnumMessageBoxResult EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
        {
            Func funct = context.UserState as Func;

            return funct.EndInvoke(result);
        }

        /// 
        /// Interroger l'utilisateur
        /// 
        /// 
        /// 
        /// 
        private static EnumMessageBoxResult Ask(IMessageBoxExtension messageBoxExtension,Int32 timeConfigured)
        {
            return messageBoxExtension.Ask(timeConfigured);
        }

        /// 
        /// CacheMetadata
        /// 
        /// 
        protected override void CacheMetadata(CodeActivityMetadata metadata)
        {
            if (TimeConfigured == null)
            {
                metadata.AddValidationError(
                    new System.Activities.Validation.ValidationError(
                        "TimeConfigured must be set!",
                        false,
                        "TimeConfigured"));
            }
            else
            {
                RuntimeArgument arg = new RuntimeArgument("TimeConfigured", typeof(int), ArgumentDirection.In);
                metadata.AddArgument(arg);
                metadata.Bind(TimeConfigured, arg);
            }

            if (Result == null)
            {
                metadata.AddValidationError(
                    new System.Activities.Validation.ValidationError(
                        "Result must be set!",
                        false,
                        "Result"));
            }
            else
            {
                RuntimeArgument arg = new RuntimeArgument("Result", typeof(EnumMessageBoxResult), ArgumentDirection.Out);
                metadata.AddArgument(arg);
                metadata.Bind(Result, arg);
            } 
        }
    }
}

Comme on le voit bien dans la méthode CacheMetadata, je me suis permis de faire un test afin de forcer l'utilisateur à affecter une variable à l'argument Result.

Et bien que mon activité de base soit complexe, cela ne change rien à la validation présente sur Result.

Facile, il suffisait juste d'y penser ;)

Navigant aujourd'hui entre MVC et WebForm, je profite de ce poste pour exhumer un vieux bout de code dont je me suis déjà servi un bon nombre de fois pour n’afficher l’InserItemTemplate d’un control de donnée WebForm que lorsque l’on ne a besoin.

L’idée est simple : n’afficher l’InserItemTemplate que lorsque l’utilisateur click sur un bouton (genre “Inserer un nouvel enregistrement”).

Pour ce faire j’ai opté pour une solution tout aussi simple que la problématique : Utiliser la propriété InsertItemPosition pour afficher l’InsertItem position quand il est demandé.

Ce qui donne côté aspx:

     
       
             
             
             
             
             
             
       
     
 
 

Et côté code behind :

protected void Page_Load(object sender, EventArgs e)
{
     if (!this.Page.IsPostBack)
     {
          this.ListView1.InsertItemPosition = InsertItemPosition.None;
     }
}

protected void Button1_Click(object sender, EventArgs e)
{
     this.ListView1.InsertItemPosition = InsertItemPosition.LastItem;
}

protected void ListView1_ItemInserted(object sender, ListViewInsertedEventArgs e)
{
     this.ListView1.InsertItemPosition = InsertItemPosition.None;
}

Plustôt simple non?

Certains préfèreront peut-être un panel visible/invisible ?

Ceux qui me connaissent bien savent que quand je customise du JavaScript, cela n’est jamais vraiment de gaité de coeur. C’es comme ça, j’aime les serveurs, mais que serraient les serveurs sans clients. Clignement d'œil

Trêve de rigolade. Voulant utiliser jsTree pour un projet MVC3 je suis tombé sur un os. Le TreeView avait le bon rendu, mais les liens qui s’y trouvaient ne permettaient pas d’ouvrir les pages qu’ils ciblaient (vraiment pas drôle).

En cherchent bien, j’ai découvert que jsTree interceptait les clicks sur mes liens et qu’il me fallait refaire un bind sur une méthode qui se chargerait d’ouvrir mes liens. Ce qui a donné le code suivant.

$(function () {
    $("#archives").jstree().bind(
        "select_node.jstree",
        function (e, data) {
            document.location.href = data.rslt.obj.children("a").attr("href");
        })
})

“archives” étant l’Id de ma

devant être transformée en TreeView. Pour ceux qui ne connecteraient pas jsTreee, il s’agit d’une
qui doit contenir des imbrications de
  • représentant les Nodes du TreeView.

    Ce qui fonctionne plutôt bien. N’étant pas un expert S JavaScript, je prendrai volontiers toute remarque Clignement d'œil

Plus de Messages Page suivante »


Les 10 derniers blogs postés

- TechDays Paris 2012 : Session pleinière jour 3 par Blog Technique de Romelard Fabrice le il y a 23 heures et 48 minutes

- Mishra Reader : un lecteur RSS très Zune Style en Open Source ! par Cyril Sansus le 02-09-2012, 08:28

- [framework 4] Les Tasks et le Thread UI par Fathi Bellahcene le 02-09-2012, 00:33

- Workflow Foundation 3 a un pied dans la tombe par Blog de Jérémy Jeanson le 02-08-2012, 22:15

- TechDays Paris 2012 : Nouvelles tendances du poste de travail - Bring Your own PC par Blog Technique de Romelard Fabrice le 02-08-2012, 19:42

- TechDays Paris 2012 : System Center Service Manager 2012 Vue d’ensemble par Blog Technique de Romelard Fabrice le 02-08-2012, 17:32

- TechDays Paris 2012 : Pleinière second jour par Blog Technique de Romelard Fabrice le 02-08-2012, 16:23

- TechDays Paris 2012 : Retour d'expérience sur la mise en place d'un Cloud Privé par Blog Technique de Romelard Fabrice le 02-08-2012, 16:04

- TechDays Paris 2012 : Comment SharePoint a sauvé mes TechDays par Blog Technique de Romelard Fabrice le 02-07-2012, 23:59

- Perspective 3.0 pour Silverlight 5.0 par Perspective le 02-07-2012, 22:39