博客文章

基于ASP.NET MVC的热插拔模块式开发框架(OrchardNoCMS)

作者: weijiqiong      时间: 2013年12月15日 20:00:00

 

      感谢NicolasPei的文章,对于Orchard这样优秀的框架是很多.net开发者梦寐以求的,但如何能打造出适合自己的框架,就需要自己进行一下DIY了,NicolasPei同学给我们提供了这样一个思路,希望对大家能起到帮助和启发,为方便大家阅读我将其三篇文章合并成了一篇。

       Orchard CMS是针对CMS开发的,对于很多开发需求来说,内容管理这块儿可能并不需要,而需要它的模块式开发模式。所以我这里通过对OrchardCMS进行瘦身,去除 内容管理部分的内容,保留简单的运行环境和基础的模块。需要做的工作:

去除Orchard Framework的内容管理部分,同时去除Orchard Framework依赖内容管理的相关内容。

去除Orchard Core部分的部分module,只保留Sharpe和Setting两个模块。

去除内容管理和博客管理的相关模块,只保留支持模块启用和停用以及皮肤模块。

这里我只是对OrchardCMS的代码进行了瘦身,所以相关的license请参考Orchard CMS的。

Github上的源代码: https://github.com/nicholaspei/OrchardNoCMS

如果你所在的地区网络不能访问github,请从下面的链接下载:http://pan.baidu.com/s/1zifoC

为什么需要对Orchard CMS瘦身?

在我们的项目中,需要一个类似于Java的OSGI框架。发现Orchard CMS是可以达到这个要求的,自己做的话,时间不够,整个成员能力也够呛。所以选择了Orchard CMS,但是这个CMS中,太多的数据库表和模块都是为了CMS服务的,而我们的业务中基本上不需要或者用CMS配置字段很难达到业务要求。于是我就对OrchardCMS进行了瘦身,只保留热插拔模块式开发,同时去除了大部分表,只保留6个表。

为了对得起开源,我就把自己整理好的代码分享出来,希望大家能够一起改进。https://github.com/nicholaspei/OrchardNoCMS

首先看一下最后完成的代码目录和之前的代码目录:

image

只保留了相当少的一部分,这就是Orchard可以运行的最小框架了。Orchard.CodeGeneration是为了创建模块的。而HelloWorld模块是为了测试模块式开发创建的新模块。

当把ContentManagement部分的代码去掉时,真的是全屏报错啊。很蛋疼。。经过不懈的努力,让整个Orchard.Framework跑起来了。

接下来蛋疼的是Orchard.Core。这里最先包含太多模块,Container,Contents,Dashboard等,大部分都依赖于ContentManagement。最后通过分析代码,发现其实必须的模块式Settings和Shapes模块。

Settings来获取站点运行时需要的信息,当前语言,时区等。

Shapes是用来把上下文转换成Html返回给浏览器的。最初没有把Shapes改好,所以出现了Action执行了,但是View却为空,发现ViewEngine也找到了页面,却显示不出内容来。

默认的Orchard是提供了模块的管理页面,皮肤的管理页面等。我个人觉得其实只需要提供控制台的模块管理就可以啦。

支持的命令如下:

image

默认命令中没有feature update,所以我增加了该命令,可以在模块的数据结构发生改变时,通过执行feature update来执行Migration。

另外,产品或者项目中,有共享模块的情况,所以接下来我会把Orchard.Package模块也集成进去。并加入自己的一些想法,加入NuGet更好的支持,让共享模块更加灵活。

希望Orchard爱好者可以关注该项目,试着使用它,并提出你的意见和建议。

更新:

1.昨天有同学说没有数据库,运行不了,发现时因为我的.gitignore文件里把*.sdf文件过滤掉了。已经更新。

2.我会接下来写一系列文章结合现实的一些需求让大家深入了解下如何更好的开发一个模块。

3.如何在不改变已经发布的模块而扩展功能。(修改关闭,扩展开放)

4.模块之间如何做到运行依赖,而非依赖。(个人不是很推荐,只是现实中有时候需要用到)

5.整合bootstrap,提供一套完整的UI解决方案。

 

之前文章中给大家说明了下我这个小小的想法,发现还是有不少人的支持和关注。你们的鼓励是对我最大的支持。

