请注意,本站并不支持低于IE8的浏览器,为了获得最佳效果,请下载最新的浏览器,推荐下载 Chrome浏览器
欢迎光临。交流群:166852192

Orchard是如何运行的


建立一个CMS网站(内容管理系统)是不同于建立一个普通的web站点:它更像是建立一个应用程序容器。 设计这样一个系统时,必须建立一流的可扩展性功能。这必需是一个非常开放式的构架,但是一个开放性的系统可能会影响应用程序可用性的挑战,在系统中的需要与未知的未来模块的组合,包括在用户界面级别,编排所有这些小零件,让互不知道的彼此成一个连贯的整体,是Orchard是关键。
本文解释了我们在orchard的构架的选择,以及是如何解决,特别是如何获得灵活性和良好的用户体验问题。

构架

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工具。它处理内容项到数据库的持久性,并从模块开发中移除对持久性的关注,这大大简化了数据模型。你可以从任何核心内容类型的源代码中看到这种例子,例如 pages。
  • Autofac: Autofac是一个IoC Container.Orchard大量使用了依赖注入。创建一个可注入Orchard依赖就像写一个类一样简单,直接或间接实现IDependency 接口,而使用依赖很简单,可以采取正确类型的构造器参数。注入依赖的范围和生存时间由Orchard framework管理。你能在IAuthorizationService的源代码中看到示例。
  • Castle Dynamic Proxy: 使用Castle动态产生代理。
  • Orchard程序和框架在这些框架的基础上构建额外的抽象层,根据Orchard的开发指南实际上对于Nhibernate,Castle,Autofac有许多方式实现细节我们并不需要了解。

    Orchard Framework



    Orchard Framework是Orchard的最底层,它包含了应用程序引擎和至少不能被分离成模块的部分。这些都是必须的东西,甚至最基本的模块也不得不依赖它,可以将它理解为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会发现所有依赖并在需要时初始化和注入实例。
    有三种不同的可能范围的依赖,选择一个从右边的接口派生的实现。
  • Request: 为每个http请求创建的依赖实例,并在请求完成后销毁。
  • Object: 创建新的实例,在接口上对象每一次依赖。实例不共享,派生自ITransientDependency,对象必须很容易创建。
  • Shell: 每个shell/tenant仅创建一个实例,派生自ISingletonDependency,为shell的生命周期必须维护一个公共策略。
  •  

    替换现有的依赖

    可能用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 名称和价格。

    内容类型剖析



    内容类型是由内容元件构建的,内容元件代码通常与下面的有关联:
  • Record:是part数据的POCO表示
  • Model:实体的part,从ContentPart<T>继承,T是record type
  • Repository:模块作者不需要实现Repository,Orchard将能使用一个通用的。
  • handlers:handlers实现了IContentHandler接口,是事件处理的集合,如OnCreated , OnSaved。基本上他们在内容项目的生命周期中执行多项任务。他们也能参与构造器内容项目的实际组成。有一个基于ContentHandler 的Filters集合,为内容类型添加公共行为的处理程序。例如:Orchard提供了一个StorageFilter 使它很容易的声明 如何持久化内容类型 应该怎么处理:just do drivers.
  • driver:是更友好更特别的处理程序(因此不太灵活),并与一个指定的content part type关联(从ContentItemDriver 继承,T 是一个content part type)。另一方面的处理器没有指定一个content part type.Drivers 能看做具体part的 controller,他们通常建立主题引擎呈现的shapes。
  •  

    内容管理

    所有的内容都通过ContentManager对象访问,这让你使用事先不知道类型的内容成为可能。ContentManager 一些方法,查询内容存储库,内容版本,并管理发布状态。

    处理(Transactions)



    Orchard自动为每个HTTP请求创建一个事务,这意味着请求过程中的所有操作都是事务中的一部分。如果请求代码中断,所有数据操作都将回滚。如果事务没有显示取消,请求结束所有操作都会提交,不需要显示commit。

    请求的生命周期(Request Lifecycle)



    下面介绍一篇博文的请求。
    当请求一篇指定的博文,程序首先寻找各种模块定义的可用的路由并找到博文模块匹配的路由,然后路由解析请求发给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出现的顺序和递归。

    部件(Widgets)



    部件是有Widget content part和widget stereotype的内容类型。像任何其他的内容类型,由元件和字段组合而成。这意味着,他们可以使用同一版本的编辑和渲染其他类型的内容的逻辑,他们像积木一样任何content part能像widget的一部分被重用。
    部件能过部件层级添加到页面,层级是部件的集合,他们有名称,规则,确定能出现在网站的哪个页面、部件列表、关联区域位置、排序、设置。
    每个层级的规则使用IronRuby表达式,在程序中所有IRuleProvider的实现都能使用这些表达式,Orchard有两个box实现:url 和 authenticated.

    网站设置(Site Settings)



    Orchard中的网址是一个内容项,这使得它可以为模块添加额外的元件,这是模块能如何进行site settings,每个租户都有Site settings。

    事件总线(Event Bus)



    Orchard和它的模块通过创建依赖接口暴露扩展点,然后实现注入。
    通过实现它的接口完成插入扩展点,或实现与接口具有相同的名称和方法。换句话说,Orchard不需要严格的强类型接口通信,启用插件扩展扩展点不需在程序集上定义的地方依赖。
    这仅仅是Orchard 事件总线的一种实现,当扩展点用调用注入实现,一条消息被发布在事件总线上,以适当命名的接口派生的类中的方法的对象之一监听事件总线发送的消息。

    命令(Commands)



    Orchard网站的很多行为都能通过命令行执行。这些命令是实现了ICommandHandler的类中的标记了CommandName 特性的方法。Orchard命令行工具在运行时模拟网站环境和使用反射检查程序集来发现可用的命令。命令执行的环境尽可能的实际运行的网站。

    搜索和索引(Search and Indexing)



    搜索和索引默认通过使用Lucene来实现,但是默认实现可以用其它索引引擎替换。

    缓存(Caching)



    Orchard中的cache依赖 ASP.NET cache,但是我们暴露了一个helper api,可以通过一个ICache类型的依赖调用get方法使用。如果cache没有包含请求项,Get方法取得key和function可用于生成 cache entry’s value。使用Orchard cache api的主要好处是每个租户透明地工作。

    文件系统(File Systems)



    Orchard中的文件系统是抽象的,以便存储能被定向到物理文件系统或Azure的blog存储的备用存储,取决于环境。Media模块就是使用抽象文件系统的例子。

    用户和角色(Users and Roles)



    Orchard中的用户是content items,一个很容易为一个模块的配置并用额外的field扩展它们的content item,角色是能被链接到用户的content part。

    权限(Permissions)



    每个模块都能公开一组权限,以及如何将这些权限授予Orchard的默认角色。

    任务(Tasks)



    模块能通过调用IScheduledTaskManager类型的依赖的CreateTask方法安排任务。该任务能被实现了 IScheduledTaskHandler接口的类型执行。这个执行方法能检查任务类型名称并决定是否处理。任务在ASP.NET线程池的一个单独线程上运行。

    通知(Notifications)



    模块能使用INotifier 依赖并调用它的方法在管理界面浮出消息,任何请求的一部分可以创建多个通知。

    本土化(Localization)



    程序和模块的本地化通过调用T()方法中包装字符串资源来完成,@T(This string can be localized)Orchard的资源管理能从位于程序指定位置的PO文件装载本地化的资源字符串。
    Content item的本地化通过不同的机制完成:content item的本地化版本是物理上独立的内容。
    目前使用的文化是由culture manager决定。返回文化的默认实现在site setting中设置,但一个备用实现可以从用户配置信息和浏览器的设置获取。

    日志(Logging)



    日志依赖ILogger实现,不同的实现可以发送到不同存储类型的日志条目。

    Orchard Core



    Orchard Core程序集包含一组Orhcard运行所必须的模块。其它模块可以安全地依赖到这些模块上,这些模块总是可用的。比如 feeds,navigation,routable模块。

    模块(Modules)



    Orchard默认发行版包含了一些内置模块,像 blogging,pages,但第三方模块也同样能创建。
    一个模块就是扩展Orchard的包含manifest.txt文件的ASP.NET MVC Area。
    一个模块通常包含事件处理程序,内容类型,它们的默认呈现模板以及一些管理界面。
    每次修改模块都能从源代码动态编译。这种”记事本”风格的开发并没有指定需要显示编译或甚至需要使用Visual Studio。

    主题(Themes)



    这是Orchard中的基本设计原则,产生的所有HTML都能用主题替换,其中包含模块产生的标记。公定了文件必须在主题中的层次。
    Orchard中的渲染机制基于shapes,主题引擎的工作是查找当前主题以及确定渲染每个shape最好的方式是什么。每个shape能有一个默认的渲染,可以由模块在代码中定义 像视图目录中的模板或像一个shape方法,默认渲染可能被当前的渲染覆盖。
    主题可以有一个父主题,能使子主题专门化或改写。Orchard自带了基础默认主题叫 Theme Machine,设计成作为父主题很容易使用。
    主题能包含代码,他们能有自己的csproj文件,有利于动态编译。这使主题定义shape方法,但也会暴露其拥有的所有设置管理界面。
    当前主题的选择通过实现IThemeSelector的类实现,返回主题名称和任何请求的优先级,Orchard自带了IThemeSelector的4个实现。
  • SiteThemeSelector 为当前租户的配置或低优先级的网站选择一个主题。
  • AdminThemeSelector 返加一个高优先级的admin主题,只要当前URL是一个管理url。
  • PreviewThemeSelector 预览主题。
  • SafeModeThemeSelector 当应用程序运行在 safe mode时 是唯一的可选项,通常在安装时使用,它有一个非常低的优先级。
  • 主题选择的一个例子:可以使用户使用移动设备时推出一个移动主题。
    参考文章:http://docs.orchardproject.net/Documentation/How-Orchard-works



作者原创内容不容易,如果觉得内容不错,请点击右侧“打赏”,赏俩给作者花花,也算是对作者付出的肯定,也可以鼓励作者原创更多更好内容。
更多详情欢迎到QQ群 166852192 交流。