aba*_*hev 108 .net c# reflection assemblies appdomain
我想加载到一个新的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));
Run Code Online (Sandbox Code Playgroud)
得到了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);
}
Run Code Online (Sandbox Code Playgroud)
但FileNotFoundException又一次,在另一个(参考)集会上.
如何递归加载所有引用?
在加载根程序集之前是否必须创建引用树?如何在不加载程序集的情况下获取程序集的引用?
Jdu*_*duv 65
您需要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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
另请注意,如果您使用,LoadFrom您可能会遇到FileNotFound异常,因为程序集解析程序将尝试查找您在GAC或当前应用程序的bin文件夹中加载的程序集.使用LoadFile加载任意组件文件,而不是-但请注意,如果你这样做,你需要自己加载任何依赖关系.
小智 14
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
来自客户站点的电话
ProxyDomain pd = new ProxyDomain();
Assembly assembly = pd.GetAssembly(assemblyFilePath);
Run Code Online (Sandbox Code Playgroud)
Nir*_*Nir 10
一旦将程序集实例传递回调用者域,调用者域将尝试加载它!这就是你得到例外的原因.这发生在你的最后一行代码中:
domain.Load(AssemblyName.GetAssemblyName(path));
Run Code Online (Sandbox Code Playgroud)
因此,无论你想对程序集做什么,都应该在代理类中完成 - 一个继承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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果确实需要从与当前应用程序域文件夹不同的文件夹加载程序集,请使用特定的dll搜索路径文件夹创建新的应用程序域.
例如,上面代码中的app域创建行应替换为:
var dllsSearchPath = @"[dlls search path for new app domain]";
AppDomain newDomain = AppDomain.CreateDomain("newDomain", new Evidence(), dllsSearchPath, "", true);
Run Code Online (Sandbox Code Playgroud)
这样,所有dll都将自动从dllsSearchPath中解析出来.
如果引用的程序集不在GAC中或在CLR的探测路径上,则需要处理AppDomain.AssemblyResolve或AppDomain.ReflectionOnlyAssemblyResolve事件(取决于您正在执行的负载).
AppDomain.ReflectionOnlyAssemblyResolve
关键是 AppDomain 引发的 AssemblyResolve 事件。
[STAThread]
static void Main(string[] args)
{
fileDialog.ShowDialog();
string fileName = fileDialog.FileName;
if (string.IsNullOrEmpty(fileName) == false)
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
if (Directory.Exists(@"c:\Provisioning\") == false)
Directory.CreateDirectory(@"c:\Provisioning\");
assemblyDirectory = Path.GetDirectoryName(fileName);
Assembly loadedAssembly = Assembly.LoadFile(fileName);
List<Type> assemblyTypes = loadedAssembly.GetTypes().ToList<Type>();
foreach (var type in assemblyTypes)
{
if (type.IsInterface == false)
{
StreamWriter jsonFile = File.CreateText(string.Format(@"c:\Provisioning\{0}.json", type.Name));
JavaScriptSerializer serializer = new JavaScriptSerializer();
jsonFile.WriteLine(serializer.Serialize(Activator.CreateInstance(type)));
jsonFile.Close();
}
}
}
}
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string[] tokens = args.Name.Split(",".ToCharArray());
System.Diagnostics.Debug.WriteLine("Resolving : " + args.Name);
return Assembly.LoadFile(Path.Combine(new string[]{assemblyDirectory,tokens[0]+ ".dll"}));
}
Run Code Online (Sandbox Code Playgroud)
我花了一段时间才了解@ user1996230的答案,因此我决定提供一个更明确的示例。在下面的示例中,我为另一个AppDomain中加载的对象创建代理,并从另一个域对该对象调用方法。
class ProxyObject : MarshalByRefObject
{
private Type _type;
private Object _object;
public void InstantiateObject(string AssemblyPath, string typeName, object[] args)
{
assembly = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + AssemblyPath); //LoadFrom loads dependent DLLs (assuming they are in the app domain's base directory
_type = assembly.GetType(typeName);
_object = Activator.CreateInstance(_type, args); ;
}
public void InvokeMethod(string methodName, object[] args)
{
var methodinfo = _type.GetMethod(methodName);
methodinfo.Invoke(_object, args);
}
}
static void Main(string[] args)
{
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = @"SomePathWithDLLs";
AppDomain domain = AppDomain.CreateDomain("MyDomain", null, setup);
ProxyObject proxyObject = (ProxyObject)domain.CreateInstanceFromAndUnwrap(typeof(ProxyObject).Assembly.Location,"ProxyObject");
proxyObject.InstantiateObject("SomeDLL","SomeType", new object[] { "someArgs});
proxyObject.InvokeMethod("foo",new object[] { "bar"});
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
124109 次 |
| 最近记录: |