Orchard基础知识

CMS系统和一般的Web应用不一样,CMS系统更像是一个应用的集合。他需要很高的灵活性,易于扩展。并且能够将不同的功能组合成新的模块。

架构

Modules

Core

Orchard Framework

ASP.NET MVC

NHibernate

Autofac

Castle

.NET

ASP.NET

IIS or Windows Azure

Orchard 基础

Orchard CMS构建在一些成熟的框架和类库上,主要包括:

  • ASP.NET MVC: ASP.NET MVC是一个Web应用开发框架。
  • NHibernate: NHibernate是一个ORM工具。他提供了内容项数据的持久化以及非常简单易用的数据库操作方法。 你能在源代码中看到对他的使用,比如Page模块。
  • Autofac: Autofac 是一个IOC容器。Orchard 大量使用了依赖注入。通过继承IDependency或者其他特定的接口,你就能很容易的创建以来注入对象,如果在需要使用该对象的类中,通过构造函数实例化。注入对象的生命周期,由Orchard框架维护。你可以在源代码中搜索"IAuthorizationService"," RolesBasedAuthorizationService"," XmlRpcHandler"关键字,来了解依赖注入在Orchard中的使用。
  • Castle Dynamic Proxy: 提供了动态代理生成。

    The Orchard application and framework are built on top of these foundational frameworks as additional layers of abstraction. They are in many ways implementation details and no knowledge of NHibernate, Castle, or Autofac should be required to work with Orchard.

    Orchard 框架

    Orchard framework是Orchard架构的最底层。他包含了Orchard应用运行所必须的功能模块。他是Orchard框架的基础。

    Orchard启动

    当Orchard应用启动,会创建一个Orchard宿主,Orchard宿主是一个独立的应用程序域。

    然后,Orchard宿主会使用ShellContextFactory,创建当前租户(就是当前站点)的壳(Shell)。租户就是相互隔离的站点,但是他们都在同一个应用程序域上面。壳(shell) 是租户级别的独立域,他提供了租户级别的隔离,实现了multi-tenancy 功能。

    当壳创建的时候,会通过ExtensionManager中获取所有可用的扩展(模块或者样式)。默认获取扩展列表的方法,就是扫描模块和样式所在的文件夹。

    同时,壳还会通过SellSettingsManager获取当前租户的设置信息。

    然后,壳会获取CompositionStrategy对象,使用它,根据扩展列表和当前租户设置,来实现IOC。最终,它并不会为壳生成IOC容器,而是生成一张包含依赖列表、控制器、记录的蓝图(ShellBlueprint)。

    ShellContainerFactory.CreateContainer 通过壳设置(ShellSettings)和壳蓝图(ShellBlueprint),获取ILifetimeScope对象,这是租户层级的IOC容器域。

    依赖注入

    创建依赖注入对象的标准方法,是创建继承自IDependency或者其他特定接口的接口,然后实例化该接口。要使用该对象 的时候,你自需要在需要使用的类的构造函数中,将依赖注入对象作为参数传入,就可以了,Orchard框架会自动维护注入对象的生命周期。

    注入对象有3种生命周期,通过你创建注入对象接口的时候,继承的接口来区分:

  • Request: 每次请求都会重新创建,请求结束就会释放。你需要继承IDependency接口。
  • Object: 每个独立域中都会重新创建。你需要继承ITransientDependency接口。
  • Shell: Web应用的整个生命周期都会存在,不会释放。你需要继承ISingletonDependency接口。

    依赖顺序

    有些时候,我们希望特性顺序加载(默认情况下是一起加载),这时候,我们需要修改模块的manifest文件,更改特性的Dependencies属性:

    Features:

    Orchard.Widgets.PageLayerHinting:

    Name: Page Layer Hinting

    Description: ...

    Dependencies: Orchard.Widgets

    Category: Widget

    Priority: -1

    ASP.NET MVC

    Orchard is built on ASP.NET MVC but in order to add things like theming and tenant isolation, it needs to introduce an additional layer of indirection that will present on the ASP.NET MVC side the concepts that it expects and that will on the Orchard side split things on the level of Orchard concepts.

    For example, when a specific view is requested, our LayoutAwareViewEngine kicks in. Strictly speaking, it's not a new view engine as it is not concerned with actual rendering, but it contains the logic to find the right view depending on the current theme and then it delegates the rendering work to actual view engines.

    Similarly, we have route providers, model binders and controller factories whose work is to act as a single entry point for ASP.NET MVC and to dispatch the calls to the properly scoped objects underneath.

    In the case of routes, we can have n providers of routes (typically coming from modules) and one route publisher that will be what talks to ASP.NET MVC. The same thing goes for model binders and controller factories.

    内容类型系统

    Orchard的内容,通过一个类型系统来管理,这个系统,比如.net 类型系统更加的强大和灵活。为了给CMS系统更加的灵活, 类型在运行时组合,通过内容管理器维护类型之间的关系。

    类型、元件和字段

    Orchard能够处理任意的内容类型,包括动态生成的内容类型(后台配出来,没有写任何代码,这种内容类型是由不同的元件组合而成)。

    比如,博客帖子、产品、视频剪辑,都包含路由地址、评论、标签功能。所以,在Orchard中,我们将路由地址、评论、标签作为了元件。这样,评论功能,我们只需要开发一次,需要的内容类型只需要附加该元件即可,使用者不需要了解评论的具体实现。

    元件包含了属性和内容字段,内容字段也是可以重用的对象,它能够附加在不同的元件和内容类型中。 元件和字段的区别,在于他们的应用范围和语义。

    字段的颗粒度比元件更小。比如,字段用来描述电话号码或者坐标,而元件用来表述评论或者标签。

    但是,他们最重要的不同是他们的语义:元件是用于表述"is a(是一个)"关系,字段用于表述"has a(有一个)"关系。

    比如,衬衫是一个产品,它有一个SKU属性和一个单价属性。你可以说,衬衫是一个产品或者衬衫是由单价和SKU组成。

    据此,我们明白,衬衫内容类型由产品元件组成,产品元件由价格字段和SKU字段组成。

    字段和元件另外一个不同,在于一个内容类型只能附加一个元件,但是可以附加任意字段。所以,如果需要在同一内容类型中多次重复使用,我们只能使用字段。

    内容类型

    我们可以看到,内容类型,是由元件组成。元件,包含下面的部分:

  • record:元件的数据。
  • model:元件,继承之ContentPart<T>,T是Record。
  • repository:Record操作仓储,不需要开发人员自己实现,Orchard会自动生成一个。
  • handlers: Handlers实现了IContentHandler接口,提供了多个事件句柄,比如OnCreated、OnSaved。基本上,他会监控内容项的整个生命周期,执行相应的任务。 在他的构造函数中,还能够管理内容类型的组成(比如给特定的内容类型添加元件)。通过基类提供的Filter集合,能够为内容类型添加行为。
  • 比如,Orchard提供了StorageFilter,用于声明元件如何持久化,只需要下面一句代码:
  • Filters.Add(StorageFilter.For(myPartRepository)); 
  • 然后,Orchard就会使用myPartRepository来实现该元件的数据库持久化。
  • 我们可以使用ActivatingFilter,来把元件附加到特定内容类型上面:
  •  Filters.Add(new ActivatingFilter<BodyAspect>(BlogPostDriver.ContentType.Name)); 
  • 我们就可以将Body元件附加到博客帖子内容类型上面了。
  • Drivers:Drivers是一个友好的,特例化的handler,他继承ContentPartDriver<T>,只为当前元件服务。你可以将其看成一个针对特定元件的控制器。Driver使用主题引擎创建需要渲染的Shape。

    内容管理

    Orchard中所有的内容都通过ContentManager对象来管理。

    ContentManager提供了内容查询,内容归档,内容发布等功能。

    事务

    Orchard会在HTTP请求的时候,自动创建事务。这就是说,在一个请求中的所有操作,都是在一个事务中。如果请求过程中,事务终止,那么该请求发送的所有操作都会回滚。如果请求过程中,没有发生事务终止,那么请求结束前,会自动提交,不需要人为干涉。

    请求生命周期

    我们用一个实际的例子来说明问题。比如,我们请求访问一篇博客帖子。

    当请求一篇博客帖子的时候,应用首先会寻找匹配的路由。路由会解析请求,调用Controller的action处理请求,该action会从ContentManager中查询对应的帖子,获取到帖子的Page Object Model(POM)对象。

    博客帖子有自己的控制器,但是,并不是所有的内容类型都有自己特定的控制器。比如,动态内容类型会使用通用的ItemController控制器。Item控制器的行为和帖子控制器的行为很相似,都是通过ContentManager获取内容项,然后将其转换为POM对象。

    视图布局引擎会根据当前主题,获取正确的视图。

    在视图中,会创建动态Shape,比如块定义。

    主题引擎会使用模板和Shape方法,渲染页面,最终呈现在用户眼前。

    部件

    部件也是一种内容类型,不过他就有部件元件,并且stereotype属性配置为widget。就像其他的内容类型一样,也是由元件和字段组成。就是说,其操作方式和内容类型一致,内容类型,也可以通过附加部件元件,并将stereotype设置为widget,转变为部件。

    部件通过部件层添加到页面。层是部件的集合。他包含名称,规则(用于确定部件是否在页面渲染),部件列表及其和块的关系和排序顺序。

    规则使用IronRuby语法。

    站点设置

    Orchard中,站点也是一个内容项。不同的租户可以有不同的站点设置。

    消息总线

    Orchard and its modules expose extensibility points by creating interfaces for dependencies, implementations of which can then get injected.

    Plugging into an extensibility point is done either by implementing its interface, or by implementing an interface that has the same name and the same methods. In other words, Orchard does not require strictly strongly typed interface correspondence, which enables plug-ins to extend an extensibility point without taking a dependency on the assembly where it's defined.

    This is just one implementation of the Orchard event bus. When an extensibility point calls into injected implementations, a message gets published on the event bus. One of the objects listening to the event bus dispatches the messages to the methods in classes that derive from an interface appropriately named.

    命令

    Orchard后台可以进行的操作,有很多都可以通过命令来完成。在继承ICommandHandler,并打上CommandName特性的类中,我们可以自定义命令。

    查询和索引

    查询和索引默认是基于Lucence。当前,你也可以替换他。

    缓存

    Orchard的缓存是基于ASP.NET的缓存,我们对其进行了封装,提供了ICache接口。

    文件系统

    Orchard的文件系统,是对现有文件系统的抽象,他可以指向具体的物理路径,也可以指向云存储等第三方存储服务,这依赖于你的环境设置。我们可以通过查看媒体模块,详细了解Orchard文件系统。

    用户和角色

    用户也是内容项,这样,用户就可以通过元件进行扩展。角色是元件,附加到用户内容类型上面。

    权限

    任何的模块都可以自定义权限,来决定可以进行怎样的操作。

    任务

    模块可以通过IScheduledTaskManager的CreateTask方法,来创建定时任务。会有一个线程,来监控这些任务,在特定时间,触发他们。

    任务是允许在独立的线程上面,线程来源于线程池。

    通知

    通过调用INotifier类中的方法,我们可以向页面发送消息。

    本地化

    需要本地化的文本,都被包裹在T方法中:@T("This string can be localized")。Orchard的资源管理器,会调用存放在特定目录的本地化资源文件。请详见本地化这一章,了解本地化的具体实现。

    日志

    日志通过实例化ILogger来实现。不同的日志实现,会将日志存在不同的位置。Orchard默认使用Castle.Core.Logging来记录日志。

    Orchard 核心

    Orchard核心包含了Orchard运行所必须的模块。

    模块

    The default distribution of Orchard comes with a number of built-in modules such as blogging or pages, but third party modules are being built as well.

    这个模块就是一个ASP.NET MVC分区,包含manifest.txt文件来对模块进行说明,他是对Orchard的扩展。

    模块包含了handler、内容类型、默认的渲染方式、后台。

    模块中的文件更改以后,Orchard会自动对模块进行编译。这就意味着,你可以不使用visual studio等编程工具,就可以更改Orchard的源码。

    模块必须放在Modules文件夹中。

    主题

    在Orchard中,所有的HTML页面,都可以在主题中重写,哪怕这些页面是写在各个模块中的。Orchard中,页面是可以继承的(子主题基础父主题的所有页面)。

    Orchard页面渲染时基于Shape的。主题引擎,会找到当前的主题,然后渲染Shape。每一个Shape,都在各自的模块,有默认的渲染方式,但是,这种渲染方式,可以在主题中重写。

    主题有一个父主题,子主题中可以对父主题中的样式进行重定义。最顶层的父主题是"Theme Machine",他是一个很简单的,易于修改的主题。

    主题也可以写代码,就像模块一样。

    通过实现IThemeSelector接口,我们可以提供主题选择的功能,他返回主题的名称和优先级。Orchard提供了4个主题选择器:

    SiteThemeSelector: 选择当前的主题,具有低优先级。

  • AdminThemeSelector: 当URL路径是请求后台页面的时候,返回后台主题,具有高优先级。
  • PreviewThemeSelector: 当主题预览的时候,会重写当前主题。
  • SafeModeThemeSelector: 只有当站点处于"safe mode"是,才有效,比如站点安装的时候。它具有最低优先级。

    主题选择器的作用是,你可以创建一个移动主题选择器,当你使用移动设备的时候,返回专为移动设备开发的主题。

posted @ 2015-09-09 10:16  争世不悔  阅读(367)  评论(0编辑  收藏  举报