我想加载到一个新的具有复杂引用树的AppDomain
程序集(MyDll.dll -> Microsoft.Office.Interop.Excel.dll -> Microsoft.Vbe.Interop.dll -> Office.dll -> stdole.dll)
据我所知,当程序集被加载到AppDomain
时,它的引用不会自动加载,我必须手动加载它们。所以当我这样做的时候:
string dir = @"SomePath"; // different from AppDomain.CurrentDomain.BaseDirectory
string path = System.IO.Path.Combine(dir, "MyDll.dll");
AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
setup.ApplicationBase = dir;
AppDomain domain = AppDomain.CreateDomain("SomeAppDomain", null, setup);
domain.Load(AssemblyName.GetAssemblyName(path));
并得到了FileNotFoundException
:
无法加载文件或程序集“MyDll,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”或其依赖项之一。系统找不到指定的文件。
我认为最关键的部分是它的依赖之一的。
好的,在domain.Load(AssemblyName.GetAssemblyName(path));
之前我会做下一步
foreach (AssemblyName refAsmName in Assembly.ReflectionOnlyLoadFrom(path).GetReferencedAssemblies())
{
domain.Load(refAsmName);
}
但是在另一个(引用的)程序集上再次获得了FileNotFoundException
。
如何以递归方式加载所有引用?
在加载根程序集之前,我必须创建引用树吗?如何在不加载的情况下获取程序集的引用?
发布于 2012-11-13 12:43:51
在外部应用程序域中执行代理对象之前,您需要调用CreateInstanceAndUnwrap
。
class Program
{
static void Main(string[] args)
{
AppDomainSetup domaininfo = new AppDomainSetup();
domaininfo.ApplicationBase = System.Environment.CurrentDirectory;
Evidence adevidence = AppDomain.CurrentDomain.Evidence;
AppDomain domain = AppDomain.CreateDomain("MyDomain", adevidence, domaininfo);
Type type = typeof(Proxy);
var value = (Proxy)domain.CreateInstanceAndUnwrap(
type.Assembly.FullName,
type.FullName);
var assembly = value.GetAssembly(args[0]);
// AppDomain.Unload(domain);
}
}
public class Proxy : MarshalByRefObject
{
public Assembly GetAssembly(string assemblyPath)
{
try
{
return Assembly.LoadFile(assemblyPath);
}
catch (Exception)
{
return null;
// throw new InvalidOperationException(ex);
}
}
}
另外,请注意,如果您使用LoadFrom
,您可能会得到一个FileNotFound
异常,因为程序集解析器将尝试查找您在GAC或当前应用程序的bin文件夹中加载的程序集。改为使用LoadFile
加载任意程序集文件--但请注意,如果这样做,您将需要自己加载任何依赖项。
发布于 2010-06-17 14:10:36
http://support.microsoft.com/kb/837908/en-us
C#版本:
创建一个版主类并从MarshalByRefObject
继承它
class ProxyDomain : MarshalByRefObject
{
public Assembly GetAssembly(string assemblyPath)
{
try
{
return Assembly.LoadFrom(assemblyPath);
}
catch (Exception ex)
{
throw new InvalidOperationException(ex.Message);
}
}
}
从客户端站点调用
ProxyDomain pd = new ProxyDomain();
Assembly assembly = pd.GetAssembly(assemblyFilePath);
发布于 2013-12-05 21:30:06
一旦您将程序集实例传递回调用方域,调用方域将尝试加载它!这就是你得到异常的原因。这发生在最后一行代码中:
domain.Load(AssemblyName.GetAssemblyName(path));
因此,无论你想对程序集做什么,都应该在一个代理类中完成--一个继承MarshalByRefObject的类。
考虑到调用方域和新创建的域都应该有权访问代理类程序集。如果您的问题不是太复杂,请考虑保持ApplicationBase文件夹不变,这样它将与调用方域文件夹相同(新域将只加载它需要的程序集)。
用简单的代码:
public void DoStuffInOtherDomain()
{
const string assemblyPath = @"[AsmPath]";
var newDomain = AppDomain.CreateDomain("newDomain");
var asmLoaderProxy = (ProxyDomain)newDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(ProxyDomain).FullName);
asmLoaderProxy.GetAssembly(assemblyPath);
}
class ProxyDomain : MarshalByRefObject
{
public void GetAssembly(string AssemblyPath)
{
try
{
Assembly.LoadFrom(AssemblyPath);
//If you want to do anything further to that assembly, you need to do it here.
}
catch (Exception ex)
{
throw new InvalidOperationException(ex.Message, ex);
}
}
}
如果确实需要从与当前应用程序域文件夹不同的文件夹加载程序集,请使用特定的dll搜索路径文件夹创建新的应用程序域。
例如,上面代码中的应用程序域创建行应该替换为:
var dllsSearchPath = @"[dlls search path for new app domain]";
AppDomain newDomain = AppDomain.CreateDomain("newDomain", new Evidence(), dllsSearchPath, "", true);
这样,所有的dlls都将自动从dllsSearchPath中解析。
https://stackoverflow.com/questions/658498
复制相似问题