从这篇文章开始的连续三篇文章我将向大家展示BlogEngine.Net中的三大开发扩展特性,它们分别是Extension,Widget和Theme。程序员可以在符合一定标准条件下开发自己的扩展,然后将扩展像插件一样(Plug'n play)与BlogEngine.Net进行集成,来达到个性化的应用。本文将详细介绍第一种扩展Extension的开发标准,管理部分介绍等。
声明一下
上一篇文章的回复中有人提到希望我写一下自己的看法和BlogEngine.Net的优缺点等,实际上我想把这些内容放在最后的总结篇里,不过在以后的每一篇文章中我也会或多或少的加入一些。对于这些看法只是我的一己之见,如果您觉得有帮助那更好,如果有不对之处还请指出。
什么是Extension与为什么使用Extension
Extension这个词我很喜欢,具有扩展之意。BlogEngine.Net中的Extension是特指使用了ExtensionAttribute特性标明的类。ExtensionAttribute被定义在BlogEngine.Core.Web.Controls中,继承了.Net中Attribute,内部主要有描述,版本,作者等成员。主要用来标识一个Extension类的信息,以便统一管理模型。BlogEngine.Net中的Extension都被放在了Web站点的App_Code\Extensions或子目录中。它在内部实现时大都是通过静态构造器来监听业务类的消息,并对这些消息提供一些处理。
Extension在BlogEngine.Net中可以做很多事情,例如:纪录业务日志,对文章的词语进行过滤或替换,对业务类活动的统计分析等。总之,写一些Extension会给你的Blog带来很多意想不到的扩展,目前一些开源社区已经有很多对于BlogEngine.Net的Extension的开发,这里有很多下载,感兴趣的朋友可以研究一下。
认识一下BlogEngine.Net已有的Extension
在Web站点的App_Code\Extensions中我们会看到有很多Extension。
Smilies:监听了Comment.Serving,也就是每当有评论被显示(Serving)时,它就会使用Post_CommentServing处理,主要是将评论中一些词语替换成一些图片。
SendPings:这里不再说了,在本系列的第七篇文章中已经做了详细的说明。它主要是发送pingback和trackback信息等。
SendCommentMail:就是每当文章有评论产生时根据配置会向文章作者的邮箱发送评论邮件,功能类似博客园中的评论邮件发送,实现类似Smilies的实现。
ResolveLinks:也就是每当有评论被显示(Serving)时,解决评论中的超链接过长等问题。
BreakPost:实现得很有意思,主要是处理文章显示的[more]问题,这都可以作为扩展,真是绝了。从这里我们也能看出以前的一个疑问,那就是Serving的作用,它主要是处理显示问题的,给[more]加入超链接。
BBCode:似乎是一个在评论显示时,进行字符替换以便按照样式显示的Extension。
CodeFormatter:这是一个第三方开发的对文章中包含的源代码进行格式输出的Extension。对于它的实现比较复杂,但是结构还是比较清晰的,有兴趣的朋友可以研究一下,这里就不再做过多说明。
实现一个自己的Extension
对于开发人员来说实现一个Extension是很简单的事,例如我们想把文章访问的IP纪录下来就可以这样实现:
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
6
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
7
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
9
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
10
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
11
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
12
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
13
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
14
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
15
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
16
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
17
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
18
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
19
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
20
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
21
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
22
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
23
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
24
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
25
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
26
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
27
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
28
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
29
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
30
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
31
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
32
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
33
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
34
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
35
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
36
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
37
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
Extension如何被Host起来的
BlogEngine.Net使用反射技术来启动这些Extension。这些Extension在整个应用程序启动时随之启动,应用程序通过查找已编译的程序集动态加载这些Extension类到内存中来,也就执行了类构造器,实际上这些Extension也就运行起来。我们在Global.asax中可以看到如下代码:
2 {
3 ArrayList codeAssemblies = Utils.CodeAssemblies();
4 foreach (Assembly a in codeAssemblies)
5 {
6 Type[] types = a.GetTypes();
7 foreach (Type type in types)
8 {
9 object [] attributes = type.GetCustomAttributes( typeof (ExtensionAttribute), false );
10 foreach ( object attribute in attributes)
11 {
12 if (ExtensionManager.ExtensionEnabled(type.Name))
13 {
14 a.CreateInstance(type.FullName);
15 }
16 }
17 }
18 }
19 }
这里请大家注意一下Utils.CodeAssemblies()的实现使用了反射动态加载已编译的程序集(查找程序集的方法)。对于ExtensionManager.ExtensionEnabled是在管理中判断这个Extension是否启用,ExtensionManager下文会提到。
Extension的管理
这里所说的Extension目前可能还不是很完善。不过它的实现是BlogEngine.Net非常经典的一部分,很值得去仔细学习和研究,其中很多地方应用到了反射,XML序列化等。它提供给管理员对这些Extension一个统一的管理,包括控制源代码的浏览,应用和取消Extension,对其进行设置(DataStore)等。由于这部分的源代码比较多,不适合对其进行更细致的分析,我在这里只是简单介绍一下它的整体设计。
ExtensionManager分成了两部分:
1.逻辑处理,位于App_Code/ExtensionManager中,有四个.cs文件:
ExtensionManager:完成了Extension管理部分常用的方法,也对页面提供一些直接性的服务。
ManagedExtension:是每个可被管理的Extension类的封装。
ExtensionSettings:也是为了管理Extension而封装的设置类,注意它与BlogEngine.Core.DataStore中的同名类的区别。
ExtensionParameter:主要是为ExtensionSettings服务的参数处理的封装。
这些是ExtensionManager主要逻辑,完成包括Extenison配置的加载和存储调用,缓存处理,统一化的管理模型,为页面提供一些直接的服务等。
1.页面管理,位于admin/Extension Manager中,这一部分是调用第一部分来实现管理的,第一部分中有很多信息也是为它服务的:
Default.aspx:一个承载页面,路由导航。
Extensions.ascx:一个Extenison的管理列表。
Editor.ascx:是Extension源代码浏览器。
Settings.ascx:是Extension设置器。注意它实际上是一个统一的配置界面。
对于ExtensionManager的实现逻辑是很复杂的,希望这个整体的介绍能给您阅读代码时带来帮助,如果有不清楚的问题可以给我回复一起讨论。这一部分我们需要注意一下配置从DataStore的加载和修改是如何完成的,对于逻辑中的配置和参数部分是如何统一化的。
总结
我觉得Extension这种扩展非常的优秀,当然这种扩展要想发挥出来肯定对于业务核心部分地设计是有很多要求的。尤其是它的ExtensionManager对模型的统一性的处理更值得我们去学习和研究,里面的反射机制用的很棒。不过目前这个ExtensionManager还有很多不太完善的地方,例如源代码修改支持,新Extension的动态添加等,可能BlogEngine.Net会在将来的版本中提供这些功能吧。
上一篇:BlogEngine.Net架构与源代码分析系列part8:扩展——DataStore分析
下一篇:BlogEngine.Net架构与源代码分析系列part10:开发扩展(中)——Widget小工具
【来源】: http://thriving-country.cnblogs.com/
本文版权归作者和博客园共同所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。