orchard,Orchard中的内容部件(Content Part)是如何工作的

在《理解Orchard中的内容管理》一文中我们介绍了Orchard中组织内容的方式。其中谈到了一个非常关键东西——内容部件(Content Part)。每一个内容部件都是一个完整的小功能块,它里面实现自身功能的UI呈现和数据存取,这也就是说它实现了一个从UI层到数据库层的完整封装。那这个功能是如何实现的呢?
我们知道在ASP.NET MVC中有一个PartialView 的概念,可以实现一个UI层的封装,如果这个部分的数据需要单独存储,那么就是还是需要由相应action来执行。但是Orchard的内容部件可能是要在其他模块中调用,其存储数据操作也是在其他模块中的action中执行的。如何很好的解决在其他模块的action中执行自身内容部件数据存储及显示的问题,是实现内容部件功能的关键。在Orchard中引入了两个东西来解决这个问题——驱动器(Driver)和处理器(Handler)。

驱动器(Driver)

驱动器是一个类,通常继承于Orchard框架中的ContentPartDriver,可重写其查看界面显示方法(Display)、编辑界面显示方法(Editor—Get时执行),编辑界面提交方法(Editor—Post时执行),还有其他一些导入导出之类的方法。从这些重写的方法来看,驱动器就好比是内容部件的Controller,驱动器中的方法就好比是内容部件的action。

处理器(Handler)

处理器也是一个类,通常继承于Orchard框架中的ContentHandler,它定义了相应内容部件的行为、事件以及在呈现前操作数据模型。我们可以把它理解为内容部件的Filter,负责告诉Orchard框架如何处理你的Part。

如何工作

当有一个request请求需要显示一个内容的时候。系统首先是根据Route规则找到该请求对应的Controller中对应的action。然后在此action中通过IContentManager接口取获取内容。在用IContentManager获取内容的时候,Orchard框架会自动通过相关内容部件处理器所提供的数据存储Filter来获取相关部件的数据。接下来通过BuildDisplay构建一个需要显示到视图上的动态类Model,组成内容的各个部件都作为这个动态类的属性。最后Orchard视图引擎根据各部件驱动器所提供的显示方法,找到对应的显示模板,最终组合成一个UI呈现给用户。呈现编辑页面和提交编辑数据的原理大致相同。内容部件工作示意图如下:
Orchard中的内容部件(Content Part)是如何工作的orchard
上图只是简单的描述了一下获取内容部件数据的执行流程,要想用好这一功能还需要仔细研究代码好好体会(可查看Orchard核心层关于内容显示部分的代码:\Orchard.Web\Core\Contents\Controllers\ItemController.cs)。另外Orchard的视图引擎功能也需要好好研究,这样才能更好的掌握灵活定制界面的功能。在这里姑且先把它理解成一个黑盒子。只要给它一个动态对象,它就能根据构成这个动态对象的部件分别找到呈现的模板,从而组合输出我们想要的界面。等有深入了解后再来揭开这个黑盒子的秘密吧。

示例

如果我们需要实现一个产品内容部件,其功能就是显示产品的一些特有信息,如:价格、品牌等。
其驱动器的代码如下:
Orchard中的内容部件(Content Part)是如何工作的orchardOrchard中的内容部件(Content Part)是如何工作的orchardProductPartDriver.csusing System; using System.Linq; using JetBrains.Annotations; using Orchard.ContentManagement; using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement.Handlers; using Orchard.Security; using MyCompany.Products.Models; namespace Orchard.Products.Drivers { /// /// Driver相当于内容部件的Controller /// public class ProductPartDriver : ContentPartDriver { /// /// 显示界面显示时执行(相当于Action) /// /// 相当于此Part的Model
/// 显示类型(如:"details"(详情显示)或 summary(摘要显示)")
/// 类似视图引擎之类的东西,可以根据相应显示的动态对象去找对应的显示模板(相当于View)
/// 这里相当于是返回了一个ActionResult,Orchard框架会针对这个返回值进行相应处理 protected override DriverResult Display(ProductPart part, string displayType, dynamic shapeHelper) { return ContentShape("Parts_Product", () => shapeHelper.Parts_Product( Price: part.Price, Brand: part.Brand)); } /// /// 编辑界面显示时执行(Get) /// ///
///
/// protected override DriverResult Editor(ProductPart part, dynamic shapeHelper) { return ContentShape("Parts_Product_Edit", () => shapeHelper.EditorTemplate( TemplateName: "Parts/Product", Model: part, Prefix: Prefix)); } /// /// 编辑界面提交时执行(Post) /// ///
///
///
/// protected override DriverResult Editor(ProductPart part, IUpdateModel updater, dynamic shapeHelper) { updater.TryUpdateModel(part, Prefix, null, null); return Editor(part, shapeHelper); } }

其处理器的代码如下:
ProductHandler.csusing System; using System.Collections.Generic; using System.Linq; using System.Web; using Orchard.ContentManagement.Handlers; using MyCompany.Products.Models; using Orchard.Data; namespace MyCompany.Products.Handlers { /// /// 处理器相当内容部件的Filter /// 目前仅针对该产品内容部件的存储进行定义 /// public class ProductHandler : ContentHandler { public ProductHandler(IRepository repository) { //定义ProductPart的数据存储是通过IRepository进行处理的 //IRepository就把它理解为数据访问层类 Filters.Add(StorageFilter.For(repository)); } }

总结

通过本文,我们又学习了Orchard中的两个概念:驱动器和处理器,并了解了它们是如何工作、如何实现内容部件功能的。这部分的内容,是Orchard中最具特色的地方,了解和掌握这部分的内容就可以向开发真正具有Orchard特色的模块进发了Orchard中的内容部件(Content Part)是如何工作的orchard
参考文档:
写一个内容部件:http://www.orchardproject.net/docs/Writing-a-content-part.ashx
理解内容处理器:http://www.orchardproject.net/docs/Understanding-content-handlers.ashx
Tags:  orchard

延伸阅读

最新评论

发表评论