Sem AppDomains no .NET Core! Por quê?

86

Existe um forte motivo pelo qual a Microsoft optou por não oferecer suporte a AppDomains no .NET Core?

AppDomains são particularmente úteis ao construir aplicativos de servidor de longa execução, onde podemos querer atualizar os assemblies carregados pelo servidor de uma maneira elegante, sem desligar o servidor.

Sem AppDomains, como vamos substituir nossos assemblies em um processo de servidor de longa duração?

Os AppDomains também nos fornecem uma maneira de isolar diferentes partes do código do servidor. Por exemplo, um servidor websocket personalizado pode ter código de soquete no appdomain primário, enquanto nossos serviços são executados no appdomain secundário.

Sem AppDomains, o cenário acima não é possível.

Eu posso ver um argumento que pode falar sobre o uso do conceito de nuvem de VMs para lidar com alterações de montagem e não ter que incorrer na sobrecarga de AppDomains. Mas é isso que a Microsoft pensa ou diz? ou eles têm uma razão específica e alternativas para os cenários acima?

Aditya Pasumarthi
fonte
9
Mas o .NET Core 5 não é o .NET Framework. Não é a próxima versão do .NET CLR 4.6, mas outra coisa separada, então não se preocupe, AppDomain está aqui para ficar.
Adriano Repetti
2
Eu vejo isso, mas se a Microsoft está alegando que o .NET Core 5 será multiplataforma (Windows / Linux / Unix), então estou curioso para saber por que eles querem remover um recurso central como o AppDomain.
Aditya Pasumarthi
3
Eu acho (mas é apenas minha opinião) eles são mais difíceis de implementar em uma maneira multiplataforma, eles tornam muitas coisas lentas e adicionam complexidade. Poucas pessoas os usam (pelo menos a maioria das pessoas não o faz diretamente). Se não precisar deles, você pode usar o .NET Core. Se você precisar deles ... não use (pense em ReFS vs NTFS). Simplesmente .NET Core não é o futuro .NET (até agora), mas um projeto separado. Talvez um workbench, mas com certeza não um caminho de migração ou alternativa 1: 1 (pelo menos agora).
Adriano Repetti
@AdrianoRepetti: Considere adicionar isso como uma resposta, pois acho que é útil como tal.
Patrick Hofman
@PatrickHofman é só a minha opinião (2º comentário), poderia responder como wiki da comunidade mas deixo esse dever para alguém com um inglês mais fluente!
Adriano Repetti

Respostas:

50

O objetivo do subconjunto .NETCore era manter uma pequena instalação do .NET . E fácil de transportar. É por isso que você pode, digamos, executar um aplicativo Silverlight no Windows e no OSX e não esperar muito tempo ao visitar a página da web. Baixar e instalar o tempo de execução e a estrutura completos leva alguns segundos, mais ou menos.

Mantê-lo pequeno inevitavelmente requer que recursos sejam cortados. Remoto estava no topo dessa lista, é muito caro. Caso contrário, bem escondido, mas você pode, por exemplo, ver que os delegados não têm mais um método BeginInvoke () funcional. O que também colocou AppDomain na lista de corte, você não pode executar o código em um domínio de aplicativo sem suporte remoto. Portanto, isso é inteiramente intencional.

Hans Passant
fonte
12
IMHO, não tem nada a ver com tamanho, mas com o fato de que CoreCLR não tem uma nomenclatura forte e, portanto, tem um novo sistema de fusão e uma nova maneira de ver o que é um assembly, sua identidade e onde está carregado, o que significa que appdomain como um contêiner não é mais útil.
Frans Bouma
7
Hmm, não. Manter o tamanho do download em 6,6 MB exigia a remoção de mais de um recurso.
Hans Passant
7
AppDomains pode ser útil em .NET completo, mesmo se você não estiver usando nomes fortes. (Por exemplo, a capacidade dos AppDomains de fornecer isolamento de falhas não depende de nomes fortes.) Portanto, a remoção de nomes fortes não seria, por si só, um motivo para remover os AppDomains.
Ian Griffiths
5
Estou confuso. Qual é a relação entre .Net Core e Silverlight?
svick
10
Os programadores tendem a presumir que o .NETCore é novo. A Microsoft faz muito pouco para dissipar essa noção, nem um pouco alterando o número da versão 5.0 para 1.0. CoreCLR existe há muito tempo, começou a vida como o tempo de execução para .NET Compact. Silverlight e o tempo de execução WinRT / UWP são usos notáveis ​​para ele antes de abri-lo. Melhor versão de runtime para escolher, já tendo sido previamente portado para OSX e vários processadores móveis WinCE.
Hans Passant
46

