插件化编程实现的一份糖炒栗子~~

迷茫的原因是因为想得太多,做得太少。因为只是 想 真的很容易,转瞬之间就会产生无数个念头,或许是该做点什么了吧。

但是整个人都是懒的,是废的,是大脑控制不住自己的行为的。解决方案唯有一步一步的去把行为变成习惯。

坚持一件事挺不容易的,不论结果的好坏,过程中总有收获的,坚持,不会是一件坏事。

胡言乱语结束~~~

下面是记录分享的一点东西~~请笑纳

0.结构一览

  

1.定义插件接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace YimoCore
{public interface IPlugin{/// <summary>/// Gets or sets the plugin descriptor/// </summary>PluginDescriptor PluginDescriptor { get; set; }/// <summary>/// Install plugin/// </summary>void Install();/// <summary>/// Uninstall plugin/// </summary>void Uninstall();}
}
定义插件

2.添加插件信息类

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;namespace YimoCore
{/// <summary>/// 插件信息/// </summary>public sealed class PluginDescriptor{/// <summary>/// 插件主目录/// </summary>public string PluginFileName { get; set; }/// <summary>/// 插件类型/// </summary>public Type PluginType { get; set; }/// <summary>/// 插件主程序集/// </summary>public Assembly ReferencedAssembly { get; internal set; }/// <summary>/// 原始程序集文件/// </summary>public FileInfo OriginalAssemblyFile { get; internal set; }/// <summary>/// 插件包目录/// </summary>public FileInfo PluginConfigFile { get; internal set; }/// <summary>/// 类别/// </summary>public string Group { get; set; }/// <summary>/// 插件名称/// </summary>public string FriendlyName { get; set; }/// <summary>/// 程序集名称/// </summary>public string SystemName { get; set; }/// <summary>/// 描述/// </summary>public string Description { get; set; }/// <summary>/// 版本号/// </summary>public string Version { get; set; }/// <summary>/// 支持版本/// </summary>public IList<string> SupportedVersions { get; set; }/// <summary>/// 作者/// </summary>public string Author { get; set; }/// <summary>/// 排序/// </summary>public int DisplayOrder { get; set; }/// <summary>/// 获取插件实例/// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>public T Instance<T>() where T : class, IPlugin{var instance = Activator.CreateInstance(PluginType) as T;if (instance != null)instance.PluginDescriptor = this;return instance;}public IPlugin Instance(){return Instance<IPlugin>();}public int CompareTo(PluginDescriptor other){if (DisplayOrder != other.DisplayOrder)return DisplayOrder.CompareTo(other.DisplayOrder);elsereturn System.String.Compare(FriendlyName, other.FriendlyName, System.StringComparison.Ordinal);}public override string ToString(){return FriendlyName;}public override bool Equals(object obj){var other = obj as PluginDescriptor;return other != null &&SystemName != null &&SystemName.Equals(other.SystemName);}public override int GetHashCode(){return SystemName.GetHashCode();}}
}
插件信息类

3.插件读取

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web;namespace YimoCore
{public class PluginManager{private const string PluginsPath = "/modules"; //插件目录private const string ShadowCopyPath = "/modules/bin"; //插件影子目录public static IEnumerable<PluginDescriptor> ReferencedPlugins { get; set; }public static void Init(){var appdir = AppDomain.CurrentDomain.BaseDirectory.Substring(0, AppDomain.CurrentDomain.BaseDirectory.LastIndexOf("\\"));appdir = appdir.Substring(0, appdir.LastIndexOf("\\"));appdir = appdir.Substring(0, appdir.LastIndexOf("\\"));//插件目录var pluginFolder = new DirectoryInfo(appdir + PluginsPath);//插件bin目录var shadowFolder = new DirectoryInfo(appdir + ShadowCopyPath);var referencedPlugins = new List<PluginDescriptor>();try{pluginFolder.Create();shadowFolder.Create();//清空bin目录foreach (var fileInfo in shadowFolder.GetFiles()){fileInfo.Delete();}var pluginConfigFiles = pluginFolder.GetFiles("about.xml", SearchOption.AllDirectories);foreach (var pluginConfigFile in pluginConfigFiles){//获取插件信息var pluginDescriptor = PluginFileParser.ParsePluginDescriptionFile(pluginConfigFile.FullName);try{if (pluginConfigFile.Directory == null)continue;//获取插件所有的dllvar pluginFiles = pluginConfigFile.Directory.GetFiles("*.dll", SearchOption.AllDirectories);var mainPluginFile = pluginFiles.FirstOrDefault(item =>item.Name.Equals(pluginDescriptor.PluginFileName,StringComparison.InvariantCultureIgnoreCase));pluginDescriptor.PluginConfigFile = pluginConfigFile;pluginDescriptor.OriginalAssemblyFile = mainPluginFile;pluginDescriptor.ReferencedAssembly = DeployDllFile(mainPluginFile, shadowFolder);foreach (var t in pluginDescriptor.ReferencedAssembly.GetTypes()){if (typeof(IPlugin).IsAssignableFrom(t)){if (t.IsInterface == false && t.IsClass && !t.IsAbstract){pluginDescriptor.PluginType = t;break;}}}referencedPlugins.Add(pluginDescriptor);}catch (ReflectionTypeLoadException ex){throw;}}}catch (ReflectionTypeLoadException ex){}ReferencedPlugins = referencedPlugins;}/// <summary>/// 部署程序集/// </summary>/// <param name="dllFile">插件程序集文件</param>/// <param name="shadowFolder">/Plugins/bin目录</param>private static Assembly DeployDllFile(FileInfo dllFile, DirectoryInfo shadowFolder){DirectoryInfo copyFolder;//根据当前的信任级别设置复制目录
copyFolder = shadowFolder;var newDllFile = new FileInfo(copyFolder.FullName + "\\" + dllFile.Name);try{File.Copy(dllFile.FullName, newDllFile.FullName, true);}catch (Exception ex1)//在某些情况下会出现"正由另一进程使用,因此该进程无法访问该文件"错误,所以先重命名再复制
            {try{File.Move(newDllFile.FullName, newDllFile.FullName + Guid.NewGuid().ToString("N") + ".locked");}catch (Exception ex2){throw ex2;}File.Copy(dllFile.FullName, newDllFile.FullName, true);}var assembly = Assembly.LoadFrom(newDllFile.FullName);//将程序集添加到当前应用程序域//BuildManager.AddReferencedAssembly(assembly);return assembly;}}
}
插件读取
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;namespace YimoCore
{/// <summary>/// Plugin files parser/// </summary>public static class PluginFileParser{public static IList<string> ParseInstalledPluginsFile(string filePath){if (!File.Exists(filePath))return new List<string>();var text = File.ReadAllText(filePath);if (String.IsNullOrEmpty(text))return new List<string>();var lines = new List<string>();using (var reader = new StringReader(text)){string str;while ((str = reader.ReadLine()) != null){if (String.IsNullOrWhiteSpace(str))continue;lines.Add(str.Trim());}}return lines;}public static void SaveInstalledPluginsFile(IList<String> pluginSystemNames, string filePath){if (pluginSystemNames == null || pluginSystemNames.Count == 0)return;string result = "";foreach (var sn in pluginSystemNames)result += string.Format("{0}{1}", sn, Environment.NewLine);File.WriteAllText(filePath, result);}public static PluginDescriptor ParsePluginDescriptionFile(string filePath){XDocument doc;try{doc = XDocument.Load(filePath);}catch (Exception){return null;}var pluginEle = doc.Element("plugin");if (pluginEle == null)return null;var descriptor = new PluginDescriptor();var ele = pluginEle.Element("SystemName");if (ele != null)descriptor.SystemName = ele.Value;ele = pluginEle.Element("Group");if (ele != null)descriptor.Group = ele.Value;ele = pluginEle.Element("FriendlyName");if (ele != null)descriptor.FriendlyName = ele.Value;ele = pluginEle.Element("Description");if (ele != null)descriptor.Description = ele.Value;ele = pluginEle.Element("Version");if (ele != null)descriptor.Version = ele.Value;ele = pluginEle.Element("SupportedVersions");if (ele != null){//parse supported versionsdescriptor.SupportedVersions = ele.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList();}ele = pluginEle.Element("Author");if (ele != null)descriptor.Author = ele.Value;ele = pluginEle.Element("DisplayOrder");if (ele != null){int displayOrder;int.TryParse(ele.Value, out displayOrder);descriptor.DisplayOrder = displayOrder;}ele = pluginEle.Element("FileName");if (ele != null)descriptor.PluginFileName = ele.Value;if (descriptor.SupportedVersions.Count == 0)descriptor.SupportedVersions.Add("2.00");return descriptor;}public static void SavePluginDescriptionFile(PluginDescriptor plugin){if (plugin == null)throw new ArgumentException("plugin");if (plugin.PluginConfigFile == null)throw new Exception(string.Format("没有加载插件 {0} 的配置文件", plugin.SystemName));var doc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),new XElement("Group", plugin.Group),new XElement("FriendlyName", plugin.FriendlyName),new XElement("SystemName", plugin.SystemName),new XElement("Description", plugin.Description),new XElement("Version", plugin.Version),new XElement("SupportedVersions", string.Join(",", plugin.SupportedVersions)),new XElement("Author", plugin.Author),new XElement("DisplayOrder", plugin.DisplayOrder),new XElement("FileName", plugin.PluginFileName));doc.Save(plugin.PluginConfigFile.FullName);}}
}
加载插件-PluginFileParser

 

4.使用

  4.0新建插件接口并继承IPlugin

  

  4.1:为插件类库添加about.xml文件配置插件信息

<?xml version="1.0" encoding="utf-8" ?>
<plugin><Group>Sign</Group><FriendlyName>素材网</FriendlyName><SystemName>素材网</SystemName><Description>素材网签到</Description><Version>1.0</Version><SupportedVersions>1.0</SupportedVersions><Author>YiMo</Author><DisplayOrder>1</DisplayOrder><FileName>素材网.dll</FileName>
</plugin>
View Code

  4.2在插件类库中实现ISign接口 (这里需要将PluginDescriptor字段实现)  

  

  4.3:修改插件所在类库的生成事件 工具下载

  

  生成......

  4.4:生成解决方案后,就可以愉快的使用了

  

  

Over~~~完整Demo 代码下载。 

 

最后附上使用上述方式写的的一个签到程序:https://github.com/yimogit/YimoCustomizedSign

 

现已经实现三个网站的的一键签到。后续会实现更多网站的签到功能等~~

跪求路过的大牛指点一二,也极度希望有人能和我一起来探讨,优化,扩展这个小软件和 更多更多更多的想法。

无论如何,每天都要进步一点点,基础再牢一点,效率再高一点,代码再风骚一点,生活再开心一点。每天只要一点点就好。

 

转载于:https://www.cnblogs.com/morang/p/5630609.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/372718.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用C#来学习唐诗三百首和全唐诗

Begin 最近把项目做完了&#xff0c;闲来无事&#xff0c;就想做点好玩的事情&#xff0c;刚好前几天下载了【唐诗三百首】和【全唐诗】这两个txt文件&#xff0c;正好用C#来整理一下。 然后导出QData格式&#xff0c;可以给其他软件读取。 以后弄个开机自动显示一句诗&#xf…

sts java配置tomcat_STS配置Tomcat.9.0

今天&#xff0c;心血来潮&#xff0c;弄了一下STS,按着建立WEB项目的方式建立工程。一、新建工程(FILE --NEW--Dynamic Web project)二、输入项目名称&#xff0c;TestWeb&#xff0c;然后下一步&#xff0c;点击FInish.三、新建index.jsp并打开index.jsp,书写测试成功&#x…

javaweb国际化

根据数据的类型不同&#xff0c;国际化分为2类&#xff1a;静态数据国际化和动态数据的国际化。 静态数据&#xff0c;包括 “标题”、“用户名”、“密码”这样的文字数据。 动态数据&#xff0c;包括日期、货币等可以动态生成的数据。 国际化涉及到java.util.Locale和java.ut…

20145335郝昊《网络攻防》Bof逆向基础——ShellCode注入与执行

20145335郝昊《网络攻防》Bof逆向基础——ShellCode注入与执行 实验原理 关于ShellCode&#xff1a;ShellCode是一段代码&#xff0c;作为数据发送给受攻击服务器&#xff0c;是溢出程序和蠕虫病毒的核心&#xff0c;一般可以获取权限。我们将代码存储到对方的堆栈中&#xff0…

玩转Android之加速度传感器的使用,模仿微信摇一摇

Android系统带的传感器有很多种&#xff0c;最常见的莫过于微信的摇一摇了&#xff0c;那么今天我们就来看看Anroid中传感器的使用&#xff0c;做一个类似于微信摇一摇的效果。 OK ,废话不多说&#xff0c;我们就先来看看效果图吧&#xff1a; 当我摇动手机的时候这里的动画效果…

Java两种设计模式_23种设计模式(11)java策略模式

23种设计模式第四篇&#xff1a;java策略模式定义&#xff1a;定义一组算法&#xff0c;将每个算法都封装起来&#xff0c;并且使他们之间可以互换。类型&#xff1a;行为类模式类图&#xff1a;策略模式是对算法的封装&#xff0c;把一系列的算法分别封装到对应的类中&#xf…

JAXB自定义绑定– Java.util.Date / Spring 3序列化

JaxB可以处理Java.util.Date序列化&#xff0c;但是需要以下格式&#xff1a; “ yyyy-MM-ddTHH&#xff1a;mm&#xff1a;ss ”。 如果需要将日期对象格式化为另一种格式怎么办&#xff1f; 我有同样的问题时&#xff0c;我正在同春MVC 3和Jackson JSON处理器 &#xff0c;最…

双足机器人简单步态生成

让机器人行走最简单的方法是先得到一组步态曲线&#xff0c;即腿部每个关节随时间运动的角度值。可以在ADAMS或3D Max、Blender等软件中建立好机构/骨骼模型&#xff0c;设计出脚踝和髋关节的运动曲线&#xff0c;然后进行逆运动学解算&#xff0c;测量每个关节在运动过程中的转…

重新访问了访客模式

访客模式是面向对象设计中最被高估但又被低估的模式之一。 高估了它&#xff0c;因为它常常被选择得太快&#xff08; 可能是由建筑宇航员选择的 &#xff09;&#xff0c;然后以错误的方式添加时会膨胀本来非常简单的设计。 如果您不遵循教科书示例&#xff0c;那么它可能会非…

ASP.NET—013:实现带控件的弹出层(弹出框)

http://blog.csdn.net/yysyangyangyangshan/article/details/38458169 在页面中用到弹出新页面的情况比较多的&#xff0c;一般来说都是使用JS方法showModalDialog("新页面相对路径?参数1&参数2",window,"新页面样式");然后会新弹出一个模态的page页。…

java 二进制 归属权限_【Java EE 学习 75 上】【数据采集系统第七天】【二进制运算实现权限管理】【权限分析和设计】...

一、权限计算相关分析1.如何存储权限首先说一下权限保存的问题&#xff0c;一个系统中最多有多少权限呢&#xff1f;一个大的系统中可能有成百上千个权限需要管理。怎么保存这么多的权限&#xff1f;首先&#xff0c;我们使用一个数字中的一位保存一种权限&#xff0c;那么如果…

GWT和HTML5 Canvas演示

这是我对GWT和HTML5 Canvas的第一个实验。 我的第一个尝试是创建矩形&#xff0c;仅用几行代码就得出了这样的内容&#xff1a; 码&#xff1a; public class GwtHtml5 implements EntryPoint {static final String canvasHolderId "canvasholder";static final St…

Solr管理界面详解

转载于:https://www.cnblogs.com/gslblog/p/6553813.html

一个实用的却被忽略的命名空间:Microsoft.VisualBasic:

当你看到这个命名空间的时候&#xff0c;别因为是vb的东西就匆忙关掉网页&#xff0c;那将会是您的损失&#xff0c;此命名空间中的资源最初目的是为了简化vb.net开发而创建的&#xff0c;所以microsoft.visualbasic并不属于system命名空间&#xff0c;而是独立存在的。虽然是为…

Linux基础之命令练习Day2-useradd(mod,del),groupadd(mod,del),chmod,chown,

作业一&#xff1a; 1) 新建用户natasha&#xff0c;uid为1000&#xff0c;gid为555&#xff0c;备注信息为“master” 2) 修改natasha用户的家目录为/Natasha 3) 查看用户信息配置文件的最后一行 4) 为natasha用户设置密码“123” 5) 查看用户密码配置文件的最后一行 6) 将nat…

动态表单,JSF世界早已等待

新的PrimeFaces扩展版本0.5.0带来了新的DynaForm组件。 通常&#xff0c;如果知道行/列的数量&#xff0c;元素的位置等&#xff0c;则可以通过h&#xff1a;panelGrid或p&#xff1a;panelGrid来构建非常简单的表单。 对于静态表单&#xff0c;这是正确的。 但是&#xff0c;如…

C# 定时器事件(设置时间间隔,间歇性执行某一函数,控制台程序)

定时器事件代码 static void Main(string[] args) {Method();#region 定时器事件 Timer aTimer new Timer();aTimer.Elapsed new ElapsedEventHandler(TimedEvent);aTimer.Interval seconds * 1000; //配置文件中配置的秒数aTimer.Enabled true;#endregionstring strLi…

Vmware安装Centos NAT方式设置静态IP

【Vmware中在搭建集群环境等&#xff0c;DHCP自动获取IP方式不方便&#xff0c;为了固定IP减少频繁更改配置信息&#xff0c;建议使用静态IP来配置&#xff0c;网络连接主要有三种方式 1.nat 2.桥接&#xff0c;3主机模式 &#xff0c;在这里主要介NAT方式&#xff0c; 为什么使…

1 TB /节点时快速,可预测且高度可用

世界正每秒从移动设备&#xff0c;Web和各种小工具向应用程序推送大量数据。 如今&#xff0c;更多的应用程序必须处理此数据。 为了保持性能&#xff0c;这些应用程序需要快速访问数据层。 在过去的几年中&#xff0c;RAM价格下降了&#xff0c;我们现在可以便宜得多地获得具有…

java jni 内存_Android开发之JNI内存模型

Java 与JNI 内存管理是怎样的想要弄清楚Java与JNI的内存管理的关系&#xff0c;首先要弄清楚JVM的内存模型JVM内存模型.png其中本地方法栈就是运行时调用native 方法的数据保存区。本地方法栈的大小可以设置成固定的或者是动态扩展。Java中的内存泄露JAVA 编程中的内存泄漏&…