Bonjour à tous. Je connais assez peu les AppDomains et je me suis retrouvé aujourd'hui face à plusieurs questions restées sans réponses malgré des heures passées sur Google et MSDN. Toute aide serait donc la bienvenue.


Problème
Je développe une biblio qui doit à un moment générer et charger des assemblys au sein d'un AppDomain isolé (sandbox/bac à sable). Un singleton est créé côté bac à sable, un délégué invoque une méthode du Singleton côté parent.

[Parent] void func(int) possède un proxy vers [Sandbox] Singleton.Instance.Run(int)

Jusque là, tout va bien. Mais ces bacs à sables doivent être détruits (AppDomain.Unload) par la suite, de façon non-déterministe, lorsque les références aux délégués générés ont été perdues par le parent. Et les MBRO associés doivent être maintenus en vie avant cela.


Ce que je crois savoir...
De ce que j'ai cru comprendre, dans le cas d'AppDomains confinés au sein du même processus (même machine), les règles sont les suivantes. Pouvez infirmer ou confirmer s'il vous plaît ?
  1. Le MBRO (MarshalByRefObject) côté sandbox et son proxy côté parent ont une durée de vie totalement indépendante l'une de l'autre.
  2. Le MBRO est détruit automatiquement une fois son bail expiré (le ILease généré par InitializeLifeTimeService), même si le proxy existe toujours côté parent.
  3. InitializeLifeTimeService est invoqué automatiquement (après la création de l'objet ?), pas besoin de l'appeler explicitement. Mais c'est nécessaire si l'on veut change le bail (ILease) renvoyé par défaut.
  4. Le proxy côté parent est soumis aux règles normales du ramasse-miettes : il est détruit lorsque toutes les références vers lui ont été perdues, même si le MBRO existe toujours côté bac à sable.
  5. Un AppDomain n'est jamais automatiquement détruit (sauf fin du processus, surcharge mémoire, etc), il doit donc l'être explicitement via AppDomain.Unload.
  6. Puis-je utiliser le bail renvoyé par AppDomain.InitializeLifeTimeService() en lieu et place de AppDomain.Unload ? Et est-ce conseillé ?


Première solution foireuse
Pour chaque AppDomain, un objet AppDomainTracker garde des WeakReference sur tous les délégués/proxies créés. Une fois par minute, un thread se réveille et vérifie si toutes les références sont mortes (les proxies associés ne sont plus référencés par "parent"). Si c'est le cas, AppDomain.Unload est appelé.

Ça ne gardait par les MBRO en vie mais ça permettait de nettoyer l'AppDomain une fois devenu inutile. Problème : l'utilisation de AppDomain.Unload dans un autre thread que le principal a des conséquences étranges. Au pire l'application est bloquée (pas de pb de deadlock ou autre, ça bloque ailleurs que dans mon code), au mieux elle ne l'est pas mais le thread associé aux AppDomainTrackers n'est jamais terminé (alors qu'il n'est pas bloqué et fonctionne normalement, je peux continuer à le déboguer, il n'a simplement jamais reçu de ThreadAbortException et continue à être réveillé toutes les 60s).


Solution envisagée
Ayant appris à me méfier de AppDomain.Unload depuis un thread perso et venant à comprendre que je devais aussi veiller à garder les MBRO en vie, je me suis dit que le mieux était de faire de AppDomainTracker un sponsor (ISponsor) de baux (leases) : chaque fois qu'un MBRO demande le renouvellement de son partenariat (sponsorship), les WeakReferences sont vérifiées et l'AppDomain détruit si toutes les références sont mortes. J'ignore sur quel thread (le GC ?) cela se fera exactement mais mon petit doigt me dit que je n'aurais pas les mêmes problèmes qu'auparavant.

N'étant pas sûr de bien comprendre le fonctionnement du bouzin, je me tourne vers vous. Cela peut-il fonctionner ? Ou suis-je à côté de la plaque ? Merci d'avance à ceux qui voudront bien me donner un peu de leur temps.