我总结了了大家的评论,有以下几个问题:

1.希望有更多的文档说明。

2.希望介绍下Orchard的热插拔机制。

3.希望可以说明如何扩展功能什么的。

4.介绍下Orchard的核心机制。

5. 介绍下我对Orchard的整个瘦身过程怎么做的。

6.觉得这个像瑞星杀毒只剩下小狮子了(这个有意思 J)

除了这些还有别的,我只是自己大概总结了下。

对于以上的问题,我不会挨个去说明。只是给大家说明下我的整个计划和接下来的安排。

首先,文档是必须的。可能在博客上未来不会有太多的文档,但是在github上你将会找到很多的说明文档。OrchardCMS的整个运作机制,确实是很庞大,很复杂的。对于大家都关注和好奇的热插拔,我不可能一下子就去介绍说明它,因为它依赖于Orchard CMS的其他好多功能和机制。比如:Shell的概念,Feature的加载机制,缓存机制,动态代理、HttpContent管理等。还有一些协调的方法类等。

从我接触OrchardCMS开始到现在也有两年了。开始试着去读它的源码,有点不靠谱,或者说对能力的要求比较高。所以试着从模块开发为出发点,慢慢的渗透,理解才是比较适合我们大多数人的方法。

所以还是从比较简单的模块开发来,中间会顺带的介绍一些OrchardCMS中的比较核心的内容。

1. 创建一个模块:

我保留了代码生成模块,不能通过手动创建模块,那样会疯掉的。所以首先需要去Tools文件夹下的Orchard/bin下把Orchard.exe拷贝到Web站点的bin目录下。

clip_image002

然后打开它,建议使用Powershell打开,容易粘贴复制。

使用codegen module Orchard.Car来生成一个Orchard.Car模块。

clip_image004

如果你使用过改模块,那么忽略这一节,往下看吧。

image

打开解决方案,在Modules文件夹下,右键选择‘添加’菜单,找到Orchard.Web文件夹下的Modules文件夹,选择刚才生成好的Orchard.Car。

image

添加完成后,我们就创建好了Orchard.Car模块。

2. 修改module.txt文件。

对于一个模块,这里需要理解什么是模块边界,就是这个模块能够放到容器里的所有触头。

OrchardNoCMS中一个模块的触头有以下几个:

image

也就是该模块必须有的部分。所以我们需要修改Module.txt文件,来确定模块以来的OrchardNoCMS版本号,以及模块的版本号。修改后的文档如下:

image

3. 创建Car的实体和关系映射。

现在我们需要的是车辆这个实体,包含名称、描述、价格、品牌、座位数几个属性。

对应的实体和数据库中表的关系映射,OrchardNoCMS会自己来完成。所以我们只是定义实体。

这里说明下Orchard是如何来找到需要创建映射关系的实体类。

首先需要关注的是CompositionStrategy 这个类。

image

看看它都干了什么。J。它通过找到命名空间以.Models结束的并且包含属性有Id这个字段的类作为需要创建mapping的实体。然后通过创建RecordBlueprint来告诉NHibernate你应该让哪个类映射到哪张表。

但是默认这里有很大的局限性。

比如:我的主键不想叫Id,我想叫tablename+Id,那怎么办呢?我的表名比较特殊,不能和类同名怎么办?不着急,后面会说明。

最终的实体关系映射会存放到APPData /site下某处,名字叫mapping.bin,你可以自己去找找看。

4. 创建Service

有了实体,接下来需要做的是创建一个Service。注意,如果你使用OrchardCMS,那么可以看到里面的数据库操作大都离不开内容管理。这里则直接是使用IRepository进行数据库操作。所以我们需要创建一个ICarInfoService接口,并实现它。

image

上图中圈住的IDependency这个 接口,是所有需要自动注入到Autofac容器的接口都需要继承的。

这里就需要说明一下Orchard的底层自动注入机制。看ShellContainerFactory.cs中的代码来完成所有的自动注入功能,同时它还结合Castle.DynamicProxy实现了AOP功能。所以大致来说,大部分的面向对象牛X的框架都离不开IoC和它上面的AOP。

image

对于不同的注入方式和AOP在别的文章里介绍吧。

5. 创建Controller和View

创建好实体后,我们创建一个新增记录的Action。

