Bien que vous puissiez appeler un délégué qui sera géré par un AppDomain distinct, j'ai personnellement toujours utilisé la méthode 'CreateInstanceAndUnwrap' qui crée un objet dans le domaine de l'application étrangère et lui renvoie un proxy.
Pour que cela fonctionne votre objet doit hériter de MarshalByRefObject.
est un exemple:
public interface IRuntime
{
bool Run(RuntimesetupInfo setupInfo);
}
// The runtime class derives from MarshalByRefObject, so that a proxy can be returned
// across an AppDomain boundary.
public class Runtime : MarshalByRefObject, IRuntime
{
public bool Run(RuntimeSetupInfo setupInfo)
{
// your code here
}
}
// Sample code follows here to create the appdomain, set startup params
// for the appdomain, create an object in it, and execute a method
try
{
// Construct and initialize settings for a second AppDomain.
AppDomainSetup domainSetup = new AppDomainSetup()
{
ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
LoaderOptimization = LoaderOptimization.MultiDomainHost
};
// Create the child AppDomain used for the service tool at runtime.
childDomain = AppDomain.CreateDomain(
"Your Child AppDomain", null, domainSetup);
// Create an instance of the runtime in the second AppDomain.
// A proxy to the object is returned.
IRuntime runtime = (IRuntime)childDomain.CreateInstanceAndUnwrap(
typeof(Runtime).Assembly.FullName, typeof(Runtime).FullName);
// start the runtime. call will marshal into the child runtime appdomain
return runtime.Run(setupInfo);
}
finally
{
// runtime has exited, finish off by unloading the runtime appdomain
if(childDomain != null) AppDomain.Unload(childDomain);
}
Dans l'exemple ci-dessus, il est codé pour exécuter un passage de la méthode « Exécuter » dans certaines informations de configuration, et l'achèvement de la méthode Run est déterminé à indiquer que tout le code dans l'enfant AppDomain a terminé son exécution, nous avons donc un bloc finally qui s'assure que l'AppDomain est déchargé.
Vous voudrez peut-être faire attention aux types que vous placez dans quels assemblages - vous pouvez utiliser une interface et la placer dans un assemblage séparé à la fois de l'appelant (notre code qui configure l'appdomain et des appels dans it) et l'implémenteur (la classe Runtime) dépendent de. Cet IIRC permet au parent AppDomain de charger uniquement l'assembly qui contient l'interface, tandis que l'appdomain enfant chargera à la fois l'assembly qui contient Runtime et sa dépendance (l'assembly IRuntime). Tous les types définis par l'utilisateur qui sont utilisés par l'interface IRuntime (par exemple, notre classe RuntimeSetupInfo) doivent généralement être placés dans le même assembly que IRuntime. Veillez également à définir ces types définis par l'utilisateur: s'il s'agit d'objets de transfert de données (comme RuntimeSetupInfo l'est probablement), vous devez probablement les marquer avec l'attribut [serializable] - afin qu'une copie de l'objet soit transmise (sérialisée l'appdomain parent à l'enfant). Vous voulez éviter que les appels soient regroupés d'un domaine à l'autre, car c'est plutôt lent. Passer des DTO par valeur (sérialisation) signifie que l'accès aux valeurs sur le DTO n'entraîne pas d'appel inter-appartement (puisque l'appdomain enfant a sa propre copie de l'original). Bien sûr, cela signifie également que les modifications de valeur ne sont pas répercutées dans le DTO d'origine du domaine d'application parent. Comme cela est codé dans l'exemple, le domaine d'application parent finira par charger les assemblys IRuntime et Runtime mais c'est parce que dans l'appel à CreateInstanceAndUnwrap j'utilise typeof (Runtime) pour obtenir le nom de l'assembly et le type complet prénom. Vous pouvez à la place coder en dur ou récupérer ces chaînes à partir d'un fichier - ce qui découplerait la dépendance.
Il existe également une méthode sur AppDomain nommée 'DoCallBack' qui semble permettre d'appeler un délégué dans un AppDomain étranger. Toutefois, le type de délégué qu'il prend est de type 'CrossAppDomainDelegate'. La définition de ce qui est:
public delegate void CrossAppDomainDelegate()
Ainsi, il ne vous permettra pas de transmettre des données. Et, puisque je ne l'ai jamais utilisé, je ne peux pas vous dire s'il y a des pièges particuliers.
Aussi, je recommande de regarder dans la LoaderOptimization propriété. Ce que vous définissez, peut avoir un impact significatif sur les performances, car certains paramètres de cette propriété forcent le nouveau domaine à charger des copies séparées de tous les assemblages (et JIT, etc.) même si (IIRC) l'assembly est dans le GAC (c'est-à-dire que cela inclut les assemblages CLR). Cela peut vous donner des performances horribles si vous utilisez un grand nombre d'assemblys à partir de votre appdomain enfant. Par exemple, j'ai utilisé WPF à partir de domaines d'application enfants, ce qui a causé d'énormes retards de démarrage pour mon application jusqu'à ce que j'aie mis en place une politique de chargement plus appropriée.
La méthode CreateInstanceAndUnwrap lance une erreur disant qu'il ne peut pas trouver l'assembly comme spécifié par (typeof (Runtime) .Assembly.FullName) . Cela fonctionne sur un serveur web pour moi et le format du nom complet est "myhostdll, Version = 1.0.0.0, Culture = neutre, PublicKeyToken = null". – Triynko
@Triynko, lors de la création de la nouvelle configuration AppDomain, essayez de spécifier le même dossier bin que le domaine maître, ou du moins, utilisez un emplacement où le nouveau domaine peut obtenir les assemblys. –