将 DLL 动态加载到分离的应用程序域中然后卸载
Loading DLL dynamically into separated app domain then unload
我正在尝试将 DLL 文件加载到单独的应用程序域中并调用 DLL 文件中的方法并从中获得一些响应。应用程序启动时,项目 bin
文件夹中不存在 DLL 文件,从另一个文件夹加载 DLL 文件。完成 DLL 文件后,我想卸载刚刚创建的应用程序域。
步骤:
- 创建了一个新的应用域
- 加载我想要的DLL到app域
- 调用方法并获得响应
- 卸载应用域
这是我到目前为止尝试过的方法
这是MyAssembly.dll
中的代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace MyAssembly
{
public class MyClass
{
public static string MyMethod()
{
return "Hello there, this is message from MyAssembly";
}
}
}
这是我加载 DLL 文件的方式
using System.Diagnostic;
using System.IO;
private class ProxyClass : MarshalByRefObject
{
public void LoadAssembly()
{
AppDomain dom;
string domainName = "new:" + Guid.NewGuid();
try
{
//Create the app domain
dom = AppDomain.CreateDomain(domainName, null, new AppDomainSetup
{
PrivateBinPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"),
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
ShadowCopyFiles = "true",
ShadowCopyDirectories = "true",
LoaderOptimization = LoaderOptimization.SingleDomain,
});
string dllPath = @"C:\MyProject\MyAssembly.dll";//the path to my assembly file I want to load
//load the assembly to the new app domain
Assembly asm = dom.Load(File.ReadAllBytes(dllPath));//Error occurred at here
Type baseClass = asm.GetType("MyAssembly.MyClass");
MethodInfo targetMethod = baseClass.GetMethod("MyMethod");
string result = targetMethod.Invoke(null, new object[]{});
/*Do something to the result*/
}
catch(Exception ex)
{
Debug.WriteLine(ex.Message);
Debug.WriteLine(ex.ToString());
}
finally
{
//Finally unload the app domain
if (dom != null) AppDomain.Unload(dom);
}
}
}
public void BeginLoadDll()
{
ProxyClass proxy = new ProxyClass();
proxy.LoadAssembly();
//OR like this, which gave me same error message as well
//var dom = AppDomain.CreateDomain("new:" + Guid.NewGuid(), null, new AppDomainSetup
// {
// PrivateBinPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"),
// ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
// ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
// ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
// ShadowCopyFiles = "true",
// ShadowCopyDirectories = "true",
// LoaderOptimization = LoaderOptimization.SingleDomain,
// });
//ProxyClass proxy = (ProxyClass)dom.CreateInstanceAndUnwrap(
// typeof(ProxyClass).Assembly.FullName, typeof(ProxyClass).FullName);
//pr.LoadAssembly(watcherData, filePath);
}
这是我到目前为止观察到的一些东西,我不确定这是否只是我的感受,还是我遗漏了什么
-如果应用程序启动前项目bin文件夹中存在"MyAssembly.dll",我可以加载dll文件
-如果 "MyAssembly.dll" 在应用程序启动前不存在于项目 bin 文件夹中,而是加载到项目 bin 文件夹以外的其他地方,我无法加载 dll 文件。例如项目bin文件夹为"C:\Main\MyMainProject\MyMainProject\bin",DLL从C:\MyProject\MyAssembly.dll
加载
-如果我将 "MyAssembly.dll" 文件移动到 bin 文件夹中(使用 File.Copy()
或 File.Move()
),它会以某种方式停止要执行的其余代码。
我收到的错误信息
Could not load file or assembly 'MyAssembly, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=2c20c56a5e1f4bd4' or one of its dependencies.
The system cannot find the file specified.
编辑
我知道我可以使用 Assembly.LoadFrom(@"PATH\TO\MY\DLL")
,但是这个问题是我无法卸载 DLL
经过几天的研究,我终于让它工作了。下面是我的最终工作代码。
帮助我实现这一目标的有用参考链接
C# reflection - load assembly and invoke a method if it exists
Using AppDomain in C# to dynamically load and unload dll
MyAssembly.dll中的代码与问题中的相同。我还意识到我也可以 return 对象类型。
如何将 DLL 文件加载到分离的应用程序域中并卸载应用程序域
public void MethodThatLoadDll()
{
AppDomain dom = null;
//declare this outside the try-catch block, so we can unload it in finally block
try
{
string domName = "new:" + Guid.NewGuid();
//assume that the domName is "new:50536e71-51ad-4bad-9bf8-67c54382bb46"
//create the new domain here instead of in the proxy class
dom = AppDomain.CreateDomain(, null, new AppDomainSetup
{
PrivateBinPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"),
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
ShadowCopyFiles = "true",
ShadowCopyDirectories = "true",/*yes they are string value*/
LoaderOptimization = LoaderOptimization.SingleDomain,
DisallowBindingRedirects = false,
DisallowCodeDownload = true,
});
ProxyClass proxy = (ProxyClass)dom.CreateInstanceAndUnwrap(
typeof(ProxyClass).Assembly.FullName, typeof(ProxyClass).FullName);
string result = proxy.ExecuteAssembly("MyParam");
/*Do whatever to the result*/
}
catch(Exception ex)
{
//handle the error here
}
finally
{
//finally unload the app domain
if(dom != null) AppDomain.Unload(dom);
}
}
我的class继承了MarshalByRefObject
private class ProxyClass : MarshalByRefObject
{
//you may specified any parameter you want, if you get `xxx is not marked as serializable` error, see explanation below
public string ExecuteAssembly(string param1)
{
/*
* All the code executed here is under the new app domain that we just created above
* We also have different session state here, so if you want data from main domain's session, you should pass it as a parameter
*/
//load your DLL file here
Debug.WriteLine(AppDomain.CurrentDomain.FriendlyName);
//will print "new:50536e71-51ad-4bad-9bf8-67c54382bb46" which is the name that we just gave to the new created app domain
Assembly asm = Assembly.LoadFrom(@"PATH/TO/THE/DLL");
Type baseClass = asm.GetType("MyAssembly.MyClass");
MethodInfo targetMethod = baseClass.GetMethod("MyMethod");
string result = targetMethod.Invoke(null, new object[]{});
return result;
}
}
您可能 运行 陷入
的常见错误
'xxx' is not marked as serializable
如果您尝试将自定义 class 作为参数传递,可能会发生这种情况,例如
public void ExecuteAssembly(MyClass param1)
这种情况下,放一个[Serializable]
到MyClass
,像这样
[Serializable]
public class MyClass { }
我正在尝试将 DLL 文件加载到单独的应用程序域中并调用 DLL 文件中的方法并从中获得一些响应。应用程序启动时,项目 bin
文件夹中不存在 DLL 文件,从另一个文件夹加载 DLL 文件。完成 DLL 文件后,我想卸载刚刚创建的应用程序域。
步骤:
- 创建了一个新的应用域
- 加载我想要的DLL到app域
- 调用方法并获得响应
- 卸载应用域
这是我到目前为止尝试过的方法
这是MyAssembly.dll
中的代码using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace MyAssembly
{
public class MyClass
{
public static string MyMethod()
{
return "Hello there, this is message from MyAssembly";
}
}
}
这是我加载 DLL 文件的方式
using System.Diagnostic;
using System.IO;
private class ProxyClass : MarshalByRefObject
{
public void LoadAssembly()
{
AppDomain dom;
string domainName = "new:" + Guid.NewGuid();
try
{
//Create the app domain
dom = AppDomain.CreateDomain(domainName, null, new AppDomainSetup
{
PrivateBinPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"),
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
ShadowCopyFiles = "true",
ShadowCopyDirectories = "true",
LoaderOptimization = LoaderOptimization.SingleDomain,
});
string dllPath = @"C:\MyProject\MyAssembly.dll";//the path to my assembly file I want to load
//load the assembly to the new app domain
Assembly asm = dom.Load(File.ReadAllBytes(dllPath));//Error occurred at here
Type baseClass = asm.GetType("MyAssembly.MyClass");
MethodInfo targetMethod = baseClass.GetMethod("MyMethod");
string result = targetMethod.Invoke(null, new object[]{});
/*Do something to the result*/
}
catch(Exception ex)
{
Debug.WriteLine(ex.Message);
Debug.WriteLine(ex.ToString());
}
finally
{
//Finally unload the app domain
if (dom != null) AppDomain.Unload(dom);
}
}
}
public void BeginLoadDll()
{
ProxyClass proxy = new ProxyClass();
proxy.LoadAssembly();
//OR like this, which gave me same error message as well
//var dom = AppDomain.CreateDomain("new:" + Guid.NewGuid(), null, new AppDomainSetup
// {
// PrivateBinPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"),
// ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
// ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
// ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
// ShadowCopyFiles = "true",
// ShadowCopyDirectories = "true",
// LoaderOptimization = LoaderOptimization.SingleDomain,
// });
//ProxyClass proxy = (ProxyClass)dom.CreateInstanceAndUnwrap(
// typeof(ProxyClass).Assembly.FullName, typeof(ProxyClass).FullName);
//pr.LoadAssembly(watcherData, filePath);
}
这是我到目前为止观察到的一些东西,我不确定这是否只是我的感受,还是我遗漏了什么
-如果应用程序启动前项目bin文件夹中存在"MyAssembly.dll",我可以加载dll文件
-如果 "MyAssembly.dll" 在应用程序启动前不存在于项目 bin 文件夹中,而是加载到项目 bin 文件夹以外的其他地方,我无法加载 dll 文件。例如项目bin文件夹为"C:\Main\MyMainProject\MyMainProject\bin",DLL从C:\MyProject\MyAssembly.dll
加载-如果我将 "MyAssembly.dll" 文件移动到 bin 文件夹中(使用 File.Copy()
或 File.Move()
),它会以某种方式停止要执行的其余代码。
我收到的错误信息
Could not load file or assembly 'MyAssembly, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=2c20c56a5e1f4bd4' or one of its dependencies.
The system cannot find the file specified.
编辑
我知道我可以使用 Assembly.LoadFrom(@"PATH\TO\MY\DLL")
,但是这个问题是我无法卸载 DLL
经过几天的研究,我终于让它工作了。下面是我的最终工作代码。
帮助我实现这一目标的有用参考链接
C# reflection - load assembly and invoke a method if it exists
Using AppDomain in C# to dynamically load and unload dll
MyAssembly.dll中的代码与问题中的相同。我还意识到我也可以 return 对象类型。
如何将 DLL 文件加载到分离的应用程序域中并卸载应用程序域
public void MethodThatLoadDll()
{
AppDomain dom = null;
//declare this outside the try-catch block, so we can unload it in finally block
try
{
string domName = "new:" + Guid.NewGuid();
//assume that the domName is "new:50536e71-51ad-4bad-9bf8-67c54382bb46"
//create the new domain here instead of in the proxy class
dom = AppDomain.CreateDomain(, null, new AppDomainSetup
{
PrivateBinPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"),
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
ShadowCopyFiles = "true",
ShadowCopyDirectories = "true",/*yes they are string value*/
LoaderOptimization = LoaderOptimization.SingleDomain,
DisallowBindingRedirects = false,
DisallowCodeDownload = true,
});
ProxyClass proxy = (ProxyClass)dom.CreateInstanceAndUnwrap(
typeof(ProxyClass).Assembly.FullName, typeof(ProxyClass).FullName);
string result = proxy.ExecuteAssembly("MyParam");
/*Do whatever to the result*/
}
catch(Exception ex)
{
//handle the error here
}
finally
{
//finally unload the app domain
if(dom != null) AppDomain.Unload(dom);
}
}
我的class继承了MarshalByRefObject
private class ProxyClass : MarshalByRefObject
{
//you may specified any parameter you want, if you get `xxx is not marked as serializable` error, see explanation below
public string ExecuteAssembly(string param1)
{
/*
* All the code executed here is under the new app domain that we just created above
* We also have different session state here, so if you want data from main domain's session, you should pass it as a parameter
*/
//load your DLL file here
Debug.WriteLine(AppDomain.CurrentDomain.FriendlyName);
//will print "new:50536e71-51ad-4bad-9bf8-67c54382bb46" which is the name that we just gave to the new created app domain
Assembly asm = Assembly.LoadFrom(@"PATH/TO/THE/DLL");
Type baseClass = asm.GetType("MyAssembly.MyClass");
MethodInfo targetMethod = baseClass.GetMethod("MyMethod");
string result = targetMethod.Invoke(null, new object[]{});
return result;
}
}
您可能 运行 陷入
的常见错误'xxx' is not marked as serializable
如果您尝试将自定义 class 作为参数传递,可能会发生这种情况,例如
public void ExecuteAssembly(MyClass param1)
这种情况下,放一个[Serializable]
到MyClass
,像这样
[Serializable]
public class MyClass { }