Pas d'AppDomains dans .NET Core! Pourquoi?

87

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?

Aditya Pasumarthi
la source
9
Mais .NET Core 5 n'est pas .NET Framework. Ce n'est pas la version à venir de .NET CLR 4.6 mais une autre chose distincte, alors ne vous inquiétez pas, AppDomain est là pour rester.
Adriano Repetti
2
Je vois cela, mais si Microsoft prétend que .NET Core 5 sera multi-plateforme (Windows / Linux / Unix), alors je suis curieux de savoir pourquoi ils veulent supprimer une fonctionnalité de base comme AppDomain.
Aditya Pasumarthi
3
Je suppose (mais c'est juste mon avis) qu'ils sont plus difficiles à implémenter de manière multi-plateforme, ils ralentissent beaucoup de choses et ajoutent de la complexité. Peu de gens les utilisent (au moins la plupart des gens ne le font pas directement). Si vous n'en avez pas besoin, vous pouvez utiliser .NET Core. Si vous en avez besoin ... ne l'utilisez pas (pensez ReFS vs NTFS). Simplement .NET Core n'est pas l'avenir de .NET (jusqu'à présent) mais un projet distinct. Peut-être un atelier mais certainement pas un chemin de migration ou une alternative 1: 1 (du moins maintenant).
Adriano Repetti
@AdrianoRepetti: Pensez à ajouter ceci comme réponse, car je pense que c'est utile en tant que tel.
Patrick Hofman
@PatrickHofman c'est juste mon avis (2ème commentaire), je pourrais répondre en tant que wiki communautaire mais je laisse ce devoir à quelqu'un avec un anglais plus courant!
Adriano Repetti

Réponses:

50

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.

Hans Passant
la source
12
À mon humble avis, cela n'a rien à voir avec la taille, mais avec le fait que CoreCLR n'a pas de nom fort, et dispose donc d'un nouveau système de fusion et d'une nouvelle façon de voir ce qu'est un assemblage, son identité et où il est chargé, ce qui signifie appdomain en tant que conteneur n'est plus utile.
Frans Bouma
7
Hmm, non. Garder la taille de téléchargement à 6,6 Mo nécessitait bien sûr la suppression de plus d'une fonctionnalité.
Hans Passant
7
AppDomains peut être utile dans son intégralité .NET même si vous n'utilisez pas de noms forts. (Par exemple, la capacité d'AppDomains à fournir une isolation des pannes ne dépend pas d'une dénomination forte.) Ainsi, la suppression d'une dénomination forte ne constituerait pas en soi une raison de supprimer AppDomains.
Ian Griffiths
5
Je suis confus. Quelle est la relation entre .Net Core et Silverlight?
svick
10
Les programmeurs ont tendance à supposer que .NETCore est nouveau. Microsoft fait très peu pour dissiper cette notion, notamment en changeant le numéro de version 5.0 en 1.0. CoreCLR existe depuis très longtemps, a commencé sa vie en tant que runtime pour .NET Compact. Silverlight et le runtime WinRT / UWP en sont des utilisations notables avant de l'ouvrir en source. Meilleure version d'exécution à choisir, ayant déjà été portée sur OSX et divers processeurs mobiles WinCE.
Hans Passant
46

Mise à jour pour .NET Standard 2 et .NET Core 2

Dans .NET Standard 2, la AppDomainclasse est là. Cependant, de nombreuses parties de cette API lèveront un PlatformNotSupportedExceptionpour .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 :

AppDomain fait-il partie de .NET Standard?

Le type AppDomain fait partie de .NET Standard. Toutes les plates-formes ne prendront pas en charge la création de nouveaux domaines d'application, par exemple .NET Core ne le fera pas, de sorte que la méthode AppDomain.CreateDomain tout en étant disponible dans .NET Standard peut lever PlatformNotSupportedException.

La principale raison pour laquelle nous exposons ce type dans .NET Standard est que l'utilisation est assez élevée et n'est généralement pas associée à la création de nouveaux domaines d'application, mais à l'interaction avec le domaine d'application actuel, comme l'enregistrement d'un gestionnaire d'exceptions non géré ou la demande du répertoire de base de l'application. .

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).

Jeroen
la source
20

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

cwishva
la source
Une question, qu'entendez-vous par For code isolation, we recommend processes and/or containers... Existe-t-il une API conteneur disponible dans .net core?
Ivandro Jao
@IvandroIsmael, ils signifient "diviser votre application / module unique en applications / modules / processus / conteneurs séparés en interaction" (très probablement - en microservices), c'est-à-dire refactoriser votre application pour ne pas utiliser AppDomains pour l'isolation de code
Burst
10

À 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.AssemblyLoadContexttype dans System.Runtime.Loader.dll est lié à ce travail, mais je ne vois rien qui permette encore le déchargement.

bricelam
la source
5

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.

Thomas
la source
5

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()
     {}
}
Stefan Steiger
la source