我现在已经研究了几天了。我试图在它自己的AppDomain下的外部程序集中正确创建一个类的实例。
我已经能够在新的AppDomain下加载外部程序集,但是它的所有依赖项似乎都加载在父AppDomain中,这违背了目的,因为我想稍后将dll卸载到释放锁定(插件系统)。知道为什么会这样做吗?
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;
}
}
}
答案 0 :(得分:1)
我不确定这个(或者一般的跨域应用程序)如何与抽象类的不同实现一起工作,因为您可能会发现在主AppDomain
中使用子类仍然需要依赖项,但最近我不得不做类似的事情,发现使用与MyCustomObject
在同一个程序集中的Serializable Loader类是保持分离的最佳方法。
我们的想法是在当前的AppDomain
中创建Loader,然后编组到新的AppDomain
,并要求加载并实例化那里所需的程序集和类型。
请注意,Loader和从MyCustomObject
继承的任何内容都必须为Serializable
或从MarshalByRefObject
继承,因为它们将在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;
}
}