image

创建好对应的View,需要注意的是,这里Views文件夹下的子文件夹需要自己手动创建。

image

Index.cshtml为空,先不创建。本人的css不是很好,所以随便写了几个div。

6. 创建路由

如果不创建路由,也可以通过Orchard.car/Car/Add来访问上面创建的Action,但是我们为了简单,可以自己定义路由,所有自定义的路由都需要实现IRouteProvider这个接口。

image

现在就可以通过car/add来访问上面定义好的Action啦。

7. 创建数据库表

使用Orchard提供的DataMigration来创建表。方法如下:

image

8. 启用模块。

在刚才打开的orchard.exe中执行如下命令: feature enable orchard.car

clip_image028

以上完成模块的开发。

以上只是理想的状态。现实总是有很多变态的需求。也希望大家提出自己的问题。

 

基于ASP.NET MVC的热插拔模块式开发框架(OrchardNoCMS)--AOP编程

Figure 8: Adapter pattern

AOP编程在目前来说好像是大家都比较喜欢的。ASP.NET MVC中的Filter就是使用AOP实现的配置器模式。AOP在编码中的应用主要有如下几个方面:

日志记录,跟踪,优化和监控

事务的处理

持久化

性能的优化

资源池,如数据库连接池的管理

系统统一的认证、权限管理等

应用系统的异常捕捉及处理

针对具体行业应用的横切行为

前面几种应用我相信大家都是比较熟悉的。在ASP.NET MVC中有Filter之类的,提供认证和权限管理。很多实现AOP的组件都是拿日志作为例子说明。我这里给大家说明一个具体业务的横切例子。

以之前的Orchard.Car模块为例,如果我们这个模块式产品中的一个模块,当应用到项目中时,可能需要一些改动,那么AOP就可以在很多时候解决我们的问题。

假设我们现在有一个方法是获取Car的列表,那么对应的代码如下:

image

对应的Service代码如下:

image

别忘了在Route.cs中添加路由代码。

运行,查看结果:

image

如果在产品发布后,项目A中使用该产品,需要为car添加一个字段,叫做缩略图,那么很现实的一个问题是,我们是不是为了项目A单独为car扩展一个字段?这时候适配器就很重要了,实现适配器的方式有很多,我们这里就说明下如何使用AOP来实现字段的扩展。

首先需要一个Aufofac的module类,代码如下:

image

我们只需要为CarInfoService类来添加一个拦截器,别的就没有必要了。这里你会看到有一个SimpleInterceptor类,它的作用就是用来对CarInfoService的方法进行拦截。

SimpleInterceptor的代码如下:

image

如果当前的方法名称是GetList那么我们就为它添加一个字段,代表缩略图。这里我随便写一个,你可以根据自己的实际需要去做相应的改变。

现实中,可能这个Interceptor是在一个扩展模块中,所以对应的需要一个扩展的服务来提供Thumb字段。

image

结果不正确,因为我们客户端或者页面已经对运来的JSON进行了解析,所以新的JSON格式不是我们需要的,再次修改Interceptor的代码:

image

除了GetList方法可以通过AOP实现修改封闭扩展开放,你叶可以使用这种方式来扩展新增记录的方法。这时你需要把Request.Form从Controller中传入Service方法。这种扩展方式一个很大的好处就是可以帮助多个项目平稳的升级。产品模块的代码永远都不会被项目牵制。

具体的例子请到github上下载相应的代码来查看,这里就不做解释了。

上面只是我自己的一个小小的使用经验,有时候当字段的类型需要更改,而你不允许直接更改当前的代码时,这种方式也是一个不错的方法。

AOP虽然不是标准的设计模式之一,但是通过它可以让很多的模式更加简单的实现。

最后说明一下,OrchardNoCMS中如何实现的AOP。

它使用的Castle.DynamicProxy来实现的。结合Autofac。首先是对AutoFac的扩展类:

image

注入时,需要为注入的Component调用EnableDynamicProxy方法,代码位置:

image

可以看出来,所有实现继承了IDependency的类都可以使用AOP。

以上就是OrchardNoCMS的AOP编程示例,可以到https://github.com/nicholaspei/OrchardNoCMS 下载完整代码。

本文转自:http://www.cnblogs.com/n-pei/