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)是如何工作的_第1张图片
上图只是简单的描述了一下获取内容部件数据的执行流程,要想用好这一功能还需要仔细研究代码好好体会(可查看Orchard核心层关于内容显示部分的代码:\Orchard.Web\Core\Contents\Controllers\ItemController.cs)。另外Orchard的视图引擎功能也需要好好研究,这样才能更好的掌握灵活定制界面的功能。在这里姑且先把它理解成一个黑盒子。只要给它一个动态对象,它就能根据构成这个动态对象的部件分别找到呈现的模板,从而组合输出我们想要的界面。等有深入了解后再来揭开这个黑盒子的秘密吧。

示例

如果我们需要实现一个产品内容部件,其功能就是显示产品的一些特有信息,如:价格、品牌等。
其驱动器的代码如下:

 

ProductPartDriver.cs
using  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 
{    
    
///   <summary>
    
///  Driver相当于内容部件的Controller
    
///   </summary>
     public   class  ProductPartDriver : ContentPartDriver < ProductPart >  
    {
        
///   <summary>
        
///  显示界面显示时执行(相当于Action)
        
///   </summary>
        
///   <param name="part"> 相当于此Part的Model </param>
        
///   <param name="displayType"> 显示类型(如:"details"(详情显示)或 summary(摘要显示)") </param>
        
///   <param name="shapeHelper"> 类似视图引擎之类的东西,可以根据相应显示的动态对象去找对应的显示模板(相当于View) </param>
        
///   <returns> 这里相当于是返回了一个ActionResult,Orchard框架会针对这个返回值进行相应处理 </returns>
         protected   override  DriverResult Display(ProductPart part,  string  displayType, dynamic shapeHelper)
        {
            
return  ContentShape( " Parts_Product " , ()  =>  shapeHelper.Parts_Product(
                Price: part.Price,
                Brand: part.Brand));
        }

        
///   <summary>
        
///  编辑界面显示时执行(Get)
        
///   </summary>
        
///   <param name="part"></param>
        
///   <param name="shapeHelper"></param>
        
///   <returns></returns>
         protected   override  DriverResult Editor(ProductPart part, dynamic shapeHelper)
        {
            
return  ContentShape( " Parts_Product_Edit " ,
                () 
=>  shapeHelper.EditorTemplate(
                    TemplateName: 
" Parts/Product " ,
                    Model: part,
                    Prefix: Prefix));
        }

        
///   <summary>
        
///  编辑界面提交时执行(Post)
        
///   </summary>
        
///   <param name="part"></param>
        
///   <param name="updater"></param>
        
///   <param name="shapeHelper"></param>
        
///   <returns></returns>
         protected   override  DriverResult Editor(ProductPart part, IUpdateModel updater, dynamic shapeHelper)
        {
            updater.TryUpdateModel(part, Prefix, 
null null );
            
return  Editor(part, shapeHelper);
        }
    }

 

其处理器的代码如下:

 

ProductHandler.cs
using  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
{
    
///   <summary>
    
///  处理器相当内容部件的Filter
    
///  目前仅针对该产品内容部件的存储进行定义
    
///   </summary>
     public   class  ProductHandler : ContentHandler 
    {
        
public  ProductHandler(IRepository < ProductRecord >  repository)
        {
            
// 定义ProductPart的数据存储是通过IRepository<ProductRecord>进行处理的
            
// IRepository就把它理解为数据访问层类
            Filters.Add(StorageFilter.For(repository));
        }
    }

 

总结

通过本文,我们又学习了Orchard中的两个概念:驱动器和处理器,并了解了它们是如何工作、如何实现内容部件功能的。这部分的内容,是Orchard中最具特色的地方,了解和掌握这部分的内容就可以向开发真正具有Orchard特色的模块进发了

 

参考文档:

你可能感兴趣的:(content)