Sommaire
Dans cet article nous allons découvrir comment créer et déployer votre premier package Constellation en C# avec Visual Studio.
Prérequis
- Un accès “Administrator” à une Constellation (Management API & Developper access)
- Le SDK Constellation installé
Nous vous conseillons de suivre le guide de démarrage ici avant de démarrer.
Créez le package dans Visual Studio
- Lancez Visual Studio
- Créez un nouveau projet de type “Constellation Package Console” (dans la catégorie Constellation) :
- Démarrez le package en mode debug en cliquant sur le bouton “Start” ou en pressant la touche “F5” :
-
Au démarrage, votre package affichera une sorte de ”Hello World” :
Vous constaterez que :
-
La méthode “OnStart” est la méthode invoquée au démarrage de votre package
-
PackageHost.WriteInfo est une méthode pour écrire des logs de type “info”
-
PackageHost.IsRunning = true (votre package est bien en cours)
-
PackageHost.IsConnected = false (votre package n’est pas connecté à Constellation, car nous l’avons lancé en local)
Fonctionnement de base
Un package est une application !
Il faut impérativement appeler la méthode “PackageHost.Start” au démarrage de l’application, c’est à dire dans la méthode “Main” autrement, ce n’est pas un package Constellation mais une simple application !
Lorsque vous appelez la méthode “PackageHost.Start” vous devez impérativement transférer les arguments (args) et indiquer la classe de votre package qui est dans notre exemple “Program”.
1 2 3 4 |
static void Main(string[] args) { PackageHost.Start<Program>(args); } |
La classe d’un package doit être une classe qui implémente l’interface “IPackage”. Cette interface définie trois méthodes :
-
OnStart qui sera invoqué lorsque le package a démarré
-
OnPreShutdown : invoqué lorsque le package va s’arrêter (à ce stade votre package est toujours connecté à Constellation, vous pouvez encore pusher des StateObjects, envoyer des messages, écrire des logs sur le hub, etc..)
-
OnShutdown : invoqué après le OnPreShutdown et après avoir fermé les connexions.
Pour vous éviter de devoir implémenter ces trois méthodes, votre classe peut hériter de la classe “PackageBase”. Cette classe abstraite implémente l’interface IPackage dans des méthodes virtuelles vides.
Libre à vous d’implémenter les méthodes que vous souhaitez !
Dans le template de projet créé ci-dessus, la classe “Program” hérite de “PackageBase” et redéfinie la méthode “OnStart” pour écrire un message de type “info” (PackageHost.WriteInfo) lorsque le package a démarré.
Ecrire des logs
Pour écrire des logs depuis un package Constellation vous disposez des méthodes :
- PackageHost.WriteDebug
- PackageHost.WriteInfo
- PackageHost.WriteWarn
- PackageHost.WriteError
Chacune de ces méthodes écrivent un message qui peut être formaté avec des arguments à la manière d’un “string.Format” :
1 |
PackageHost.WriteInfo("Je suis le package nommé {0} version {1}", PackageHost.PackageName, PackageHost.PackageVersion); |
Attention : bien respecter les index dans le format de votre message sous peine d’avoir une erreur.
Note : la méthode WriteDebug écrit seulement dans la console (mode debug local). Les logs de type “Debug” ne sont jamais envoyés dans la Constellation.
Accéder aux settings
Chaque package peut définir des paramètres de configuration définis au niveau du serveur Constellation. Cela vous permet de changer ces paramètres directement depuis la Constellation qui se chargera de redescendre ces paramètres sur vos packages.
Il y a deux types de settings :
- Les “Setting Value” : très simple il s’agit d’un couple clé/value à l’instant des <appSettings> d’une application .NET
- Les “Setting Content” : au lieu de définir la valeur d’un paramètre dans un attribut XML, on peut la définir dans un élément XML enfant permettant d’avoir des settings qui renferme du XML ou JSON
Voici par exemple des “SettingValues” déclarés dans notre configuration :
1 2 3 |
<setting key="MyBoolSetting" value="true" /> <setting key="MyStringSetting" value="This is a string" /> <setting key="MyIntSetting" value="123" /> |
Ces trois settings définissent la valeur dans l’attribut “value” (= SettingValue).
Pour récupérer la valeur du paramètre “MyStringSetting” dans votre code, utilisez la méthode “GetSettingValue” :
1 |
PackageHost.WriteInfo("My String = {0}", PackageHost.GetSettingValue("MyStringSetting")); |
La méthode “GetSettingValue” renvoie la valeur d’un setting de type “string” mais vous pouvez également caster la valeur depuis cette méthode en utilisant sa forme générique :
1 2 |
int myIntSetting = PackageHost.GetSettingValue<int>("MyIntSetting"); bool myBoolSetting = PackageHost.GetSettingValue<bool>("MyBoolSetting"); |
Si par contre vous avez un modèle de configuration plus compliqué qu’une série de clé/valeur vous pouvez utiliser les “Setting Contents” pour définir du XML ou JSON comme valeur de setting.
Par exemple la configuration de votre package peut définir deux autres settings, contenant du XML ou JSON de cette façon :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<setting key="MyXmlDocument"> <content> <note date="09-02-2016"> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me this weekend!</body> </note> </content> </setting> <setting key="MyJsonObject"> <content> <![CDATA[ { "Number": 123, "String" : "This is a test (local)", "Boolean": true } ]]> </content> </setting> |
Plusieurs méthodes pour récupérer ces settings :
- GetSettingValue : vous pouvez toujours récupérer le contenu brute de votre setting sous forme d’un string
- GetSettingAsJsonObject : dé-sérialise le contenu JSON de votre setting et vous retourne un objet dynamique
- GetSettingAsJsonObject<T> : dé-sérialise le contenu JSON de votre setting et le convertie dans un objet de votre type (T)
- GetSettingAsXmlDocument : dé-sérialise le contenu XML de votre setting et vous retourne un XmlDocument
- GetSettingAsConfigurationSection<TConfigurationSection> : dé-sérialise le contenu XML de votre setting sous forme d’un ConfigurationSection .NET
Par exemple, pour manipuler le setting XML on pourrait écrire :
1 2 |
var xml = PackageHost.GetSettingAsXmlDocument("MyXmlDocument"); PackageHost.WriteInfo("My XmlDocument Attribute = {0} , first node value = {1}", xml.ChildNodes[0].Attributes["date"].Value, xml.ChildNodes[0].FirstChild.InnerText); |
Autre exemple avec le setting JSON :
1 2 |
dynamic json = PackageHost.GetSettingAsJsonObject("MyJsonObject"); PackageHost.WriteInfo("My JsonObject String={0}, Int={1}, Boolean={2}", json.String, json.Number, json.Boolean); |
Les settings d’un package sont déclarés au niveau du serveur dans la déclaration du package et/ou dans le fichier App.config.
Tous les settings doivent être déclarés dans le manifeste du package (fichier PackageInfo.xml).
Retrouvez plus d’information sur les settings dans cet article.
Publier des StateObjects
Pour publier (Push) un StateObject dans Constellation vous devez invoquer la méthode “PackageHost.PushStateObject” en précisant obligatoirement le nom du StateObject et sa valeur.
Par exemple, vous pouvez publié n’importe quel type de base :
1 2 3 4 |
PackageHost.PushStateObject("MyString", "OK"); PackageHost.PushStateObject("MyNumber", 123); PackageHost.PushStateObject("MyDecimal", 123.12); PackageHost.PushStateObject("MyBoolean", true); |
Pouvez également publié des objets anonymes :
1 |
PackageHost.PushStateObject("AnonymousObject", new { String = "test", Number = 123 }); |
Ou encore avec des types plus complexes :
1 |
PackageHost.PushStateObject<MyCustomObject>("MyObject", new MyCustomObject() { String = "test", Number = 123 }); |
Vous avez également la possibilité de définir des paramètres optionnels comme les métadonnées de votre StateObject ou sa durée de vie.
Par exemple, le StateObject “ShortLife” a une durée de vie de 20 secondes après sa publication. Au delà il sera marqué comme expiré.
1 |
PackageHost.PushStateObject("ShortLife", "Expire in 20 secs !!!", lifetime: 20); |
Ici, on publie un StateObject “Salon” en lui associé les metadatas “Id” et “Zone”.
1 |
PackageHost.PushStateObject("Salon", monObjetZoneSalon, metadatas: new Dictionary<string, object> { { "Id", 42 }, { "Zone", "Salon" } }); |
Sur les objets personnalisés il est recommande de décorer les classes de l’attribut [StateObject] si vous avez possibilité de modifier le code de la classe. Autrement, sur votre classe IPackage, ajoutez l’attribut [StateObjectKnownTypes] en définissant tous les types de StateObjects que vous serez amener à publier. Cela permet de décrire ces types dans la Constellation pour l’auto-description (utilisez entre autre par les générateurs de code).
Pour plus d’information sur les StateObjects dans l’API .NET cliquez ici.
Tester son package dans sa Constellation
Pour tester nous allons créer un package qui push à intervalle régulier un StateObject.
Le code de notre Package sera :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public class Program : PackageBase { static void Main(string[] args) { PackageHost.Start<Program>(args); } public override void OnStart() { PackageHost.WriteInfo("Package starting - IsRunning: {0} - IsConnected: {1}", PackageHost.IsRunning, PackageHost.IsConnected); PackageHost.WriteInfo("Je suis le package nommé {0} version {1}", PackageHost.PackageName, PackageHost.PackageVersion); while (PackageHost.IsRunning) { PackageHost.WriteInfo("Je push un long !"); PackageHost.PushStateObject("DemoLong", DateTime.Now.Ticks); Thread.Sleep(PackageHost.GetSettingValue<int>("Interval")); } } } |
Notre application console démarre bien le package au démarrage (Main) où le package est notre classe Program qui hérite de PackageBase (donc c’est un IPackage).
Au démarrage on écrit deux logs de type information qui indique notamment le nom du package, sa version, si il est démarré (IsRunning) et si il est connecté (IsConnected).
Ensuite on crée une boucle qui tournera tant que le package est démarré. A chaque itération on écrit un log, publie un StateObject avant de mettre le thread en pause avant la prochaine itération.
Le temps de pause est un setting de type “Int” que l’on a nommé “Interval”.
L’utilisateur pourra le configurer dans la configuration du package sur le serveur, mais pour être sûr d’avoir une valeur par défaut nous allons déclarer ce setting ainsi que sa valeur par default dans son manifest.
Editez le fichier PackageInfo.xml pour ajouter :
1 |
<Setting name="Interval" type="Int32" defaultValue="5000" description="Interval en millisecondes" /> |
Ainsi même si le setting n’est pas déclaré sur le serveur ni dans le App.config local, cette valeur sera par défaut égale à 5 secondes.
Vous pouvez démarrer le projet en mode debug (“F5” ou bouton “Start”) mais bien entendu il ne sera pas connecté à Constellation.
Pour débugger dans Constellation, vous trouverez une icone dans la toolbar (en en pressant Ctrl+Alt+F8) :
Vous pouvez également cliquez droit sur votre projet et dans le menu Constellation sélectionnez “Debug On Constellation” :
Si vous n’avez pas encore configuré la Constellation utilisée pour le débogage, vous devriez voir une alerte vous invitant à configurer vos accès :
Cette fois ci, votre package tourne bien en étant connecté à votre Constellation :
Lancez maintenant votre Console Constellation, vous verrez en temps réel les logs de votre package.
Sur le StateObject Explorer, vous verrez également le StateObject “DemoLong” publié par le package “MonPremierPackage”.
Notez que la sentinelle qui héberge le package est une sentinelle virtuelle nommée “Developer”.
Vous pouvez cliquer sur “View” pour voir toutes les informations à propos de ce StateObject.
Pour finir, cliquez sur “Subscribe” pour vous abonner aux mises à jour.
Publier son package dans Constellation
Nous voulons maintenant publier ce package et le déployer sur une des sentinelles de notre Constellation.
Toujours dans la toolbar “Constellation”, cliquez sur “Publish Constellation package” :
Ou depuis le menu contextuel de votre projet, sélectionnez “Publish Constellation package” :
Vous pouvez soit le publier en local puis l’uploader manuellement via la Console par exemple, soit le publier directement dans votre Constellation.
Pour cela, sélectionnez “Upload on Constellation Server”.
Sélectionnez ensuite l’adresse de votre Constellation et cliquez sur “Publish”.
Un message vous informera de la réussite de la publication. Dans le panneau “Ouput” de Visual Studio vous retrouvez également le détail de la publication :
Depuis la Console, sur la page “Package Repository” vous pourrez apercevoir votre package fraichement publié :
Pour le déployer, vous devez éditer la configuration de votre Constellation pour ajouter le package à une (ou plusieurs) sentinelle. Vous pouvez également redéfinir le setting “Interval” que nous exploitations dans notre package (bien que nous avons défini une valeur par défaut).
1 2 3 4 5 |
<package name="MonPremierPackage" enable="true"> <settings> <setting key="Interval" value="2000" /> </settings> </package> |
Vous pouvez éditer la configuration du serveur Constellation directement depuis Visual Studio en cloquant sur “Edit Constellation Server configuration” (depuis la toolbar ou via le menu contextuel).
La configuration sera automatiquement téléchargée du serveur et ouverte dans Visual Studio :
L’avantage est de pouvoir profiter de la validation du schéma XML et de l’IntelliSense de Visual Studio :
Dès que vous enregistrerez votre configuration, Visual Studio détectera les modifications et vous proposera d’uploader et de recharger la nouvelle configuration sur votre serveur Constellation :
Vous pouvez aussi éditer la configuration de votre Constellation depuis la Console. Après avoir ajouter votre package, cliquez sur “Save & Deploy” (pour informer les sentinelles des nouveaux packages) :
Vous pourrez alors voir dans les logs que le package est automatiquement téléchargé et déployé sur sa sentinelle et commence à pusher des StateObject toutes les 2 secondes comme nous l’avons indiqué dans sa configuration :
Sur la page “Packages” vous pouvez maintenant contrôler votre package, l’arrêter, le redémarrer ou le recharger (= déploiement d’une nouvelle version).
Next steps
-
Les Settings : paramètres de configuration de vos packages
-
Exposer vos méthodes dans Constellation grâce aux MessageCallbacks
-
Accéder au hub de contrôle depuis un package C# avec le ControlManager
-
Créer des Packages UI en Winform ou WPF
Démarrez la discussion sur le forum Constellation