>国内 >

全球微动态丨【Dotnet 工具箱】DotNetCorePlugins- 动态加载和卸载 .NET 程序插件

时间:2023-05-08 09:46:34       来源:博客园

你好,这里是 Dotnet 工具箱,定期分享 Dotnet 有趣,实用的工具和组件,希望对您有用!


(资料图)

1. DotNetCorePlugins- 动态加载和卸载 .NET 程序插件

DotNetCorePlugins 是一个 .NET 的开源插件项目,它提供了能够动态加载程序集的 API,然后把它们作为 .NET 主程序的扩展程序执行。

这个库主要用到了 AssemblyLoadContext技术, System.Runtime.Loader.AssemblyLoadContext,又名 ALC,提供了一些用于定义动态程序集加载行为的基本 API。这是 .NET Core 中我最喜欢但鲜为人知的 API 之一。

如何使用?

安装 McMaster.NETCore.PluginsNuGet 包。

dotnet add package McMaster.NETCore.Plugins

主要使用的 API 是 PluginLoader.CreateFromAssemblyFile, 它允许从文件中读取并加载程序集。

PluginLoader.CreateFromAssemblyFile(    assemblyFile: "./plugins/MyPlugin/MyPlugin1.dll",    sharedTypes: new [] { typeof(IPlugin), typeof(IServiceCollection), typeof(ILogger) },    isUnloadable: true)
assemblyFile = 插件 .dll 的文件路径sharedTypes = 加载程序的统一的类型列表isUnloadable = 允许这个插件在将来的某个时候从内存中卸载。

定义接口

这是一个示例,我们定义了一个接口,里面包含了 GetName, 如下

public interface IPlugin{    string GetName();}

对于插件,我们直接使用这个接口并进行实现,如下

internal class MyPlugin1 : IPlugin{    public string GetName() => "My plugin v1";}

对于主程序,我们可以使用 PluginLoaderAPI 来加载插件,程序需要使用查找磁盘中的插件程序集。一种方式是基于约定的,比如

plugins/    $PluginName1/        $PluginName1.dll        (additional plugin files)    $PluginName2/        $PluginName2.dll

每个插件都发布到一个单独的目录中,这样可以避免插件之间的争用和重复的依赖问题。

以通过运行下面的命令,输出插件到文件夹中。

dotnet publish MyPlugin1.csproj --output plugins/MyPlugin1/

接下来,我们可以通过反射获取所有的插件,并进行加载, 代码如下

using McMaster.NETCore.Plugins;var loaders = new List();// create plugin loadersvar pluginsDir = Path.Combine(AppContext.BaseDirectory, "plugins");foreach (var dir in Directory.GetDirectories(pluginsDir)){    var dirName = Path.GetFileName(dir);    var pluginDll = Path.Combine(dir, dirName + ".dll");    if (File.Exists(pluginDll))    {        var loader = PluginLoader.CreateFromAssemblyFile(            pluginDll,            sharedTypes: new [] { typeof(IPlugin) });        loaders.Add(loader);    }}// Create an instance of plugin typesforeach (var loader in loaders){    foreach (var pluginType in loader        .LoadDefaultAssembly()        .GetTypes()        .Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsAbstract))    {         IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType);        Console.WriteLine($"Created plugin instance "{plugin.GetName()}".");    }}

支持 MVC 和 Razor

另外插件还支持加载 MVC 的 Controller 和 Razor Pages。通过安装下面的 Nuget 包。

dotnet add package McMaster.NETCore.Plugins.Mvc

加载程序集的方法如下:

public class Startup{    public void ConfigureServices(IServiceCollection services)    {        var pluginFile = Path.Combine(AppContext.BaseDirectory, "plugins/MyRazorPlugin/MyRazorPlugin.dll");        services            .AddMvc()             .AddPluginFromAssemblyFile(pluginFile);    }}

更多插件的使用方法,作者提供了一些示例项目,可以进行参考。

https://github.com/natemcmaster/DotNetCorePlugins

2. 推荐一个强大高效的开源 .NET 访问控制组件Casbin 简介

Casbin 是一个强大高效的开源访问控制库,支持各种 访问控制模型 , 如 ACL, RBAC, ABAC 等。

我们希望可以让指定的主体 subject,可以访问指定的资源 object,访问可以是读和写。这就是 Casbin 使用最广泛的方式。也称为 { subject, object, action }流程。

另外,Casbin 能够处理标准流程以外的许多复杂授权场景,还支持添加 RBAC 和 ABAC 等。

Casbin 能做什么?{ subject, object, action } 定义访问策略,支持允许和拒绝授权。处理访问控制模型和策略的存储。管理角色-用户映射和角色-角色映射(也称为 RBAC 中的角色层次结构)。支持内置超级用户,例如rootadministrator。超级用户可以在没有明确许可的情况下做任何事情。内置多种运算符,支持规则匹配。例如,keyMatch可以将资源键映射/foo/bar到模式/foo*。Casbin 不做的事用户身份验证。管理用户和角色列表。Casbin 支持的语言

Casbin 提供对各种编程语言的支持,可以集成到任何项目和工作流程中:

它是怎么运行的?

在Casbin中,基于PERM元模型 (Policy, Effect, Request, Matchers)将一个访问控制模型抽象成一个CONF文件。

所以切换或升级项目的授权机制就像修改配置一样简单。

Casbin中 最基本最简单的模型就是ACL。ACL 的模型 CONF 是:

# Request definition[request_definition]r = sub, obj, act# Policy definition[policy_definition]p = sub, obj, act# Policy effect[policy_effect]e = some(where (p.eft == allow))# Matchers[matchers]m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

ACL 模型的示例策略如下:

p, alice, data1, readp, bob, data2, write

它的意思是:

alice 可以读取 data1.bob 可以写入 data2。如何使用?

首先,需要安装 Casbin.NET。

dotnet add package Casbin.NET
使用模型文件和策略文件新建一个 Casbin 执行器:
var e = new Enforcer("path/to/model.conf", "path/to/policy.csv")

注意:这里您还可以使用数据库中的策略而不是文件来初始化执行器。

在进行资源访问的时候,使用下面的授权代码。
var sub = "alice";  # 想要访问资源的用户var obj = "data1";  # 将要被访问的资源var act = "read";  # 用户对资源进行的操作if (await e.EnforceAsync(sub, obj, act)) {    // 允许alice读取data1}else{    // 拒绝请求,抛出异常}

https://github.com/casbin/Casbin.NET

关键词: