Hello,
Oui à lire votre code ce WE j’étais étonné de voir que ça ne marche pas ! En effet avec le bon nom de SO ça marche mieux
Pour ce qui est de l’expiration, non pas d’événement, il y a juste une propriété IsExpired sur l’objet StateObject qui indique si le SO a expiré ou non en comparant la différence entre la date courante et propriété « LastUpdate » avec le « Lifetime » défini sur le SO (exprimé en seconde).
Vous pouvez vous même ajouter une classe qui s’occuperait de surveiller l’expiration de vos SO et de lever un event. « surveiller » veut dire, créer un thread en background qui contrôle régulièrement si la propriété « IsExpired » change.
Imaginez la classe suivante :
public class StateObjectCollectionWatcher : StateObjectCollectionNotifier
{
public event EventHandler<StateObjectUpdatedEventArgs> StateObjectExpired;
public StateObjectCollectionWatcher() : base()
{
Task.Factory.StartNew(async () =>
{
while (PackageHost.IsRunning)
{
try
{
foreach (StateObjectNotifier so in this)
{
if (so.Value.IsExpired && !so.Value.Metadatas.ContainsKey("__Watcher_SeenExpired"))
{
so.Value.Metadatas.Add("__Watcher_SeenExpired", null);
this.StateObjectExpired?.Invoke(this, new StateObjectUpdatedEventArgs() { StateObject = so.Value });
}
}
}
catch { }
await Task.Delay(1000);
}
});
}
}
Ici on crée une classe StateObjectCollectionWatcher qui hérite de la classe StateObjectCollectionNotifier que nous avons vu rapidement en cours (pour plus d’info voir ici), c’est à dire que notre classe « StateObjectCollectionWatcher » est une collection de StateObjectNotifier.
Sur cette classe nous rajoutons un événement « StateObjectExpired » qui sera levé quand un SO de la collection expirera.
Pour le savoir, nous créons une tache en background via le Task.Factory dans le constructeur de notre classe. Cette tache tourne tant que le package est démarré (PackageHost.IsRunning) en marquant une pause d’une seconde à chaque itération. Cette boucle parcourt tous les SO qu’elle contient pour savoir qui a expiré. Quand elle en trouve, elle vient lever l’événement « StateObjectExpired » en passant dans les EventArgs l’instance du SO qui a expiré.
Pour finir, on ajoute dans les metadatas du SO, une clé que j’ai nommé ici « __Watcher_SeenExpired » de façon à éviter que l’événement « StateObjectExpired » soit levé en boucle. En gros, on tag le SO pour dire qu’on « sait qu’il a expiré »
De ce fait, dans votre package, vous pouvez tout simplement créer une instance de notre « StateObjectCollectionWatcher » et vous abonnez à l’événement "StateObjectExpired " dans lequel vous récupérez dans les EventArgs (la variable ‹ e ›), le SO venant d’expirer :
StateObjectCollectionWatcher watcher = new StateObjectCollectionWatcher();
watcher.StateObjectExpired += (s, e) =>
{
PackageHost.WriteWarn($"Le StateObject '{e.StateObject.Name}' produit par {e.StateObject.SentinelName}/{e.StateObject.PackageName} vient juste d'expirer !!!");
};
Dernière étape, c’est bien sur d’alimenter notre « watcher ». Pour cela, il suffit juste de s’abonnez au « StateObjectUpdated » du PackageHost pour ajouter les SO réceptionnés dans notre collection « watcher » :
PackageHost.StateObjectUpdated += (s, e) =>
{
watcher.AddOrUpdate(e.StateObject);
};
Ainsi à chaque SO reçu, on l’ajoute (ou met à jour) dans notre collection « watcher » qui surveille l’expiration du SO et si expiré on lève l’event !
Notez bien que si le SO expire, on ajoute un tag dans les métadatas ! Ce tag est présent seulement dans les metadatas de l’objet StateObject côté .NET ! Cette métadata n’est pas remontée dans la Constellation (les SO sont en read-only à moins de faire un PushStateObject). Si le SO expiré est à nouveau mis à jour dans votre Constellation par le package d’origine, il sera donc reçu dans le PackageHost.StateObjectUpdated qui le mettra à jour dans la collection « watcher ». Donc la valeur du SO et ses métadatas seront bien écrasés par le nouveau SO, ainsi si il est amené à expiré de nouveau, l’événement sera bien levé
Petite précision et pas des moindres car vous risquez d’être déçu La méthode « AddOrUpdate » de la classe « StateObjectCollectionNotifier » est une méthode « internal » donc elle vous est inaccessible actuellement ! Dans la version de la libraire 16166, elle est publique !
La mise à jour sera disponbile sur Nuget dès demain. Il faudra juste, dans le gestionnaire Nuget de votre package, cliquez sur le bouton « Update » ! Je posterai un message ici dès que l’update sera dispo
Bonne soirée,