在自己的应用程序域中加载和卸载程序集
本文关键字:卸载 程序集 加载 自己的 应用程序域 | 更新日期: 2023-09-27 18:37:01
我做通过输入参数加载程序集文件的web.服务。然后在汇编中将尝试查找特定类型(继承自特定接口),创建一个实例并返回该方法的结果。
我需要使调用大会再次被释放。
从该方法的输入参数中,我在 web.config 中找到程序集的路径。 并尝试加载它。
这是有效的代码:
[WebMethod]
public String[] GetData(String confKey)
{
var assemblyPath = ConfigurationManager.AppSettings[confKey];
var assembly = Assembly.LoadFrom(assemblyPath);
List<String> retVals = new List<String>();
foreach (var t in assembly.GetTypes())
{
if (t.ImplementsInterface(typeof(IMyServiceProvider)))
{
IMyServiceProvider objectInstance = Activator.CreateInstance(t) as IMyServiceProvider;
retVals.Add(objectInstance.GetData());
}
}
return retVals.ToArray();
}
但是这样我就可以删除加载的程序集或替换它,因为文件被"锁定"。
所以我尝试采用不同的方式,将程序集加载到自己的 AppDomain 中,如下所示:
[WebMethod]
public String[] GetData(String confKey)
{
var assemblyPath = ConfigurationManager.AppSettings[confKey];
var tmp = String.Concat("AppDomain", Guid.NewGuid().ToString("N"));
AppDomain dom = AppDomain.CreateDomain(tmp, null, AppDomain.CurrentDomain.SetupInformation);
AssemblyName assemblyName = new AssemblyName();
assemblyName.CodeBase = assemblyPath;
Assembly assembly = dom.Load(assemblyPath);
List<String> retVals = new List<String>();
foreach (var t in assembly.GetTypes())
{
if (t.ImplementsInterface(typeof(IMyServiceProvider)))
{
IMyServiceProvider objectInstance = Activator.CreateInstance(t) as IMyServiceProvider;
retVals.Add(objectInstance.GetData());
}
}
AppDomain.Unload(dom);
return retVals.ToArray();
}
但是这个解决方案被抛出异常:
无法加载文件或程序集"NameOfMyAssembly"或其依赖项之一。给定的程序集名称或代码库无效。(HRESULT的例外:0x80131047)- at System.Reflection.AssemblyName.nInit(RuntimeAssembly&assembly, Boolean forIntrospection, Boolean raiseResolveEvent) at System.Reflection.RuntimeAssembly.CreateAssemblyName(String assemblyString, Boolean forIntrospection, RuntimeAssembly&assemblyFromResolveEvent) at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection) at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark&stackMark, Boolean forIntrospection) at System.AppDomain.Load(String assemblyString) at System.AppDomain.Load(String assemblyString)
为什么第一个解决方案程序集加载没有问题,而第二个解决方案组件抛出错误?谢谢
dom.Load(string) 方法尝试按程序集的全名加载程序集,全名由程序集名称、版本、区域性信息和公钥组成。CLR 在 GAC 和应用程序的目录中搜索组件。您还可以使用 .config 文件(app.config 或 )和探测元素设置其他搜索路径。在您的情况下,据我所知,assemblyPath 是您想要加载的程序集的路径,它不需要作为参数传递。我使用下一个代码在创建的域中加载程序集:
var domain = AppDomain.CreateDomain("Plugin domain"); // Domain for plugins
domain.Load(typeof(IPlugin).Assembly.FullName); // Load assembly containing plugin interface to domain
// ...
var asm = Assembly.LoadFrom(pluginFile);
foreach (var exportedType in asm.GetExportedTypes())
{
if (!typeof (IPlugin).IsAssignableFrom(exportedType))
continue; // Check if exportedType implement IPlugin interface
domain.Load(asm.FullName); // If so load this dll into domain
// ...
}
由于所有插件都位于"''Plugins"目录中,因此相对应用程序目录,我还添加了.config文件:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="Plugins"/>
</assemblyBinding>
</runtime>
</configuration>
请注意,如果您抱怨使用dom。Load(AssemblyName) 仅使用指定的代码库属性,您必须将其设置为 Uri 格式(即"file:///D:/Dir/..."),我认为如果这些程序集不在当前应用程序的文件夹中,则必须对其进行强命名。
另外,正如我所看到的,您是usig Activator.CreateInstance()来创建对象。在这种情况下,尽管您在创建的域中加载程序集,但在当前域中创建对象,并且此对象的所有代码也在当前域中执行。要在单独的域中创建和执行代码,您应该使用 appDomain.CreateInstanceAndUnwrap() 方法 (link)