我之前的项目中使用了Orchard, 它依据依赖注入的思想而做的模块化让我深深为之着迷,这里开始宣传一下这个架构。
包含的概念非常之多,我现在也不甚了解。Orchard就是自己想控制它改变它的话需要非常对.net非常的了解。
Orchard是一个以微软为主导的开源CMS项目,它允许使用者在Asp.Net平台上快速建立网站,并且提供扩展框架能够允许定制人员通过模块和主题 等增加额外的内容,Orchard能够建设出复杂的内容管理系统,它提供了强大的模块化建设模式,通过组件的重用将系统建设成本最小化,帮助用户减少编码,从而吸引非技术人员的关注。
Orchard项目建立于2010年3月并与2011年1月发布正式版1.0V,是微软“Oxite”开源CMS系统的继承者,2010年12月微软将Orchard从自己的CodePlex迁移到 Outercurve基金会,并承诺提供三年的技术支持该项目。Orchard使用了当今.Net平台最先进的技术构架,使之成为该平台中最新、最先进的开源CMS系统之一。
建立一个CMS网站(内容管理系统)是不同于建立一个普通的web站点:它更像是建立一个应用程序容器。 设计这样一个系统时,必须建立一流的可扩展性功能。这必需是一个非常开放式的构架,但是一个开放性的系统可能会影响应用程序可用性的挑战,在系统中的需要与未知的未来模块的组合,包括在用户界面级别,编排所有这些小零件,让互不知道的彼此成一个连贯的整体,是Orchard是关键。
Modules |
|||
Core |
|||
Orchard Framework |
|||
ASP.NET MVC |
NHibernate |
Autofac |
Castle |
.NET |
ASP.NET |
||
IIS or Windows Azure |
Orchard CMS基于现有的框架和库构建。下面列出一些主要的内容:
Orchard程序和框架在这些框架的基础上构建额外的抽象层,根据Orchard的开发指南实际上对于Nhibernate,Castle,Autofac有许多方式实现细节我们并不需要了解。
Orchard Framework是Orchard的最底层,它包含了应用程序引擎和至少不能被分离成模块的部分。这些都是必须的东西,甚至最基本的模块也不得不依赖它,可以将它理解 为Orchard最底层的类库。
当Orchard 启动起来,一个Orchard Host被创建,Host是在应用程序域层的单例。然后Host将使用ShellContextFactory取得当前租户的Shell,租户是按识别用户被隔离的应用程序实例,他们运行在同一个应用程序域中,这增加了网站密集度。Shell是租户层的单例,事实上代表着租户,它有效提供了租户层隔离对象同时对多租户模块编程模型无关。Shell一旦建立,将从ExtensionManager获取可用的扩展。扩展是模块和主题,默认实现了扫描modules和themes目录的扩展。同时,shell从ShellSettingsManager获取租户的设置列表,默认会从appdata适当子目录获取设置列表,但能从不同地方获取设置。例如:我们有使用blob storage的Azure实现,因为在那个环境中Appdata不一定可写。然后,shell获取CompositionStrategy对象,并从可以扩展列表为当前host准备IoC container,当前租户的准备设置,这样做的结果不是一个shell的IoC container,它是依赖列表、controller、record blueprints的ShellBlueprint。每个租户的ShellSettings列表和ShellBluePrint被扔进 ShellContainerFactory,CreateContainer得到一个ILifetimeScope,它基本上租户层启用的IoC container范围,因此模块可以在租户范围内得到注入依赖,不用做其它任何具体的事。
Orchard中创建可注入依赖的标准方法是直接或间接实现IDependency 接口。在构造器中能得得接口类型的参数。application framework会发现所有依赖并在需要时初始化和注入实例。有三种不同的可能范围的依赖,选择一个从右边的接口派生的实现。
可能用OrchardSuppressDependency 特性来标记您的类,替换现有的依赖,需要完全合格的类型作为参数去替换。
一些依赖是不是唯一的,而是有部分列表。例如:处理程序都在同时激活,有些情况你要修改这些依赖创建的顺序,这个可以通过修改模块的manifest实现,使用feature的 Priority属性:
Features:
Orchard.Widgets.PageLayerHinting:
Name: Page Layer Hinting
Description: ...
Dependencies: Orchard.Widgets
Category: Widget
Priority: -1
ASP.NET MVC
Orchard基于ASP.NET MVC构建,为了添加像主题和租户隔离这样的东西,需要引入一个额外的间接层,展示ASP.NET MVC上提出的概念,将在Orchard概念层中分离。
例如:当请求一个指定的view时,LayoutAwareViewEngine引入 ,严格地说,它不是一个新的视图引擎,它包含了依赖当前主题去寻找正确view的逻辑,代理了实际视图引擎的渲染工作。
同样,提供了route providers, model binders and controller factories,作为ASP.NET MVC的单一入口点和在适当范围内对象下分发请求。
在路由情况下,我们能提供很多路由,并且一个路由发布到ASP.NET mvc,model binders and controller factories也是同样的。
Orchard中的内容是在类型系统下管理的,在某些方面是比.net类型系统更丰富和更灵活的一个的类型系统,能给web CMS提供必要的灵活性,类型必须在运行时动态组合以反映内容管理的灵活性。
Orchard能处理任意内容类型,包括一些管理员以代码的方式动态创建的。这些内容类型是内容元件的聚合,因为元件关系到许多的内容类型。
例如:博客,产品,视频可能都有路由地址、评论、标签,所以Orchard中路由地址、评论、标签分隔成内容元件,这样路由地址、评论、标签模块就只需要开发一次并就用到这些内容类型中。元件可以拥有自己的属性和内容字段,字段同样也是可复用用的,元件和字段的区别是他们的范围和语义不同。字段比元件的粒度更小,例如:字段可能描述一个phone number 或 email address,但是元件可能就是描述了评论或标签的整个范围。主要的区别还是语义上的:元件是实现了”is a”关系,字段实现了”has a”关系。例如:一件衬衫is a 产品,has a 名称和价格。
内容类型是由内容元件构建的,内容元件代码通常与下面的有关联:
所有的内容都通过ContentManager对象访问,这让你使用事先不知道类型的内容成为可能。ContentManager 一些方法,查询内容存储库,内容版本,并管理发布状态。
Orchard自动为每个HTTP请求创建一个事务,这意味着请求过程中的所有操作都是事务中的一部分。如果请求代码中断,所有数据操作都将回滚。如果事务没有显示取消,请求结束所有操作都会提交,不需要显示commit。
下面介绍一篇博文的请求。
当请求一篇指定的博文,程序首先寻找各种模块定义的可用的路由并找到博文模块匹配的路由,然后路由解析请求发给blog post控制器的action item,action将从content manager查询博文,这个action从基于请求的主要对象的content manager(叫BuildDisplay)获取 Page Object Model,从content manager检索这个博文。
博文有自己的controller,但不是所有content type都有。例如:动态内容类型被Core Routable part的许多通用ItemController服务,ItemController的显示行为几乎与博文的controller做同样的事,它从 content manager取得content item 然后从结果创建POM。
布局视图依赖当前的主题和使用的模块类型一起解析正确的视图,视图内,许多动态的shape被创建,比如zone,找到正确的template或shape method 呈现每个shape ,主题引擎实际呈现在POM中遇到的shape出现的顺序和递归。
部件是有Widget content part和widget stereotype的内容类型。像任何其他的内容类型,由元件和字段组合而成。这意味着,他们可以使用同一版本的编辑和渲染其他类型的内容的逻辑,他们像积木一样任何content part能像widget的一部分被重用。
部件能过部件层级添加到页面,层级是部件的集合,他们有名称,规则,确定能出现在网站的哪个页面、部件列表、关联区域位置、排序、设置。
每个层级的规则使用IronRuby表达式,在程序中所有IRuleProvider的实现都能使用这些表达式,Orchard有两个box实现:url 和 authenticated.
Orchard中的网址是一个内容项,这使得它可以为模块添加额外的元件,这是模块能如何进行site settings,每个租户都有Site settings。
Orchard和它的模块通过创建依赖接口暴露扩展点,然后实现注入。
通过实现它的接口完成插入扩展点,或实现与接口具有相同的名称和方法。换句话说,Orchard不需要严格的强类型接口通信,启用插件扩展扩展点不需在程序集上定义的地方依赖。
这仅仅是Orchard 事件总线的一种实现,当扩展点用调用注入实现,一条消息被发布在事件总线上,以适当命名的接口派生的类中的方法的对象之一监听事件总线发送的消息。
Orchard网站的很多行为都能通过命令行执行。这些命令是实现了ICommandHandler的类中的标记了CommandName 特性的方法。Orchard命令行工具在运行时模拟网站环境和使用反射检查程序集来发现可用的命令。命令执行的环境尽可能的实际运行的网站。
搜索和索引默认通过使用Lucene来实现,但是默认实现可以用其它索引引擎替换。
Orchard中的cache依赖 ASP.NET cache,但是我们暴露了一个helper api,可以通过一个ICache类型的依赖调用get方法使用。如果cache没有包含请求项,Get方法取得key和function可用于生成 cache entry’s value。使用Orchard cache api的主要好处是每个租户透明地工作。
Orchard中的文件系统是抽象的,以便存储能被定向到物理文件系统或Azure的blog存储的备用存储,取决于环境。Media模块就是使用抽象文件系统的例子。
Orchard中的用户是content items,一个很容易为一个模块的配置并用额外的field扩展它们的content item,角色是能被链接到用户的content part。
每个模块都能公开一组权限,以及如何将这些权限授予Orchard的默认角色。
模块能通过调用IScheduledTaskManager类型的依赖的CreateTask方法安排任务。该任务能被实现了 IScheduledTaskHandler接口的类型执行。这个执行方法能检查任务类型名称并决定是否处理。任务在ASP.NET线程池的一个单独线程上运行。
模块能使用INotifier 依赖并调用它的方法在管理界面浮出消息,任何请求的一部分可以创建多个通知。
程序和模块的本地化通过调用T()方法中包装字符串资源来完成,@T("This string can be localized")
Orchard的资源管理能从位于程序指定位置的PO文件装载本地化的资源字符串。
Content item的本地化通过不同的机制完成:content item的本地化版本是物理上独立的内容。
目前使用的文化是由culture manager决定。返回文化的默认实现在site setting中设置,但一个备用实现可以从用户配置信息和浏览器的设置获取。
日志依赖ILogger实现,不同的实现可以发送到不同存储类型的日志条目。
Orchard Core程序集包含一组Orhcard运行所必须的模块。其它模块可以安全地依赖到这些模块上,这些模块总是可用的。比如 feeds,navigation,routable模块。
Orchard默认发行版包含了一些内置模块,像 blogging,pages,但第三方模块也同样能创建。
一个模块就是扩展Orchard的包含manifest.txt文件的ASP.NET MVC Area。
一个模块通常包含事件处理程序,内容类型,它们的默认呈现模板以及一些管理界面。
每次修改模块都能从源代码动态编译。这种”记事本”风格的开发并没有指定需要显示编译或甚至需要使用Visual Studio。
这是Orchard中的基本设计原则,产生的所有HTML都能用主题替换,其中包含模块产生的标记。公定了文件必须在主题中的层次。
Orchard中的渲染机制基于shapes,主题引擎的工作是查找当前主题以及确定渲染每个shape最好的方式是什么。每个shape能有一个默认的渲染,可以由模块在代码中定义 像视图目录中的模板或像一个shape方法,默认渲染可能被当前的渲染覆盖。
主题可以有一个父主题,能使子主题专门化或改写。Orchard自带了基础默认主题叫 Theme Machine,设计成作为父主题很容易使用。
主题能包含代码,他们能有自己的csproj文件,有利于动态编译。这使主题定义shape方法,但也会暴露其拥有的所有设置管理界面。
当前主题的选择通过实现IThemeSelector的类实现,返回主题名称和任何请求的优先级,Orchard自带了IThemeSelector的4个实现。
主题选择的一个例子:可以使用户使用移动设备时推出一个移动主题。
参考文章:http://docs.orchardproject.net/Documentation/How-Orchard-works