Sommaire
Chaque package peut définir des paramètres de configuration centralisés au niveau du serveur Constellation.
L’ensemble des paramètres des configurations de vos différents packages, virtuels ou non, sont donc centralisés dans un fichier unique. Une modification de valeur est automatiquement mis à jour sur le package cible.
Il y a deux types de settings :
- Le “Setting Value” : il s’agit d’un couple clé/valeur défini dans des attributs XML à l’instar des <appSettings> d’une application .NET
- Le “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 renfermant du XML ou JSON
Les Settings Values
Voici par exemple des “SettingValues” déclarés dans la configuration d’un package :
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 C#, vous pouvez utiliser la méthode “GetSettingValue” :
1 |
PackageHost.WriteInfo("My String = {0}", PackageHost.GetSettingValue("MyStringSetting")); |
La méthode “GetSettingValue” vous retourne par défaut la valeur d’un setting en “string” mais vous pouvez également convertir cette valeur en précisant le type attendu :
1 2 |
int myIntSetting = PackageHost.GetSettingValue<int>("MyIntSetting"); bool myBoolSetting = PackageHost.GetSettingValue<bool>("MyBoolSetting"); |
Les Settings Contents
Si 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, l’un contenant du XML et l’autre du 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> |
Voici les méthodes pour récupérer ces settings :
- GetSettingValue : récupère 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 converti 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); |
TryGetSettings
Notez que toutes ces méthodes citées ci-dessus ont un équivalent de type “TryGetSettingXXX” :
- TryGetSettingAsConfigurationSection<TConfigurationSection>
- TryGetSettingAsJsonObject
- TryGetSettingAsJsonObject<T>
- TryGetSettingAsXmlDocument
- TryGetSettingValue<T>
Ces méthodes placent le résultat dans un paramètre de sortie (“out”) et vous retourne un booléen indiquant si l’opération est réussite ou non.
Par exemple :
1 2 3 4 5 6 7 8 9 |
int monParametre = 0; if (PackageHost.TryGetSettingValue<int>("MyIntSetting", out monParametre)) { PackageHost.WriteInfo("Lecture de 'MyIntSetting' en int OK. Valeur = {0}", monParametre); } else { PackageHost.WriteError("Impossible de récupérer le setting 'MyIntSetting' en int"); } |
Déclarer les settings dans le Package Manifest
Tous les settings devraient être déclarés dans le manifeste du package (fichier PackageInfo.xml).
La déclaration des settings dans le manifeste n’a pas impact dans le fonctionnement du package mais il permet de décrire la configuration du package pour que des outils tel que la Console puisse proposer une interface graphique de configuration pour chaque package. Il est donc vivement recommandé de décrire les settings de ses packages. De plus il est possible de définir des valeurs par défaut dans le manifeste.
Chaque setting déclaré dans le manifeste doit obligatoirement comporter les attributs suivants :
- Name : le nom (clé) du setting
- Type : le type du setting
Le type peut être :
- Boolean : un booléen (true/false)
- Double : un double
- String : un chaine de caractère
- Int32 : un entier (32 bits)
- Int64 : un long (64 bits)
- ConfigurationSection : un section de configuration .NET
- DateTime : un DateTime
- TimeSpan : une durée
- XmlDocument : un document XML
- JsonObject : un objet JSON (objet ou tableau)
Ensuite vous pouvez définir d’autre attribut pour décrire vos settings :
- “isRequired“ : indique si le setting est obligatoire ou non (par défaut “false”)
- “description” : la description du setting (texte qui sera affiché à l’utilisateur)
- “defaultValue” : la valeur par défaut du setting si le setting n’est pas déclaré (ni sur le serveur, ni dans le fichier local App.config et seulement si le setting n’est pas obligatoire)
- “schemaXSD” : indique le nom du fichier du schéma XSD (chemin relatif au package) que la valeur XML doit valider (seulement pour les settings de type XmlDocument ou ConfigurationSection)
- “ignoreLocalValue” : si “true” alors la valeur définie dans le fichier local App.config est ignorée
- “ignoreDefaultValue” : si “true” alors la valeur par défaut définie dans le manifeste est ignorée
Pour les settings XmlDocument, ConfigurationSection et JsonObject vous pouvez également ajouter une sous-section <defaultContent> sur vos settings pour définir le contenu par défaut.
Pour plus d’information, veuillez lire l’article sur le Package Manifest.
Déclarez des settings dans votre configuration locale
Les settings d’un package sont déclarés au niveau du serveur Constellation mais vous pouvez également les déclarer dans le fichier App.config de votre package. Cela est très utile pendant la phase de développement.
Pour définir les settings dans le fichier App.config vous devez utiliser la section “constellationSettings ». Le schéma et le fonctionnement sont exactement les mêmes que pour la configuration définie sur le serveur Constellation.
Par exemple, dans le fichier App.config de votre package, on peut écrire :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<constellationSettings xmlns="http://schemas.myconstellation.io/Constellation/1.8/ConstellationSettings"> <settings> <setting key="MyStringSetting" value="This is a string" /> <setting key="MyBoolSetting" value="true" /> <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> </settings> </constellationSettings> |
La structure est présente par défaut dans les projets Constellation créés depuis le SDK Constellation pour Visual Studio.
Si un même setting (= même clé) est déclaré à la fois sur le serveur Constellation et dans le fichier local, c’est toujours la valeur définie sur le serveur qui gagne (voir ci-dessous).
Notez également que si un setting est déclaré comme obligatoire dans le manifeste, il est automatiquement supprimé du fichier App.config lorsque vous publiez ce package depuis Visual Studio (que ce soit en local ou sur un serveur). Vous pouvez donc mettre vos “credentials” ou autre information personnel pour vos développements tout en sachant qu’ils seront supprimés lorsque vous publierez votre package.
Résolution des settings
Par défaut, la valeur d’un setting est en priorité récupérée depuis la configuration du package défini sur le serveur Constellation.
Si le setting n’existe pas sur le serveur (et qu’il n’est pas déclaré comme obligatoire dans le manifeste du package), le package va chercher la valeur du setting dans le fichier de configuration local App.config.
Si le fichier local App.config ne défini pas non plus de valeur pour ce setting ou que le manifeste demande d’ignorer cette valeur (ignoreLocalValue à true), le package va alors chercher la valeur par défaut de ce setting dans le manifeste (attribut “defaultValue” ou section”defaultContent”).
Si le manifeste du package ne défini pas de valeur par défaut pour ce setting, ou que cette valeur doit être ignorée (ignoreDefaultValue à true), la valeur du setting sera nulle.
Le processus de résolution des settings peut se résumé ainsi :
Prenons un exemple pour bien comprendre. Si votre package est déclaré sur le serveur de cette façon :
1 2 3 4 5 |
<package name="MonPackage" enable="true"> <settings> <setting key="MyStringSetting" value="Valeur du serveur" /> </settings> </package> |
Et que le package contient dans son fichier local App.config la section suivante :
1 2 3 4 5 6 |
<constellationSettings xmlns="http://schemas.myconstellation.io/Constellation/1.8/ConstellationSettings"> <settings> <setting key="MyStringSetting" value="Valeur locale" /> <setting key="MyIntSetting" value="42" /> </settings> </constellationSettings> |
Avec dans son manifeste, la déclaration suivante :
1 2 3 4 |
<Settings> <Setting name="MyStringSetting" type="String" description="This is a String setting" /> <Setting name="MyIntSetting" type="Int32" isRequired="false" ignoreLocalValue="true" defaultValue="1234" /> </Settings> |
Imaginez maintenant le code C# suivant :
1 2 |
PackageHost.WriteInfo("My String = {0}", PackageHost.GetSettingValue("MyStringSetting")); PackageHost.WriteInfo("My Int = {0}", PackageHost.GetSettingValue("MyIntSetting")); |
Si vous lancez le package en debug depuis Visual Studio :
- My String = “Valeur locale”
- My Int = 123
Les valeurs sont simplement lues depuis le fichier de configuration locale. Si maintenant vous supprimez le setting dans votre App.config, la valeur de MyIntSetting sera 1234, c’est à dire la valeur par défaut du manifest.
Maintenant si vous déployez votre package dans votre Constellation :
- My String = “Valeur du serveur”
- My Int = 1234
My String est bien récupéré depuis la configuration du serveur (car prioritaire), cependant “MyIntSetting” n’étant pas déclaré sur le serveur, le package va tenter de lire cette valeur depuis la configuration locale (123) mais le manifeste demande à ignorer la valeur locale (ignoreLocalValue= »true » dans le manifeste) ce qui l’amène à récupérer la valeur par défaut (defaultValue) déclaré dans le manifeste du package. Donc MyIntSetting = 1234.
Note sur le “ignoreDefaultValue”
On peut se demander quel est l’intérêt de définir une valeur par défaut tout demandant de l’ignorer (ignoreDefaultValue = true).
En fait la valeur par défaut du manifeste peut être considérée comme un “exemple”. La defaultValue ou defaultContent est affiché à titre d’exemple à l’utilisateur lors de la configuration de son package dans la Console Constellation. Cela est surtout fort utile pour les “Setting Contents”, car ça renseigne l’utilisateur la structure du XML ou du JSON du setting.
Mais une valeur d’ “exemple” ne doit pas être chargée ! De ce fait on déclare un setting avec une defaultValue/defaultContent pour l’exemple et on demande à ne jamais tenir compte de cette valeur en l’ignorant (ignoreDefaultValue = true).
Si on veut une valeur “par défaut”, on utilisera le fichier local App.config.
En clair, on peut voir les choses ainsi :
- Valeur déclarée dans la configuration du package au niveau du serveur Constellation = configuration de l’utilisateur
- Valeur déclarée dans la configuration locale du package (App.config) = configuration pour le développement ou valeur par défaut
- Valeur déclarée dans le manifeste du package (PackagInfo.xml) = exemple de configuration ou valeur par défaut
Mise à jour dynamique
Les settings d’un package sont récupérés du serveur Constellation au démarrage du package. Il est également possible de “pusher” les settings d’un package lorsque le package est en fonctionnement.
Il y a trois façons de “pusher” les settings sur un package :
- Lors du rechargement de la configuration Constellation sur le serveur
- Lors d’un “UpdateSettings” sur un package en particulier via le hub contrôle
- A la demande d’un package via la méthode “RequestSettings”
Le hub de contrôle (control hub) expose une méthode “reloadServerConfiguration” permettant de recharger la configuration de la Constellation au niveau du serveur. Cette méthode prend en paramètre un booléen (optionnel) indiquant si il faut ou non déployer la configuration après son rechargement sur le serveur. Par défaut ce paramètre est à “false” (la configuration est seulement rechargée).
Lorsque la configuration est déployée, le serveur Constellation informe toutes les sentinelles et tous les packages que la configuration a changé. Chaque package recevra la valeurs des settings déclarées dans la nouvelle configuration et chaque sentinelle se conformera à sa configuration (arrêt des packages supprimés et déploiement/démarrage des packages ajoutés).
Il est possible de lancer cette action depuis la Console Constellation (soit depuis la page “Packages” ou soit depuis la page “Configuration Editor« ).
L’autre possibilité, toujours sur le hub de contrôle, avec une méthode “updateSettings” permettant de pusher les settings du serveur vers un package en particulier. Vous retrouverez également cette action depuis la Console Constellation :
Enfin, le package lui-même peut faire la demande au serveur de lui renvoyer ses settings par la méthode suivante :
1 |
PackageHost.RequestSettings(); |
Dans tous les cas, le dictionnaire des settings de votre package (propriété PackageHost.Settings) sera mis à jour de façon de transparent (en tenant compte du processus de résolution des settings décrit ci-dessus).
Ainsi, lorsque vous appelez les méthodes GetSettingXXXX, elles vous retourneront toujours les dernières valeurs des settings. C’est pourquoi il est conseillé de ne jamais mettre en cache les valeurs des settings et de toujours invoquer les méthodes GetSettingsXXX pour tenir compte des modifications en temps réel.
Vous avez également la possibilité de vous abonnez à l’événement “PackageHost.SettingsUpdated” pour être informé de ces mises à jour et agir en conséquence :
1 2 3 4 5 |
PackageHost.SettingsUpdated += (s, e) => { PackageHost.WriteInfo("Mise à jours des settings"); PackageHost.WriteInfo("Il y a {0} setting(s)", PackageHost.Settings.Count); }; |
Les groupes de Settings
Vous pouvez grouper des settings (Content ou Value) dans des groupes au niveau du serveur et importer ces groupes dans les settings de vos packages ou dans d’autres groupes.
Par exemple, créons un groupe pour “HWMonitorSettings” qui contient le setting “Interval” :
1 2 3 4 5 6 7 |
<settingsGroups> <group name="HWMonitorSettings"> <settings> <setting key="Interval" value="500" /> </settings> </group> </settingsGroups> |
Ainsi pour chaque instance du package “HWMonitor”, vous pouvez importer le groupe “HWMonitorSettings” afin de centraliser la configuration de ce package :
1 2 3 4 5 6 7 |
<package name="HWMonitor"> <settings> <import> <settingGroup groupName="HWMonitorSettings" /> </import> </settings> </package> |
Vous pouvez importer des groupes dans des groupes sans limite.
C’est toujours la valeur du setting la plus proche du package qui gagne (surcharge).
Bien entendu, vous pouvez créer autant de groupe que vous voulez et chaque groupe peut contenir des SettingValues ou des SettingContents :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
<settingsGroups> <group name="test"> <settings> <setting key="Demo1" value="Seb" /> <setting key="Demo2" value="123" /> </settings> </group> <group name="test2"> <settings> <import> <settingGroup groupName="common" /> </import> <setting key="Demo1" value="Sebastien" /> <setting key="Demo2" value="2015" /> </settings> </group> <group name="common"> <settings> <setting key="MyStringSetting" value="This is a string" /> <setting key="MyBoolSetting" value="true" /> <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> </settings> </group> </settingsGroups> |
Pour bien comprendre, imaginez le package suivant :
1 2 3 4 5 6 7 8 9 10 |
<package name="DemoPackage"> <settings> <import> <settingGroup groupName="test" /> <settingGroup groupName="test2" /> </import> <setting key="numberTest" value="42" /> <setting key="Demo1" value="It’me" /> </settings> </package> |
Ici cette instance du package “DemoPackage” contient 7 settings (sans prendre en compte les settings déclarés dans le fichier local et le manifeste) :
- numberTest = 42 (défini dans les settings du package)
- Demo1 = “It’s me” (défini dans les settings du package, cette valeur écrase celle des groupes importés)
- Demo2 = 2015 (défini par le groupe “test2”. Cette valeur écrase la valeur du groupe “test”, car le groupe “test2” est importé APRES le groupe “test”)
- MyStringSetting, MyBoolSetting, MyXmlDocument et MyJsonObject définis par le groupe “common” (groupe importé dans le groupe “test2” lui même importé sur le package “DemoPackage”).
Démarrez la discussion sur le forum Constellation