.NET Core中插件式开发实现

但是.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 方法只是为了启动卸载。以下目标达成后,卸载完成:

没有线程将程序集中的方法加载到其调用堆栈上的 AssemblyLoadContext 中。
程序集中的任何类型都不会加载到 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 name="pluginPath"></param>
public 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项目,实现调用插件方法:

修改窗体界面布局:

添加执行方法

复制代码
///
/// 将此方法标记为noinline很重要,否则JIT可能会决定将其内联到Main方法中。
/// 这可能会阻止成功卸载插件,因为某些实例的生存期可能会延长到预期卸载插件的时间点之外。
///
///
///
///
///
[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;

}

USB Microphone https://www.soft-voice.com/
Wooden Speakers https://www.zeshuiplatform.com/
亚马逊测评 www.yisuping.cn
深圳网站建设www.sz886.com

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值