使用MarshalByRefObject创建二级AppDomains遇平台及类型加载错误
我参考.NET 7文档中的示例,尝试用MarshalByRefObject类在二级应用域中创建类实例,几乎完全复制了示例代码:
using System; using System.Reflection; namespace MarshalByRefObjectExample { public class Worker : MarshalByRefObject { public void PrintDomain() { Console.WriteLine("Object is executing in AppDomain \"{0}\"", AppDomain.CurrentDomain.FriendlyName); } } internal class Program { static void Main(string[] args) { // 在当前AppDomain创建普通实例 Worker localWorker = new Worker(); localWorker.PrintDomain(); // 创建新AppDomain,在其中创建Worker实例并执行代码 AppDomain ad = AppDomain.CreateDomain("New domain"); Worker remoteWorker = (Worker) ad.CreateInstanceAndUnwrap( typeof(Worker).Assembly.FullName, "Worker" ); remoteWorker.PrintDomain(); } } }
运行后报错:
Object is executing in AppDomain "MarshalByRefObjectExample"
Unhandled exception. System.PlatformNotSupportedException: Secondary AppDomains are not supported on this platform.
at System.AppDomain.CreateDomain(String friendlyName)
at MarshalByRefObjectExample.Program.Main(String[] args) in Program.cs:line 24
我的项目文件如下:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <RootNamespace>MarshalByRefObjectExample</RootNamespace> <Nullable>enable</Nullable> </PropertyGroup> </Project>
请问哪里操作错了?
看到评论后,我尝试把项目改成.NET Framework(而非.NET Core),项目文件如下:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net472</TargetFramework> <RootNamespace>MarshalByRefObjectExample</RootNamespace> </PropertyGroup> </Project>
现在又出现新错误:
Unhandled Exception: System.TypeLoadException: Could not load type 'Worker' from assembly 'MarshalByRefObjectExample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
at System.Reflection.RuntimeAssembly.GetType(RuntimeAssembly assembly, String name, Boolean throwOnError, Boolean ignoreCase, ObjectHandleOnStack type)
at System.Reflection.RuntimeAssembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase)
at System.Activator.CreateInstance(String assemblyString, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, Evidence securityInfo, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(String assemblyName, String typeName)
at System.AppDomain.CreateInstance(String assemblyName, String typeName)
at System.AppDomain.CreateInstanceAndUnwrap(String assemblyName, String typeName)
at System.AppDomain.CreateInstanceAndUnwrap(String assemblyName, String typeName)
at MarshalByRefObjectExample.Program.Main(String[] args) in Program.cs:line 25
第一个错误(.NET 7下的PlatformNotSupportedException)
.NET Core/.NET 5+ 不支持二级AppDomain,这是平台设计上的核心变更。AppDomain是.NET Framework的专属特性,在现代.NET中已被移除,替代方案根据需求选择:
- 若需要隔离程序集加载,使用
AssemblyLoadContext实现加载上下文隔离 - 若需要跨上下文的代码执行隔离,考虑使用独立进程+IPC通信
- 旧的
System.Runtime.Remoting已被标记为过时,不推荐在新代码中使用
第二个错误(.NET Framework下的TypeLoadException)
问题出在CreateInstanceAndUnwrap的类型名称参数上。你的Worker类属于MarshalByRefObjectExample命名空间,必须传入完全限定类型名(命名空间+类名),而不是仅类名"Worker"。
修改代码如下(推荐方式,避免手动拼写错误):
Worker remoteWorker = (Worker) ad.CreateInstanceAndUnwrap( typeof(Worker).Assembly.FullName, typeof(Worker).FullName );
或者手动拼写完全限定名:
Worker remoteWorker = (Worker) ad.CreateInstanceAndUnwrap( typeof(Worker).Assembly.FullName, "MarshalByRefObjectExample.Worker" );
修改后,在.NET Framework 4.7.2环境下运行,就能正常输出两个不同的AppDomain名称。
内容的提问来源于stack exchange,提问作者user32882

