Création d’une VM Docker dans Azure

Azure propose aujourdh’ui une VM préconfigurée pour exécuter Docker sur un Ubuntu 15.04 Server afin de vous épargner la création d’une machine et l’installation des différents composants.

Voici les étapes à suivre pour avoir une machine disponible en quelques minutes :

1. Connectez vous sur votre compte Azure : http://portal.azure.com

2. Dans le portail, cliquez sur Nouveau

image

3. Rechercher l’image “Docker on Ubuntu Server” dans le marketplace

image

image

4. Cliquez sur Créer en bas de page, puis saisissez le nom d’hôte, le nom d’utilisation et mot de passe. Gardez le type d’authentification en Mot de passe plutôt que clé publique SSH pour des raisons de simplicité. Si vous êtes familiarisé avec SSH et les clés publiques, changez de mode. Sélectionnez votre niveau de tarification selon vos besoins, le groupe de ressources et l’emplacement du data center.

image

5. Cliquez sur Créer puis attendez la création de la VM qui devrait prendre quelques minutes.

6. Une fois la VM créée, connectez-vous à l’interface d’administration de celle-ci dans le portail Azure

image

7. Naviguez dans Gérer > Adresses IP pour récupérer l’adresse IP avec laquelle vous vous connecterez en SSH

image

8. Créez un point de terminaison pour autoriser la connexion sur le port HTTP (80) si vous déployer un container avec un serveur web en naviguant dans Gérer > Points de terminaison :

image

9. Pour tester la connexion SSH avec le serveur, utilisez un client SSH (par exemple Putty) et essayer de vous connecter pour valider la bon fonctionnement de votre nouvel VM Docker :

image

10. Exécuter la commande sudo docker pour vérifier le bon fonctionnement de Docker :

image

Votre VM Docker est maintenant fonctionnelle. Vous allez pouvoir héberger des containers (voir prochains posts).

“SYSTEM.IO.FILENOTFOUNDEXCEPTION: COULD NOT LOAD FILE OR ASSEMBLY ‘MICROSOFT.SHAREPOINT.CLIENT. WORKFLOWSERVICES”

Vous lancez votre application ou solution SharePoint utilisant CSOM et Workflow Manager 1.0(WorkflowServicesManager, Workflow Definition), vous avez le message suivant qui s’affiche : “System.IO.FileNotFoundException: Could not load file or assembly ‘Microsoft.SharePoint.Client.WorkflowServices, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c’ or one of its dependencies. The system cannot find the file specified.”

Solution 1 (application seulement) :

Vous copiez les DLLs suivantes à la racine de votre applications (si c’est une solution SharePoint, cette solution n’est pas applicable) :

  • - Microsoft.SharePoint.Client.dll
  • - Microsoft.SharePoint.Client.Runtime.dll
  • - Microsoft.SharePoint.Client.WorkflowServices.dll

Solution 2 :

Si gacutil.exe n’est pas sur votre serveur de production/qualification, copiez depuis le répertoire de votre machine de développement “C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6 Tools” (ou d’un répertoire v8.0, v8.1A) les fichiers suivants :

- gacutil.exe
- gacutil.exe.config
- 1033\gacutlrc.dll

Ouvrez une console en tant qu’administrateur. Depuis l’emplacement où vous avez copier gacutil.exe (ou depuis n’importe quel emplacement si vous avez mis gacutil dans le PATH), saisissez :

gacutil -i “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll”

gacutil -i “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll”

gacutil -i “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.WorkflowServices.dll”

Pour chaque commande, vous devriez avoir le message suivant : Assembly successfully added to the cache

Toutes les DLLs requises pour votre solution utilisant CSOM / Workflow Manager sont maintenant disponibles dans le GAC et votre solution devrait fonctionner.

Visual Studio 2015 est enfin là !

La version RTM de Visual Studio 2015 vient tout juste de sortir et nous avons le droit à de nombreuses améliorations et fonctionnalités comparé à VS 2013.

