C# 在新AppDomain下执行dll程序集
我已经研究了几天了。我正在尝试在外部程序集中自己的AppDomain下正确创建类的实例 我已经能够在新的AppDomain下加载外部程序集,但是它的所有依赖项似乎都加载在父AppDomain中,这与此目的背道而驰,因为我想稍后卸载dll以释放它们上的锁(插件系统)。你知道为什么会这样做吗C# 在新AppDomain下执行dll程序集,c#,.net,.net-assembly,appdomain,C#,.net,.net Assembly,Appdomain,我已经研究了几天了。我正在尝试在外部程序集中自己的AppDomain下正确创建类的实例 我已经能够在新的AppDomain下加载外部程序集,但是它的所有依赖项似乎都加载在父AppDomain中,这与此目的背道而驰,因为我想稍后卸载dll以释放它们上的锁(插件系统)。你知道为什么会这样做吗 public MyCustomObject BindAssembly() { string currentAssemblyPath = @"C:\PathToMy\Assembly"; stri
public MyCustomObject BindAssembly()
{
string currentAssemblyPath = @"C:\PathToMy\Assembly";
string currentAssemblyFile = @"C:\PathToMy\Assembly\MyAssembly.dll";
AssemblyName currentAssemblyName = AssemblyName.GetAssemblyName(currentAssemblyFile);
AppDomain domain = AppDomain.CurrentDomain;
domain.AssemblyResolve += domain_AssemblyResolve;
AppDomainSetup setup = new AppDomainSetup()
{
PrivateBinPath = currentAssemblyPath,
ApplicationBase = domain.BaseDirectory,
DynamicBase = domain.SetupInformation.DynamicBase,
ShadowCopyFiles = domain.SetupInformation.ShadowCopyFiles,
CachePath = domain.SetupInformation.CachePath,
AppDomainManagerAssembly = domain.SetupInformation.AppDomainManagerAssembly,
AppDomainManagerType = domain.SetupInformation.AppDomainManagerType
};
AppDomain newDomain = AppDomain.CreateDomain("NewDomain", AppDomain.CurrentDomain.Evidence, setup);
newDomain.AssemblyResolve += newDomain_AssemblyResolve;
currentAssembly = newDomain.Load(currentAssemblyName);
// tried this too
//var obj = domain.CreateInstanceFromAndUnwrap(currentAssemblyFile, className);
// list all of the assemblies inside the custom app domain
var newDomainAssemblies = newDomain.GetAssemblies(); // (contains my loaded assembly, but not dependencies)
// list all of the assemblies inside the parent app domain
var appAssemblies = AppDomain.CurrentDomain.GetAssemblies(); // (contains my loaded assembly as well as all dependencies)
return obj as MyCustomObject;
}
// resolve dependencies in custom domain
Assembly newDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// this never fires
AppDomain domain = (AppDomain)sender;
}
// resolve dependencies in parent domain
Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args)
{
AppDomain domain = (AppDomain)sender;
string assemblyDependencyPath = String.Format(@"{0}", Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(args.RequestingAssembly.CodeBase).Path)));
string[] files = Directory.GetFiles(assemblyDependencyPath, "*.dll", SearchOption.AllDirectories);
foreach (string file in files)
{
// if we found it, load the assembly and cache it.
AssemblyName aname = AssemblyName.GetAssemblyName(file);
if (aname.FullName.Equals(args.Name))
{
Assembly assembly = domain.Load(aname);
//Assembly assembly = Assembly.LoadFrom(file); // also tried this, same result
return assembly;
}
}
}
我不确定这个(或者通常跨appdomain)将如何处理抽象类的不同实现,因为您可能会发现在主appdomain
中使用子类仍然需要依赖项,但我最近不得不做类似的事情,并发现使用可序列化加载程序类,它与MyCustomObject
位于同一程序集中,是保持事物独立的最佳方式
其思想是在当前的AppDomain
中创建加载程序,然后将其编组到新的AppDomain
,并要求加载和实例化所需的程序集和类型
请注意,加载程序和从MyCustomObject
继承的任何内容都必须是或继承自,因为它们将在AppDomain
之间传递
public MyCustomObject BindAssembly()
{
string currentAssemblyPath = @"C:\PathToMy\Assembly";
string currentAssemblyFile = @"C:\PathToMy\Assembly\MyAssembly.dll";
AssemblyName currentAssemblyName = AssemblyName.GetAssemblyName(currentAssemblyFile);
AppDomain domain = AppDomain.CurrentDomain;
domain.AssemblyResolve += domain_AssemblyResolve;
AppDomainSetup setup = new AppDomainSetup()
{
PrivateBinPath = currentAssemblyPath,
ApplicationBase = domain.BaseDirectory,
DynamicBase = domain.SetupInformation.DynamicBase,
ShadowCopyFiles = domain.SetupInformation.ShadowCopyFiles,
CachePath = domain.SetupInformation.CachePath,
AppDomainManagerAssembly = domain.SetupInformation.AppDomainManagerAssembly,
AppDomainManagerType = domain.SetupInformation.AppDomainManagerType
};
AppDomain newDomain = AppDomain.CreateDomain("NewDomain", AppDomain.CurrentDomain.Evidence, setup);
newDomain.Load(typeof(Loader).Assembly.GetName());
Loader loader = (Loader)newDomain.CreateInstanceAndUnwrap(
typeof(Loader).Assembly.FullName, typeof(Loader).FullName);
// load the assembly containing MyCustomObject into the remote domain
loader.LoadAssembly(currentAssemblyFile);
// ask the Loader to create the object instance for us
MyCustomObject obj = loader.CreateCustomObject();
return obj;
}
public class Loader : MarshalByRefObject
{
/// <summary>Stores the assembly containing the task class.</summary>
private Assembly assembly;
/// <summary>Retrieves the current lifetime service object that controls the lifetime policy for this instance.</summary>
/// <returns>This always returns null.</returns>
public override object InitializeLifetimeService()
{
return null;
}
/// <summary>Loads the assembly containing the task class.</summary>
/// <param name="path">The full path to the assembly DLL containing the task class.</param>
public void LoadAssembly(string path)
{
this.assembly = Assembly.Load(AssemblyName.GetAssemblyName(path));
}
/// <summary>Instantiates the required object.</summary>
/// <param name="classFullName">The full name (namespace + class name) of the task class.</param>
/// <returns>The new object.</returns>
public MyCustomObject CreateCustomObject()
{
MyCustomObject instance = new MyCustomObject();
// do whatever you want with the instance here
return instance;
}
}
public MyCustomObject BindAssembly()
{
字符串currentAssemblyPath=@“C:\Pathomy\Assembly”;
字符串currentAssemblyFile=@“C:\Pathomy\Assembly\MyAssembly.dll”;
AssemblyName currentAssemblyName=AssemblyName.GetAssemblyName(currentAssemblyFile);
AppDomain域=AppDomain.CurrentDomain;
domain.AssemblyResolve+=域_AssemblyResolve;
AppDomainSetup=新建AppDomainSetup()
{
PrivateBinPath=currentAssemblyPath,
ApplicationBase=domain.BaseDirectory,
DynamicBase=domain.SetupInformation.DynamicBase,
ShadowCopyFiles=domain.SetupInformation.ShadowCopyFiles,
CachePath=domain.SetupInformation.CachePath,
AppDomainManagerAssembly=domain.SetupInformation.AppDomainManagerAssembly,
AppDomainManagerType=domain.SetupInformation.AppDomainManagerType
};
AppDomain newDomain=AppDomain.CreateDomain(“newDomain”,AppDomain.CurrentDomain.Evidence,setup);
Load(typeof(Loader.Assembly.GetName());
加载器加载器=(加载器)newDomain.CreateInstanceAndUnwrap(
typeof(Loader.Assembly.FullName,typeof(Loader.FullName);
//将包含MyCustomObject的程序集加载到远程域
loader.LoadAssembly(currentAssemblyFile);
//请加载程序为我们创建对象实例
MyCustomObject obj=loader.CreateCustomObject();
返回obj;
}
公共类装入器:MarshalByRefObject
{
///存储包含任务类的程序集。
私人集会;
///检索控制此实例的生存期策略的当前生存期服务对象。
///这总是返回null。
公共重写对象初始化ElifetimeService()
{
返回null;
}
///加载包含任务类的程序集。
///包含任务类的程序集DLL的完整路径。
公共void加载程序集(字符串路径)
{
this.assembly=assembly.Load(AssemblyName.GetAssemblyName(路径));
}
///实例化所需的对象。
///任务类的全名(命名空间+类名)。
///新对象。
公共MyCustomObject CreateCustomObject()
{
MyCustomObject实例=新建MyCustomObject();
//对这里的实例执行任何您想要的操作
返回实例;
}
}
您是否尝试过currentAssembly=newDomain.Load(currentAssemblyName)代码>而不是currentAssembly=domain.Load(currentAssemblyName)代码>?我还确认,如果卸载我创建的新AppDomain,依赖程序集仍然保留在父AppDomain中。Rhumboll-很抱歉,我的存根代码中有一个输入错误。修复了我的问题。您不能引用在AppDomain中加载的程序集中定义的任何类型。比如我的自定义对象。改用在另一个程序集中定义的接口。当你查询“.net plugin architecture”.Hans时,谷歌点击了很多次-MyCustomObject并没有在加载的程序集中定义,而是一个抽象类,它是在一个单独的抽象程序集中定义的,由双方共享。我使用代理尝试了类似的方法,然而,我修改了它以符合您的建议,但它在这里失败,出现了一个无法加载程序集错误:Loader Loader=(Loader)domain.createInstanceFromandWrap(typeof(Loader.assembly.FullName),typeof(Loader.FullName);经过一些修改后,我意识到我必须将CreateInstanceFromAndUnwrap()的完整路径传递给dll,但是依赖项添加到父AppDomain的行为仍然存在。