2021-03-07 乐帮网
c# netcore
在Net core中我们可以使用AssemblyLoadContext来实现以前 .NET Framework 中的AppDomain 机制,注意这个在.Net core 2.x版本中是不支持的。下面我就使用AssemblyLoadContext来制作一个示例程序 ,演示一个Net Core站点程序如何从安装插件并且执行插件中的方法。在此之前我们必须安装Visual Studio 2019,示例中的.Net Core使用的是3.1。下面开始我们的代码之旅。
1、首先建立一个Net Core类库,用以协定插件实现的接口约束
我以vkt.plugin.pbase为项目名称建立完成,然后在下面添加接口IPlugin代码下如:
namespace vkt.plugin.pbase
{
public interface IPlugin
{
string Name { get; }
string Description { get; }
string Execute();
}
}
2、建立一个.Net Core公用类库,实现AssemblyLoadContext加载管理
这个我们新建两个类PluginKit 实现动态加载以及动态查找执行方法。PluginLoadContext 实现定制化AssemblyLoadContext,方便做一些处理,代码如下:
public class PluginKit
{
static Assembly LoadPlugin(string relativePath)
{
// Navigate up to the solution root
string root = Path.GetFullPath(Path.Combine(
Path.GetDirectoryName(
Path.GetDirectoryName(
Path.GetDirectoryName(
Path.GetDirectoryName(
Path.GetDirectoryName(typeof(PluginKit).Assembly.Location)))))));
string pluginLocation = Path.GetFullPath(Path.Combine(root, relativePath.Replace('\\', Path.DirectorySeparatorChar)));
Console.WriteLine($"Loading commands from: {pluginLocation}");
PluginLoadContext loadContext = new PluginLoadContext(pluginLocation);
return loadContext.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(pluginLocation)));
}
static IEnumerable<IPlugin> CreateCommands(Assembly assembly)
{
int count = 0;
Type[] typeArray = assembly.GetTypes();
foreach (Type type in typeArray)
{
if (typeof(IPlugin).IsAssignableFrom(type))
{
var result = Activator.CreateInstance(type) as IPlugin;
if (result != null)
{
count++;
yield return result;
}
}
}
if (count == 0)
{
string availableTypes = string.Join(",", assembly.GetTypes().Select(t => t.FullName));
throw new ApplicationException(
$"Can't find any type which implements IPlugin in {assembly} from {assembly.Location}.\n" +
$"Available types: {availableTypes}");
}
}
public static string DynExecute(string name, string[] pluginPaths)
{
Assembly pluginAssembly = LoadPlugin(pluginPaths[0]);
var cc = CreateCommands(pluginAssembly);
IEnumerable<IPlugin> commands = pluginPaths.SelectMany(pluginPath =>
{
Assembly pluginAssembly = LoadPlugin(pluginPath);
return CreateCommands(pluginAssembly);
}).ToList();
IPlugin command = commands.FirstOrDefault(c => c.Name == name);
if (command == null)
{
return "No such command is known.";
}
return command.Execute();
}
}
public class PluginLoadContext : AssemblyLoadContext
{
private AssemblyDependencyResolver _resolver;
public PluginLoadContext(string pluginPath)
{
_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;
}
}
3、编写一个测试插件项目,此项目要引用vkt.plugin.pbase,并且实现里面的接口。
这里我们起名vkt.plugin.msgplugin项目,并且编写三个类,实现三个插件逻辑如下:
public class HelloCommand : IPlugin
{
public string Name { get => "hello"; }
public string Description { get => "Displays hello message."; }
public string Execute()
{
return "Hello !!!";
}
}
public class JsonCommand : IPlugin
{
public string Name { get => "json"; }
public string Description { get => "第三方依赖"; }
public string Execute()
{
return JsonConvert.SerializeObject(new {id=1,name="test",lib= "JsonCommand" });
}
}
public class WorkCommand : IPlugin
{
public string Name { get => "work"; }
public string Description { get => "Good day!"; }
public string Execute()
{
return "I am working !!!";
}
}
4、建立一个站点项目,直接加载并调用插件显示信息
新建一个Net Core Web Pages项目vkt.plugin.web。在首页我们调用插件如下:
public void OnGet()
{
string[] path = new string[]
{
@"D:\Demo\vkt.plugin\vkt.plugin.msgplugin\bin\Debug\netcoreapp3.1\vkt.plugin.msgplugin.dll"
};
Message = PluginKit.DynExecute("json", path);
}
在前台页面上添加Message的显示 <p>from Assembly load method:@Model.Message</p>
注意这里我使用了绝对路径"D:\Demo\vkt.plugin\vkt.plugin.msgplugin\bin\Debug\netcoreapp3.1\vkt.plugin.msgplugin.dll"。
5、修改一下项目文件,并且设置Web项目为启动项目,然后直接运行。
使用记事本打开vkt.plugin.msgplugin.csproj文件,编辑如下:
<ProjectReference Include="..\vkt.plugin.base\vkt.plugin.pbase.csproj">
<Private>false</Private>
<ExcludeAssets>runtime</ExcludeAssets>
</ProjectReference>
下图中红框内的内容为新加。
最后运行效果如下图:
示例代码下载链接:https://pan.baidu.com/s/1PrkF0xhfUdU6ZD0X2B809Q
参考文档:https://docs.microsoft.com/zh-cn/dotnet/core/tutorials/creating-app-with-plugin-support
关注我的微信公众号
在公众号里留言交流
投稿邮箱:1052839972@qq.com
庭院深深深几许?杨柳堆烟,帘幕无重数。
玉勒雕鞍游冶处,楼高不见章台路。
雨横风狂三月暮。门掩黄昏,无计留春住。
泪眼问花花不语,乱红飞过秋千去。
如果感觉对您有帮助
欢迎向作者提供捐赠
这将是创作的最大动力