Alors pourquoi, un 'enfin' dans le titre ? Tout simplement car VS 2015 et .NET 4.6 apporte chacun de vraies nouveautés dans la façon de développer vos projets : nouveau modèle de projet, prise en charge de .NET 4.6 et ASP.NET 5 (et donc de .NET Core, la version open source et optimisée cloud de .NET), télémétrie (pour tout savoir de l'exécution de votre application), développement multi plateforme mobile, compilateur Roslyn, outils de diagnostic (un must), etc ...

La version Community est disponible à cette adresse : https://www.visualstudio.com/downloads/download-visual-studio-vs

Les versions entreprise sont quantà elles disponibles sur votre compte MSDN dès aujourd'hui !

Les éditions

Quelle édition choisir :

  • Edition Community : gratuit pour les étudiants, les projets open source et les équipes de petite taille. Les fonctionnalités vous permettront de développer des applications web, Azure, Windows et multi plateforme mobile (iOS, Android et Windows Phone).
  • Edition Professionelle : l'environnement le plus répandu parmi les développeurs expérimentés. Possède tous les outils nécessaires à développer une application complexe à l'aide d'outil de productivité de code (CodeLens, collaboration Agile, connectivité avec Team Foundation Server, VS Online, etc).
  • Edition Test Professionnelle : uniquement dédié aux testeurs avec uniquement les outils pour ce dernier.
  • Edition Entreprise : dédié aux sociétés souhaitant réaliser et automatiser les tests (charge, unitaires, etc) et utiliser IntelliTest et IntelliTrace pour le débogage. Mais encore avoir 150$ de crédits Azure par mois.

Les fonctionnalités en (très) bref

  • Outils de développement pour réaliser des applications web, mobile (iOS, Android et WP via Cordova et Xamarin), Windows, Windows 10 universelle (PCs, tablets, XBox, HoloLens, IoT), et cloud
  • Langages supportés : C#, JavaScript, NodeJS, TypeScript, Visual Basic, F#, C++, IronPython, ...

Coup de coeur : ASP.Net 5 et .NET Core

Supporté sur Windows, Linux et MacOS, les applications ASP.NET 5 et .NET Core vont pouvoir se déployer sur des serveurs cloud à moindre coût ! La plateforme .Net rentre dans une nouvelle phase d'adoption des développeurs, où mêmant outils et productivité, ceux-ci auront la vie beaucoup plus facile et pourront porter l'innovation rapidement et de façon fiable vers leurs utilisateurs.

Vous pouvez retrouver tous les projets .NET sur le github de la .NET Foundation à cette adresse : https://github.com/dotnet

Utilisation du service WorkflowQueuingService

L'exécution d'un workflow est souvent dépendante des entrées que les hommes (via une console ou une application Windows Form) ou les programmes (ASP.NET, Web Service, Mainframe, etc) feront dans votre workflow, même après plusieurs jours d'attente. Une activité qui attend des entrées d'une entité extérieure se doit de faire deux choses :

  • Notifier qu'elle attend des données (se mettre 'au repos')
  • Etre notifié quand les données seront mise à disposition.

Et cela, même si l'instance de son workflow est persistée (dans un fichier texte ou une base de données par exemple). Lorsque les données arrivent, le moteur d'exécution (le runtime) doit pouvoir recharger en mémoire l'instance et être capable de continuer l'exécution du workflow au bon endroit.

Comment faire en sorte de pouvoir spécifier au workflow qu'il est en attente d'une donnée et de traiter la donnée une fois celle-ci mise à la disposition de l'instance du workflow ? Comment assurer une communication 'propre' à l'intérieur des couches logicielles et de votre architecture ? Il y a plusieurs méthodes, plus ou moins robuste pour le faire,  une bonne méthode est néanmoins d'utiliser ce qui fait le fondement de WF : les files de Workflow !

De cette façon, à chaque fois que vous avez besoin de pousser une entrée vers le workflow, telle qu'une chaine de cractères ou tout autre objet (dans notre exemple, une transaction financière), vous ajoutez un élément à l'une ou les piles de l'instance du workflow. La pile se chargera à son tour d'appeler les méthodes abonnées aux évènements pour traiter ces entrées comme stimuli de l'activité. Ce principe nous permet d'utiliser le service WorkflowQueuingService qui s'exécute dans le moteur d'exécution de WF et qui va vous permettre d'ajouter et de nommer des files dans une instance de workflow.

L'autre avantage de cette méthode est le fait de pouvoir ainsi marquer des points d'exécution et des points de persistence dans votre workflow sans que vous ne soyez obligé d'être dans la portée d'une transaction.

Imaginons que nous voulons traiter un workflow simple qui attend le traitement d'une transaction financière par un serveur backend.

Voici la structure d'une transaction attendue comme entrée par le workflow :

public struct Transaction {

public double Amount;

public DateTime Date;

public Guid ID;

public Transaction(Guid id, double amount, DateTime date) {

this.ID = id; this.Amount = amount; this.Date = date;

}

public override string ToString() {

return string.Format("ID: {0} - Amount: {1} - Date: {2}", ID, Amount, Date);

}

}

Commençons par implémenter une activité possédant une propriété contenant notre transaction  :

public partial class WaitProcessedTransaction : System.Workflow.ComponentModel.Activity

{

private Transaction mTransaction;

public Transaction Transaction

{

get { return mTransaction; }

set { mTransaction = value; }

}

...

}

Voici les méthodes de création (méthode d'initialisation de l'activité) et de destruction (méthode de 'désinitialisation', comprendre que cette méthode est appelée de façon synchrone lorsque de la transition de l'état de l'activité de Executing vers Closed) de la file de Workflow :

protected override void Initialize(IServiceProvider provider) {

WorkflowQueuingService qService =

(WorkflowQueuingService)provider.GetService(typeof(WorkflowQueuingService));

if (!qService.Exists(this.Name))

qService.CreateWorkflowQueue(this.Name, true);

}

protected override void Uninitialize(IServiceProvider provider) {

WorkflowQueuingService qService = (WorkflowQueuingService)provider.GetService(typeof(WorkflowQueuingService));

if (qService.Exists(this.Name))

qService.DeleteWorkflowQueue(this.Name);

}

}

