Existe-t-il une bonne raison pour laquelle Microsoft a choisi de ne pas prendre en charge AppDomains dans .NET Core?
Les AppDomains sont particulièrement utiles lors de la création d'applications serveur de longue durée, dans lesquelles nous souhaitons peut-être mettre à jour les assemblys chargés par le serveur de manière gracieuse, sans arrêter le serveur.
Sans AppDomains, comment allons-nous remplacer nos assemblys dans un processus serveur de longue durée?
AppDomains nous fournit également un moyen d'isoler différentes parties du code serveur. Par exemple, un serveur Websocket personnalisé peut avoir un code de socket dans le domaine d'application principal, tandis que nos services s'exécutent dans le domaine d'application secondaire.
Sans AppDomains, le scénario ci-dessus n'est pas possible.
Je peux voir un argument qui pourrait parler de l'utilisation du concept de VM de Cloud pour gérer les changements d'assemblage et de ne pas avoir à supporter la surcharge d'AppDomains. Mais est-ce ce que pense ou dit Microsoft? ou ont-ils une raison spécifique et des alternatives pour les scénarios ci-dessus?
Réponses:
Le but du sous-ensemble .NETCore était de conserver une petite installation .NET . Et facile à mettre en communication. C'est pourquoi vous pouvez, par exemple, exécuter une application Silverlight sur Windows et OSX et ne pas attendre très longtemps lorsque vous visitez la page Web. Le téléchargement et l'installation du runtime et du framework complets ne prennent que quelques secondes, à peu près.
Le garder petit nécessite inévitablement de couper des fonctionnalités. La communication à distance était très élevée sur cette liste, c'est assez cher. Sinon bien caché, mais vous pouvez par exemple voir que les délégués n'ont plus de méthode BeginInvoke () fonctionnelle. Ce qui place également AppDomain sur la liste de coupe, vous ne pouvez pas exécuter de code dans un domaine d'application sans prise en charge à distance. C'est donc entièrement par conception.
la source
Mise à jour pour .NET Standard 2 et .NET Core 2
Dans .NET Standard 2, la
AppDomain
classe est là. Cependant, de nombreuses parties de cette API lèveront unPlatformNotSupportedException
pour .NET Core.La principale raison pour laquelle il est encore là - dedans est pour des choses de base comme l' enregistrement d' un gestionnaire d'exception non gérée qui va fonctionner.
La FAQ .NET Standard a cette explication :
En dehors de cela, la réponse principale et d'autres réponses expliquent également bien pourquoi la majeure partie d'AppDomain a toujours été coupée (par exemple, une exception non prise en charge).
la source
Domaines d'application
Pourquoi a-t-il été interrompu? Les AppDomains nécessitent un support d'exécution et sont généralement assez chers. Bien qu'il soit toujours implémenté par CoreCLR, il n'est pas disponible dans .NET Native et nous ne prévoyons pas d'y ajouter cette fonctionnalité.
Que dois-je utiliser à la place? Les AppDomains ont été utilisés à des fins différentes. Pour l'isolation du code, nous recommandons des processus et / ou des conteneurs. Pour le chargement dynamique des assemblys, nous vous recommandons la nouvelle classe AssemblyLoadContext.
Source du blog MSDN
la source
For code isolation, we recommend processes and/or containers
... Existe-t-il une API conteneur disponible dans .net core?À un moment donné, j'ai entendu dire que le déchargement des assemblys serait activé sans utiliser de domaines. Je pense que le
System.Runtime.Loader.AssemblyLoadContext
type dans System.Runtime.Loader.dll est lié à ce travail, mais je ne vois rien qui permette encore le déchargement.la source
J'ai entendu dans un stand de la communauté ou dans un discours sur Microsoft que la fonction d'isolation d'AppDomains est mieux gérée par les processus (et en fait le modèle commun sur d'autres plates-formes) et que le déchargement est en effet prévu comme une fonctionnalité normale sans rapport avec AppDomains.
la source
Vous n'avez plus besoin d'AppDomains, vous avez maintenant LoadContexts:
public class CollectibleAssemblyLoadContext : AssemblyLoadContext { public CollectibleAssemblyLoadContext() : base(isCollectible: true) { } protected override Assembly Load(AssemblyName assemblyName) { return null; } } byte[] result = null; // Assembly Emit-result from roslyn System.Runtime.Loader.AssemblyLoadContext context = new CollectibleAssemblyLoadContext(); System.IO.Stream ms = new System.IO.MemoryStream(result); System.Reflection.Assembly assembly = context.LoadFromStream(ms); System.Type programType = assembly.GetType("RsEval"); MyAbstractClass eval = (MyAbstractClass )System.Activator.CreateInstance(programType); eval.LoadContext = context; eval.Stream = ms; // do something here with the dynamically created class "eval"
et puis tu peux dire
eval.LoadContext.Unload(); eval.Stream.Dispose();
Bonus si vous mettez cela dans l'interface IDisposable de la classe abstraite, vous pouvez simplement utiliser using, si vous le souhaitez.
Remarque:
cela suppose une classe abstraite fixe dans un assembly commun
public abstract class MyAbstractClass { public virtual void foo() {} }
et une classe générée dynamiquement à l'exécution (utilisant Roslyn), référençant la classe abstraite dans l'assembly commun, qui implémente par exemple:
public class RsEval: MyAbstractClass { public override void foo() {} }
la source