培训网站建设学校,个人做网站的时代已经过去,个人简历模板下载免费,小程序页面设计报价在 .NET Framework 中#xff0c;通过AppDomain实现动态加载和卸载程序集的效果#xff1b;但是.NET Core 仅支持单个默认应用域#xff0c;那么在.NET Core中如何实现【插件式】开发呢#xff1f;
一、.NET Core 中 AssemblyLoadContext的使用
1、AssemblyLoadContext简…在 .NET Framework 中通过AppDomain实现动态加载和卸载程序集的效果但是.NET Core 仅支持单个默认应用域那么在.NET Core中如何实现【插件式】开发呢
一、.NET Core 中 AssemblyLoadContext的使用
1、AssemblyLoadContext简介
每个 .NET Core 应用程序均隐式使用 AssemblyLoadContext。它是运行时的提供程序用于定位和加载依赖项。只要加载了依赖项就会调用 AssemblyLoadContext 实例来定位该依赖项。 它提供定位、加载和缓存托管程序集和其他依赖项的服务。 为了支持动态代码加载和卸载它创建了一个独立上下文用于在其自己的 AssemblyLoadContext 实例中加载代码及其依赖项。
2、AssemblyLoadContext和AppDomain卸载差异
使用 AssemblyLoadContext 和使用 AppDomain 进行卸载之间存在一个值得注意的差异。对于 Appdomain卸载为强制执行。
卸载时会中止目标 AppDomain 中运行的所有线程会销毁目标 AppDomain 中创建的托管 COM 对象等等。对于 AssemblyLoadContext卸载是“协作式的”。
调用 AssemblyLoadContext.Unload 方法只是为了启动卸载。以下目标达成后卸载完成
1、没有线程将程序集中的方法加载到其调用堆栈上的 AssemblyLoadContext 中。
2、程序集中的任何类型都不会加载到 AssemblyLoadContext这些类型的实例本身由以下引用 AssemblyLoadContext 外部的引用弱引用WeakReference 或 WeakReference除外。 AssemblyLoadContext 内部和外部的强垃圾回收器 (GC) 句柄GCHandleType.Normal 或 GCHandleType.Pinned。
二、.NET Core 插件式方式实现
1、创建可卸载的上下文PluginAssemblyLoadContext
class PluginAssemblyLoadContext : AssemblyLoadContext
{private AssemblyDependencyResolver _resolver;/// summary/// 构造函数/// isCollectible: true 重点允许Unload/// /summary/// param namepluginPath/parampublic PluginAssemblyLoadContext(string pluginPath) : base(isCollectible: true){_resolver new AssemblyDependencyResolver(pluginPath);}protected override Assembly Load(AssemblyName assemblyName){string assemblyPath _resolver.ResolveAssemblyToPath(assemblyName);if (assemblyPath ! null){return LoadFromAssemblyPath(assemblyPath);}return null;}protected override IntPtr LoadUnmanagedDll(string unmanagedDllName){string libraryPath _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);if (libraryPath ! null){return LoadUnmanagedDllFromPath(libraryPath);}return IntPtr.Zero;}
}2、创建插件接口及实现
整体项目结构为 a添加项目PluginInterface插件接口
public interface IPlugin
{string Name { get; }string Description { get; }string Execute(object inPars);
}b添加HelloPlugin项目,实现不引用外部dll插件
public class HelloPlugin : PluginInterface.IPlugin
{public string Name HelloPlugin;public string Description { get Displays hello message.; }public string Execute(object inPars){return (Hello !!! inPars?.ToString()); } }c添加JsonPlugin项目实现引用三方dll插件
public class JsonPlugin : PluginInterface.IPlugin
{public string Name JsonPlugin;public string Description Outputs JSON value.;private struct Info{public string JsonVersion;public string JsonLocation;public string Machine;public DateTime Date;}public string Execute(object inPars){Assembly jsonAssembly typeof(JsonConvert).Assembly;Info info new Info(){JsonVersion jsonAssembly.FullName,JsonLocation jsonAssembly.Location,Machine Environment.MachineName,Date DateTime.Now};return JsonConvert.SerializeObject(info, Formatting.Indented);}
}d添加PluginsApp项目实现调用插件方法
修改窗体界面布局 添加执行方法
/// summary
/// 将此方法标记为noinline很重要否则JIT可能会决定将其内联到Main方法中。
/// 这可能会阻止成功卸载插件因为某些实例的生存期可能会延长到预期卸载插件的时间点之外。
/// /summary
/// param nameassemblyPath/param
/// param nameinPars/param
/// param namealcWeakRef/param
/// returns/returns
[MethodImpl(MethodImplOptions.NoInlining)]
static string ExecuteAndUnload(string assemblyPath, object inPars, out WeakReference alcWeakRef)
{string resultString string.Empty;// 创建 PluginLoadContext对象var alc new PluginAssemblyLoadContext(assemblyPath);//创建一个对AssemblyLoadContext的弱引用允许我们检测卸载何时完成alcWeakRef new WeakReference(alc);// 加载程序到上下文// 注意:路径必须为绝对路径.Assembly assembly alc.LoadFromAssemblyPath(assemblyPath);//创建插件对象并调用foreach (Type type in assembly.GetTypes()){if (typeof(IPlugin).IsAssignableFrom(type)){IPlugin result Activator.CreateInstance(type) as IPlugin;if (result ! null){resultString result.Execute(inPars);break;}}}//卸载程序集上下文alc.Unload();return resultString;
}三、效果验证
1、非引用外部dll的插件执行执行后对应dll成功卸载程序集数量未增加。 2、引用外部包的插件执行后对应dll未卸载程序集数量增加。 通过监视查看对象状态该上下文在卸载中。暂未找到原因卸载失败疑问 四、总结
虽然微软文档说.NET Core中使用AssemblyLoadContext来实现程序集的加载及卸载实现但通过验证在加载引用外部dll后加载后不能正常卸载。或者使用方式还不正确。
源码地址https://github.com/cwsheng/PluginsApp