On peut constater que les files sont nommées, ici par le nom de l'activité.

Nous allons redéfinir la méthode d'exécution de l'activité par la méthode suivante :

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) {

WorkflowQueuingService qService = executionContext.GetService<WorkflowQueuingService>();

WorkflowQueue queue = qService.GetWorkflowQueue(this.Name);

if (queue.Count > 0){

this.mTransaction = (Transaction)queue.Dequeue();

return ActivityExecutionStatus.Closed;

}

queue.QueueItemAvailable += this.ContinueAt;

return ActivityExecutionStatus.Executing;

}

void ContinueAt(object sender, QueueEventArgs e){

ActivityExecutionContext context = (ActivityExecutionContext)sender;

WorkflowQueuingService qService = context.GetService<WorkflowQueuingService>();

WorkflowQueue queue = qService.GetWorkflowQueue(this.Name);

this.mTransaction = (Transaction)queue.Dequeue();

context.CloseActivity();

}

Dans la méthode d'exécution, nous récupérons le service de file puis nous extrayons l'entrée qui pourrait potentiellement se trouver dans la file. Si la donnée est récupérée de la file, nous spécifions la clôture de l'activité, sinon nous abonnons une méthode à l'évènement qui sera appelée dés qu'une entrée dans la file sera disponible, puis nous laissons le statut de l'activité comme 'en cours d'exécution'.

Maintenant c'est au tour de l'application de jouer son rôle en fournissant l'entrée dans la file nommée de l'instance du workflow :

// Création d'une instance de workflow et démarrage

WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(WorkflowDemo.WorkflowQueueTest));

instance.Start();

...

// On crée une transaction financière et la met dans la file nommée 'WaitTransactionProcessed' (qui est le nom de l'activité ciblée) ce qui aura pour effet de réveiller le workflow et d'exécuter la méthode abonnée à l'évènement 'QueueItemAvailable' de la file (méthode 'ContinueAt')

