一起谈.NET技术,.NET动态调用DLL的方法

  很多软件都是可插拔的,最知名的便是微软的Windows操作系统。你可以在Windows操作系统上安装QQ,也可卸掉QQ,这便是可插拔。这里不谈Windows的实现,因为太过复杂。本文就谈谈管理软件的可插拔的实现。相对Windows操作系统,QQ就是它的一个插件。所以可以简单的将开发可插拔的软件分为两个部分。一个是主应用程序的开发,一个是插件的开发。

  比Windows小的,常见的可插拔的软件是MSN。MSN主应用程序由MS开发,还存在一些MSN插件开发商,国内好像也有不少,这些插件开发商通过在插件中植入广告获取利润。MS不可能提高源代码给这些开发商,那么MSN的主应用程序和MSN的插件是如何衔接起来的呢。我想应该是MS提供了一些接口和方法供开发商使用,估计有个api之类的东西,所以开发可插拔的应用系统分为三个部分。

  1、主应用程序的开发

  2、公用接口的开发

  3、插件的开发

  了解了这些以后,下面通过一个实例来说明。这个实例的原则是可扩展性强,能向下兼用。

  业务需求是:老系统每当逢年过节的时候,会通过邮件给用户发送一些祝福的邮件。现在流行手机和MSN(QQ没有借口)之后,客户希望系统能通过手机短信和MSN的消息给用户送去祝福。现在我们需要开发手机短信和MSN留言两个插件,然后将它们安装到系统中去。

  实现:

  为了简单起见,这里使用控制台应用程序,如果你有兴趣,可以修改成asp.net或者Windows Form的。

  定义两个接口:

public interface IPluginHost{void AddMenuItem(string name, MenuItemClickedHandler clickHandler);void RegisterComponent<T>(T component) where T : class;void MailNotice(string messaage);}public delegate void MenuItemClickedHandler(string name);

  这个接口是主应用程序继承的,现在只有MailNotice功能, AddMenuItem是供插件调用的方法,创建一个菜单。RegisterComponent是插件向主应用程序提供一些方法。

public interface IPlugin{void Initialize(IPluginHost pluginHost);void DoSomething();}

  上面是插件的接口。

  在主应用程序中有一个加载插件的地方。这里的插件是dll,所以我通过反射去加载这些dll。

public void LoadPlugin(){foreach (string fileName in Directory.GetFiles(Directory.GetCurrentDirectory() + "\\" + "Plugins", "*.dll"))    {Assembly assembly = Assembly.LoadFile(fileName);foreach (Type pluginType in assembly.GetTypes())        {if (!pluginType.IsPublic || pluginType.IsAbstract || pluginType.IsInterface)continue;Type concreteType = pluginType.GetInterface(typeof(IPlugin).FullName, true);

if (concreteType != null)            {IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType);                plugin.Initialize(this);                pluginList.Add(plugin);break;            }        }    }}

  主应用程序执行的代码如下:

void Start(){//邮件发送祝福MailNotice("中秋快乐");//加载插件LoadPlugin();//运行插件if (pluginList.Count > 0)    {foreach (IPlugin plugin in pluginList)        {            plugin.DoSomething();        }    }

Console.ReadLine();}

  运行结果如下:

  开发两个插件,都继承IPlugin。

  手机短信通知插件:

public class PluginA : IPlugin{

public void Initialize(IPluginHost pluginHost)    {IPluginHost myApplication = (IPluginHost)pluginHost;        myApplication.AddMenuItem("Click me", OnClick);

}private void OnClick(string name)    {Console.WriteLine("Omg! You clicked me!");    }

public void DoSomething()    {Console.WriteLine("手机短信通知:中秋快乐");    }

}

  MSN通知插件:

public class PluginB : IPlugin{

public void Initialize(IPluginHost pluginHost)    {IPluginHost myApplication = (IPluginHost)pluginHost;        myApplication.AddMenuItem("Click me", OnClick);

}private void OnClick(string name)    {Console.WriteLine("Omg! You clicked me!");    }

public void DoSomething()    {Console.WriteLine("MSN信息通知:中秋快乐");    }

}

  插件的目录如下图:

  运行效果:

  扩展性和兼容性:

  如果我想在主应用程序中添加一个ShowMessageBox方法。而且这个方法供插件调用。考虑到版本的兼容性,公开的接口是不能修改的。比如:将主应用程序的接口修改成:

public interface IPluginHost{void AddMenuItem(string name, MenuItemClickedHandler clickHandler);void RegisterComponent<T>(T component) where T : class;    T GetComponent<T>() where T : class;void MailNotice(string messaage);void ShowMessageBox(string message);}

  那么如何实现呢,很简单,使用依赖注入的方式。添加下面接口:

public interface IMessageBoxHost{void ShowMessageBox(string message);} 

  通过主应用程序的构造函数,将MessageBoxHost对下岗注入到主应用程序,在通过插件的构造函数,将其注入插件之中。

  主应用程序的构造函数:

public Program(IMessageBoxHost messageBoxHostInstance){this.messageBoxHostInstance = messageBoxHostInstance;}

  插件构造函数:

public PluginA(IMessageBoxHost messageBoxHost){this.messageBoxHost = messageBoxHost;}

  修改实例化插件的代码:

IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType, new object[] { messageBoxHostInstance });

  这样我们对版本兼容有了保障。

  总结:本文闲谈了可插拔应用程序的开发原理,文章的后面提供了插件和应用程序之间版本兼容的一种方案。有讨论才有进步,欢迎各位留言。

  参考:A Flexible Plugin System    A more extensible way to build plugin system

时间: 2024-10-20 18:09:08

一起谈.NET技术,.NET动态调用DLL的方法的相关文章

一起谈.NET技术,SilverLight调用WebService的方法

在我们添加Service Reference的时候,可能不知道该服务最终会被部署到什么位置,或者该服务可能被迁移,此时我们可以使用以下手段进行Service的调用,提高代码编写的灵活性. 步骤1:修改宿主Web页面的代码,将服务地址以初始化参数方式传入. <form id="form1" runat="server" style="height:100%">    <div id="silverlightControl

.NET动态调用DLL的方法

很多软件都是可插拔的,最知名的便是微软的Windows操作系统.你可以在Windows操作系统上安装QQ,也可卸掉QQ,这便是可插拔.这里不谈Windows的实现,因为太过复杂.本文就谈谈管理软件的可插拔的实现.相对Windows操作系统,QQ就是它的一个插件.所以可以简单的将开发可插拔的软件分为两个部分.一个是主应用程序的开发,一个是插件的开发. 比Windows小的,常见的可插拔的软件是MSN.MSN主应用程序由MS开发,还存在一些MSN插件开发商,国内好像也有不少,这些插件开发商通过在插件

C#程序实现动态调用DLL的研究

原文:C#程序实现动态调用DLL的研究 C#程序实现动态调用DLL的研究 摘  要:在<csdn开发高手>2004年第03期中的<化功大法--将DLL嵌入EXE>一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资源中释放出来,通过静态加载延迟实现DLL函数的动态加载,程序退出后实现临时文件的自动删除,从而为解决"DLL Hell"提供了一种解决方案.这是一个很好的设计思想,而且该作者也用C++实现了,在Internet上也

动态电用dll出错-动态调用Dll出错,服务模式

问题描述 动态调用Dll出错,服务模式 用MFC开发一个服务程序,服务程序在应用模式下,动态调用dll正常,然而变成服务模式,会导致服务停止.请问这是怎么回事,请大神指点. 解决方案 主要是你服务运行情况下,进程权限会变高,同时不能直接访问一些用户目录等.服务运行在SESSION0,这个可能会导致你的DLL处理有问题.你需要检查一下DLL的内部代码逻辑 解决方案二: http://www.cnblogs.com/duanshuiliu/archive/2012/07/05/2577402.htm

C++生成dll和调用dll的方法实例_C 语言

本人根据网络多个相关博客帖子原创 1)生成dll 建立两个文件 xxx.h , xxx.cpp xxx.h内容如下: #ifdef BUILD_XXX_DLL#define EXPORT __declspec(dllexport)#else#define EXPORT __declspec(dllimport)#endif extern "C"{EXPORT void example(void);... ...} xxx.cpp内容如下: #define BUILD_XXX_DLL#i

php中动态调用函数的方法

 这篇文章主要介绍了php中动态调用函数的方法,实例分析了php动态函数的实现原理与具体实现步骤,需要的朋友可以参考下     本文实例讲述了php中动态调用函数的方法.分享给大家供大家参考.具体分析如下: php中你可以动态调用函数,分为以下步骤: 1. 定义一个函数 2. 将函数名(字符串)赋值给一个变量 3. 使用变量名代替函数名动态调用函数 详细代码如下所示: ? 1 2 3 4 5 6 7 <?php function addition ($a, $b){ echo ($a + $b)

php中动态调用函数的方法_php技巧

本文实例讲述了php中动态调用函数的方法.分享给大家供大家参考.具体分析如下: php中你可以动态调用函数,分为以下步骤: 1. 定义一个函数 2. 将函数名(字符串)赋值给一个变量 3. 使用变量名代替函数名动态调用函数 详细代码如下所示: <?php function addition ($a, $b){ echo ($a + $b), "\n"; } $result = "addition"; $result (3,6); ?> 希望本文所述对大家

vb动态调用DLL的问题

问题描述 一个连接接口DLL,正常调用时先注册DLL文件,vb中引入,创建对象都没问题:DimobjCommAsHsCommX.Comm'定义对象objComm=CreateObject("HsCommX.Comm")objComm.Create()'创建对象----但这种方式在多线程调用的情况下性能就会急剧下降.目前是想改成动态调用的方式,在不同的目录下放置多个DLL,但在VB.net里实在不知道怎么实现常使用反射,DimAssDLLAsAssemblyAssDLL=System.R

求助:C#动态调用DLL的,为什么getProcAddress无法获得NATIVE DLL中的导出函数?

问题描述 ①自己用C++写了个DLL在其中声明了一个导出函数extern"C"__declspec(dllexport)LRESULTCALLBACKhookProc(intnCode,WPARAMwParam,LPARAMlParam){//实现内容忽略return1;} 生成DLL后,因为是C++编译器编译的,会改变方法名,于是我用了VIEWDLL查看了导出函数名称叫_hookProc@12②调用DLL代码[DllImport("kernel32.dll",Ch