我需要在运行时加载的程序集中执行一个方法。现在我想在方法调用后卸载那些已加载的程序集。我知道我需要一个新的AppDomain,所以我可以卸载库。但在这里,出现了问题。
要加载的程序集是我的插件框架中的插件。他们根本没有切入点。我所知道的是它们包含一些实现给定接口的类型。旧的非AppDomain代码看起来像这样(略微缩短):
try
{
string path = Path.GetFullPath("C:\library.dll");
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
Assembly asm = Assembly.LoadFrom(path);
Type[] types = asm.GetExportedTypes();
foreach (Type t in types)
{
if ((t.GetInterface("IStarter") != null) && !t.IsAbstract)
{
object tempObj = Activator.CreateInstance(t);
MethodInfo info = t.GetMethod("GetParameters");
if (info != null)
{
return info.Invoke(tempObj, null) as string;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(String.Format("Damn '{0}'.", ex.Message), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.Name.StartsWith("MyProject.View,"))
{
string path = Path.GetFullPath("C:\view.dll"));
return Assembly.LoadFrom(path);
}
return null;
}
现在我想让它们加载到自己的AppDomain中:
try
{
string path = Path.GetFullPath("C:\library.dll");
AppDomain domain = AppDomain.CreateDomain("TempDomain");
domain.AssemblyResolve += CurrentDomain_AssemblyResolve; // 1. Exception here!!
domain.ExecuteAssembly(path); // 2. Exception here!!
domain.CreateInstanceFrom(...); // 3. I have NO clue, how the type is named.
domain.Load(...); // 4. I have NO clue, how the assembly is named.
domain.DoCallBack(...); // 5. Exception here!!
// ...
}
catch (Exception ex)
{
MessageBox.Show(String.Format("Damn '{0}'.", ex.Message), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
如您所见,我已经提出了5个案例。
如果我设置了事件处理程序,我会收到一个异常,即无法找到/加载程序集(它是管理控制台(mmc.exe)SnapIn。
ExecuteAssembly没有找到入口点(好吧,没有入口点)。
我不知道该类型是如何命名的。如何通过界面加载?
类似于3.如何获取程序集的名称?
与1中的错误相同。
我认为问题可能是某种方式的管理控制台,或者我不知道我做错了什么。任何帮助表示赞赏。
更新1
我现在尝试使用已发布的代理解决方案。
AppDomain domain = AppDomain.CreateDomain("TempDomain");
InstanceProxy proxy = domain.CreateInstanceAndUnwrap(Assembly.GetAssembly(
typeof(InstanceProxy)).FullName, typeof(InstanceProxy).ToString()) as InstanceProxy;
if (proxy != null)
{
proxy.LoadAssembly(path);
}
AppDomain.Unload(domain);
public class InstanceProxy : MarshalByRefObject
{
public void LoadAssembly(string path)
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
Assembly asm = Assembly.LoadFrom(path);
Type[] types = asm.GetExportedTypes();
// ...see above...
}
}
这也不起作用。在尝试创建代理对象时,我得到一个例外:
无法加载文件或程序集“MyProject.SnapIn,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null”或其依赖项之一。系统找不到指定的文件。
错误消息中的文件是加载到mmc(SnapIn)中的文件。知道如何修复此错误吗?不调用AppDomain.AssemblyResolve(在旧域或新域中都没有)。
更新2
我现在尝试使用AppDomainSetup解决方案。现在,异常已更改为:
无法加载文件或程序集'file:/// C:/Development/MyProject/bin/SnapIn/MyProject.SnapIn.DLL'或其依赖项之一。给定的程序集名称或代码库无效。 (来自HRESULT的异常:0x80131047)
有什么想法吗?
答案 0 :(得分:13)
试试这个:
namespace SeperateAppDomainTest
{
class Program
{
static void Main(string[] args)
{
LoadAssembly();
}
public static void LoadAssembly()
{
string pathToDll = Assembly.GetExecutingAssembly().CodeBase;
AppDomainSetup domainSetup = new AppDomainSetup { PrivateBinPath = pathToDll };
var newDomain = AppDomain.CreateDomain("FooBar", null, domainSetup);
ProxyClass c = (ProxyClass)(newDomain.CreateInstanceFromAndUnwrap(pathToDll, typeof(ProxyClass).FullName));
Console.WriteLine(c == null);
Console.ReadKey(true);
}
}
public class ProxyClass : MarshalByRefObject { }
答案 1 :(得分:1)
查看之前的答案:How to load an assembly into different AppDomain on Windows Mobile (.NET CF) ?。该答案创建了一个代理类,它运行到新的AppDomain上下文中,因此,您可以完全控制您的初始化。
您可以在Start()
课程中创建一个ServiceApplicationProxy
方法,并通过proxy.Start()
从您的主持人那里正常调用。
答案 2 :(得分:0)
https://msdn.microsoft.com/en-us/library/3c4f1xde%28v=vs.110%29.aspx
指定
的typeName 键入:System.String
The fully qualified name of the requested type, including the namespace but not the assembly, as returned by the Type.FullName
属性。
请尝试使用完全限定名称进行调用,而不是使用typeof(InstanceProxy).ToString()
使用字符串/文字"<<Namespace>>.InstanceProxy"
如下
InstanceProxy proxy = domain.CreateInstanceAndUnwrap(path, "<<Namespace>>.InstanceProxy") as InstanceProxy;