Transaction t = new Transaction(Guid.NewGuid(), 1000.0, DateTime.Now);

instance.EnqueueItem("AttendreTraitementTransaction", t, null, null);

...

En utilisant un objet d'une instance de workflow, et cela n'importe où dans l'application hôte, vous allez pouvoir marquer des points d'exécution dans votre workflow grâce aux files et communiquer une ou plusieurs entrées à votre activité pour pouvoir continuer son exécution. Cela est vrai même si celui-ci a été persisté pendant son état de repos.

Dans notre cas, nous parlons d'un workflow qui peut attendre un stimulus d'une entité extérieure sur des périodes plutôt longues, il faut donc s'attendre à se que le workflow soit décharger de la mémoire pour être persisté à un endroit physique. Dans notre cas nous allons le faire persister dans une base SQL Server 2005 (classique en quelque sorte) en utilisant le service SqlWorkflowPersistenceService (voici un lien pour mettre en place tout ce qu'il faut : http://msdn2.microsoft.com/en-us/library/aa349366.aspx).

clip_image002

Note : voici également un excellent schéma des états d'un workflow : http://msdn2.microsoft.com/en-us/library/aa663362.hostingwwf03l%28en-us,msdn.10%29.jpg

Voici les quelques lignes qu'il faut rajouter pour configurer le runtime :

...

string stringConnection = @"Initial Catalog=WF_Persistence;Data Source=localhost\SQLEXPRESS;User Id=x;Password=x";

// Création d'une instance du service de persistence Sql Server avec un argument à true pour spécifier de persister une instance de workflow dés que son état passe au repos

SqlWorkflowPersistenceService persistenceService = new SqlWorkflowPersistenceService(

stringConnection, true, TimeSpan.MaxValue, new TimeSpan(0, 1, 0));

workflowRuntime.AddService(persistenceService);

...

Pour mieux comprendre ce qui se passe on rajoute des handle à différents évènements qui afficheront les changements d'état :

workflowRuntime.WorkflowIdled += new EventHandler<WorkflowEventArgs>(workflowRuntime_WorkflowIdled);

workflowRuntime.WorkflowPersisted += new EventHandler<WorkflowEventArgs>(workflowRuntime_WorkflowPersisted);

workflowRuntime.WorkflowLoaded += new EventHandler<WorkflowEventArgs>(workflowRuntime_WorkflowLoaded);

workflowRuntime.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs>(workflowRuntime_WorkflowCompleted);

...

void workflowRuntime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e) { Console.WriteLine("Workflow completed !"); }

void workflowRuntime_WorkflowLoaded(object sender, WorkflowEventArgs e){ Console.WriteLine("Workflow loaded !"); }

void workflowRuntime_WorkflowPersisted(object sender, WorkflowEventArgs e) { Console.WriteLine("Workflow persisted !"); }

void workflowRuntime_WorkflowIdled(object sender, WorkflowEventArgs e) { Console.WriteLine("Workflow idle !"); }

...

Imaginons que nous avons un workflow séquentiel contenant notre activité qui attend le traitement d'une transaction lancée en amont d'un workflow, et d'une activité qui affiche un message de confirmation du traitement :

clip_image004

Nous pourrons observer le résultat suivant :

clip_image006

Voici un cas simple d'utilisation du service WorkflowQueuingService. Ce service est à la base de nombreuses activités et reste un moyen élégant et efficace de placer des points d'attente nommés - par le nom de la file - où vos activités peuvent recevoir des données, c'est à dire des endroits logiques dans votre workflow dont l'exécution peut être reprise quand un stimuli spécifique (une données, un évènement, ...) arrive, tout en étant capable d'être persisté pendant le temps d'attente.

Le lien MSDN vers le WorkflowQueuingService qui devrait être à la base de beaucoup de vos activités communicant avec l'extérieur (permet de remplacer très élégamment l'activité HandleExternalEvent : http://msdn2.microsoft.com/en-us/library/system.workflow.runtime.workflowqueuingservice.aspx