微软是否有理由选择不支持.NET Core中的AppDomain?
AppDomains在构建长时间运行的服务器应用程序时特别有用,我们可能希望在不关闭服务器的情况下更新服务器加载的程序集。
如果没有AppDomains,我们如何在长时间运行的服务器进程中替换我们的程序集?
AppDomains还为我们提供了一种隔离服务器代码不同部分的方法。比如,自定义websocket服务器可以在主appdomain中有套接字代码,而我们的服务在辅助appdomain中运行。
如果没有AppDomains,则无法实现上述方案。
我可以看到一个论点可能会讨论使用VM的云概念来处理程序集更改而不必承担AppDomains的开销。但这是微软的想法或说法吗?或者他们有上述情景的具体原因和替代方案?
答案 0 :(得分:39)
.NETCore子集的目的是保持.NET安装小。并且易于移植。这就是为什么你可以在Windows和OSX上运行Silverlight应用程序,而不是在访问网页时等待很长时间。下载和安装完整的运行时和框架需要花费几秒钟的时间,给予或接受。
保持小巧不可避免地需要削减功能。 Remoting在这个名单上非常高,它非常昂贵。否则很好地隐藏,但您可以看到委托不再具有功能的BeginInvoke()方法。这也将AppDomain放在了剪切列表中,您无法在没有远程支持的情况下在应用程序域中运行代码。所以这完全是设计的。
答案 1 :(得分:28)
在.NET Standard 2中,AppDomain
类在中。但是,该API的许多部分将为.NET Core抛出PlatformNotSupportedException
。
它仍然存在的主要原因是注册将工作的未处理异常处理程序等基本内容。
The .NET Standard FAQ has this explanation:
AppDomain是.NET Standard的一部分吗?
AppDomain类型是.NET Standard的一部分。并非所有平台都支持创建新的应用程序域,例如,.NET Core不会,因此在.NET Standard中可用的方法AppDomain.CreateDomain可能会抛出PlatformNotSupportedException。
我们在.NET Standard中公开此类型的主要原因是因为使用率相当高,并且通常与创建新的应用程序域无关,而是与当前应用程序域进行交互,例如注册未处理的异常处理程序或要求应用程序的基本目录。
除此之外,top answer和其他答案也很好地解释了为什么大部分AppDomain仍被切断(例如抛出不支持的异常)。
答案 2 :(得分:9)
为什么停止使用? AppDomains需要运行时支持,而且通常非常昂贵。虽然仍由CoreCLR实现,但它在.NET Native中不可用,我们不打算在那里添加此功能。
我应该使用什么? AppDomains用于不同目的。对于代码隔离,我们建议使用进程和/或容器。对于动态加载程序集,我们建议使用新的AssemblyLoadContext类。
答案 3 :(得分:6)
有一次,我听说不使用域就可以启用卸载程序集。我认为System.Runtime.Loader.dll中的System.Runtime.Loader.AssemblyLoadContext
类型与此工作有关,但我还没有看到任何可以卸载的内容。
答案 4 :(得分:6)
您不再需要AppDomain,现在有了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"
然后你可以说
eval.LoadContext.Unload();
eval.Stream.Dispose();
如果将其放在抽象类的IDisposable接口中,则奖励,如果需要,可以使用using。
注意:
这假定在公共程序集中有一个固定的抽象类
public abstract class MyAbstractClass
{
public virtual void foo()
{}
}
和一个动态运行时生成的类(使用Roslyn),该类引用公共程序集中的抽象类,该类实现例如:
public class RsEval: MyAbstractClass
{
public override void foo()
{}
}
答案 5 :(得分:4)
我在社区站点或微软的一些谈话中听说,AppDomains的隔离功能可以通过进程更好地处理(实际上是其他平台中的常见模式),并且卸载确实计划为与AppDomains无关的正常功能。