Atualização para .NET Standard 2 e .NET Core 2

No .NET Standard 2, a AppDomainclasse está lá. No entanto, muitas partes dessa API lançarão um PlatformNotSupportedExceptionpara .NET Core.

A principal razão ele ainda está lá é para coisas básicas como registrar um manipulador de exceção não tratada que vai trabalhar.

As perguntas frequentes do .NET Standard têm esta explicação :

O AppDomain faz parte do .NET Standard?

O tipo AppDomain faz parte do .NET Standard. Nem todas as plataformas suportam a criação de novos domínios de aplicativo, por exemplo, o .NET Core não, portanto, o método AppDomain.CreateDomain, embora esteja disponível no .NET Standard, pode lançar PlatformNotSupportedException.

O principal motivo de expor esse tipo no .NET Standard é porque o uso é bastante alto e normalmente não está associado à criação de novos domínios de aplicativo, mas para interagir com o domínio de aplicativo atual, como registrar um manipulador de exceção não tratado ou solicitar o diretório base do aplicativo .

Além disso, a resposta principal e outras respostas também explicam bem por que a maior parte do AppDomain ainda foi cortada (por exemplo, lança uma exceção não suportada).

Jeroen
fonte
20

Domínios do aplicativo

Por que foi descontinuado? AppDomains requerem suporte de tempo de execução e geralmente são bastante caros. Embora ainda implementado pelo CoreCLR, não está disponível no .NET Native e não planejamos adicionar esse recurso lá.

O que devo usar no lugar? AppDomains foram usados ​​para diferentes fins. Para isolamento de código, recomendamos processos e / ou contêineres. Para carregamento dinâmico de assemblies, recomendamos a nova classe AssemblyLoadContext.

Fonte do MSDN Blog

Cwishva
fonte
Uma pergunta, o que você quer dizer com For code isolation, we recommend processes and/or containers... Existe uma API de contêiner disponível no núcleo .net?
Ivandro Jao
@IvandroIsmael, eles significam "dividir seu único aplicativo / módulo em aplicativos / módulos / processos / contêineres de interação separados" (provavelmente - em microsserviços), ou seja, refatorar seu aplicativo para não usar AppDomains para isolamento de código
Estouro
10

Em um ponto, ouvi que descarregar assemblies seria habilitado sem o uso de domínios. Acho que o System.Runtime.Loader.AssemblyLoadContexttipo em System.Runtime.Loader.dll está relacionado a este trabalho, mas não vejo nada lá que permita o descarregamento ainda.

bricelam
fonte
5

Eu ouvi em um stand da comunidade ou alguma conversa da Microsoft que o recurso de isolamento de AppDomains é melhor tratado por processos (e na verdade o padrão comum em outras plataformas) e o descarregamento é planejado como um recurso normal não relacionado a AppDomains.

Thomas
fonte
5

Você não precisa mais de AppDomains, agora você tem 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"

e então você pode dizer

eval.LoadContext.Unload();
eval.Stream.Dispose();

Bônus se você colocar isso na interface IDisposable da classe abstrata, então você pode apenas usar using, se quiser.

Nota:
Isso pressupõe uma classe abstrata fixa em uma montagem comum

public abstract class MyAbstractClass 
{

     public virtual void foo()
     {}
}

e uma classe gerada dinamicamente em tempo de execução (usando Roslyn), referenciando a classe abstrata no assembly comum, que implementa, por exemplo:

public class RsEval: MyAbstractClass 
{

     public override void foo()
     {}
}
Stefan Steiger
fonte