开发一个CMS(内容管理系统)程序,与开发一个普通的应用程序很大情况下是不同的,CMS程序更像是一个应用程序的管理器系统。当我们在设计这个系统的时候,第一考虑的是它的扩展性,这是一个非常有挑战的开放式架构。这些扩展性可能会影响系统的可用性,这些扩展需要与系统中未知的模块作良好的兼容,包括达到与用户界面级别,架构组织好这些各自不同的模块彼此运行在一起,这就是Orchard的全部。
这篇文章介绍了Orchard如何解决以上典型的问题灵活性和良好的用户体验。
Orchard架构图
基础与依赖
Orchard CMS是建立在现有的框架和类库基础之上,它们分别是:
- ASP.NET MVC:ASP.NET MVC是现在最流行的Web开发框架之一, 鼓励关注点分离;
- NHibernate:NHibernate是一个对象-关系映射工具。它处理了Orchard内容项数据库持久化,大大地简化了我们所关心的数据模型等操作,你可以从我们的源码中看到这样的例子,例如页面类。
- Autocac:Autofac是一个IoC容器,Orchard大量使用了依赖注入。创建一个依赖注入非常简单,就像创建一个类一样,只要直接或者间接实现或者标记了IDependency接口,采用实现正确的构造方法参数。而后所有注入的范围和生命周期都交给Orchard来完成,你可以从代码中看到这样的例子,像IAuthorizationService接口。
- Castle Dynamic Proxy:我们使用Castle为作为动态代理工具。
Orchard应用和框架是建立在这些基础框架的额外的抽象层,在实现的各个方面与NHibernate、Castle、Autofac一起运行起来。
Orchard Framework
从Orchard架构图中可以看出,Orchard Framework是最底层库,包含了应用程序引擎或者不可缺的模块,甚至于最小的一部分模块都不得不依赖于它,你可以理解这是Orchard最基础的类型。
工作程序
当Orchard运行起来,一个Orchard Host就会被创建,host是独立于应用程序域级别的一个东西。
接下来,这个host就会从当前的子站点(tenant)取得Shell去使用ShellContextFactory
,这些租群(tenants)是独立于用户的应用程序实例,运行于同一个应用域,主要是为提高站点的密度。shell是一个单例的租户级别,事实上也可以代表租户。这将会有效地提供租户-级别的隔离,即保持了模块程序与多租户信息不可知的某种关联。
这个shell,一旦被创建就会从ExtensionManager
获取有效的扩展信息,这些扩展包含了模块(modules)和主题(themes),默认会自动扫描modules和themes文件夹里的扩展。
与此同时,租户会从ShellSettingsManager
取得一系统的设置信息给shell,默认实现了从适当的子文件夹app_data或者安装时实现的位置获取。例如,Azure实现了从云端存储而替代app_data文件环境获取。
然后shell获取所有的有效的信息物件后使用它来准备IoC容器,注入可用的扩展列表和当前的host,当前的子站点。最终形成这个一系列的依赖图,控制器和记录列表在内。
这个一系列的shell设置(也就是每一个租户)和这些一系列依赖图通过ShellContainerFactory.CreateContainer
得到一个ILifetimeScope
,这基本上是租户IoC包涵的范围了,至此这些modules被注入了当前租户范围信息,但modules并没有做实现具体的事情。
依赖注入
实现一个标准的依赖注入方式是直接或者间接实现IDependency
接口,在另一面实现一个带参的构造函数。应用框架会找出所有的依赖,并且会根据需要实例化和注入实例。
依赖关系有三种不同的可能范围,选择其中一个去实现正确的接口:
- Request:每一个新的Http请求和在请求被摧毁的处理时依赖实例都会被创建,从
IDependency
接口派生出来对象创建都是非常安全可靠的并且成本很低。 - Object:每次都创建一个实例对象接口,实例不被共享。使用这个从
ITransientDependency
派生出来的。创建的对象必须是非常便宜的。 - Shell:每个whell/tenant只能创建一个实例,使用从
ISingletonDependency
创建对象,shell必须保持一个共同的生命状态。
替换存在中的依赖
可以取代现有的依赖,如果一个类被OrchardSuppressDependency
装饰您的类特性,但这需要完全限定类型名称来取代作为参数。
依赖的排序
一些依赖关系并不是唯一的,而且部分列表。例如,有同一时间的一些处理程序被激活时,在某一些情况下你想修改一些依赖的顺序,这可以通过修改模块的清单里优先属性,例如下面这个:
Features:
Orchard.Widgets.PageLayerHinting:
Name: Page Layer Hinting
Description: ...
Dependencies: Orchard.Widgets
Category: Widget
Priority: -
官网地址:http://docs.orchardproject.net/Documentation/How-Orchard-works
第一次做翻译,英文太差,请见谅。未完。