天天看點

如何擴充Orchard

翻譯自:

<a href="http://msdn.microsoft.com/en-us/magazine/hh708754.aspx">http://msdn.microsoft.com/en-us/magazine/hh708754.aspx</a>

動态類型系統

Content item是Orchard中的原子, 比如blog post, pages, products, widgets

探索Content item原子

作為開發者,我們首先會想到Content item是一個類的執行個體(比如blog post類), 類中包含了property, method等. 實際的Content item不是由簡單類型的屬性等組成的, 而是由content part組成,這是Orchard中的重要概念.

一個blog post典型的由URL, title, date, rich text body, tags和comments這些parts組成. 但是這些parts不隻是為blog post所用. 比如tag, rich text body也會被用在page上.

另外, CMS中的content type并不是一成不變的. Blog post以前是simple text, 但是很快就發展的更加複雜. 可以包含videos, podcasts或者image galleries. 甚至, 如果你在旅行, 你會在blog post中提供位置服務.

Content parts是解決變化的key, 需要位置服務, 那麼隻需要給blog post content item添加上mapping part. 這些不能有developer來做,而是admin來. 是以, 擴充不能是依賴于.net的一些類型的, 而是metadata-driven, 在運作時建立, 能夠通過背景頁面管理. 下圖就是Orchard的content type編輯頁.

Orchard擴充方法:

使用背景的Orchard Content type editor

界面能做的事情,也可以通過代碼實作, 如下:

item.Weld(part);

上面的代碼是在content item中動态的添加了part. 但這隻是給instance添加了part, 如果我們想給該Content type都添加上part, 可以這樣:

上面的方式也是實際上blog post content type的建構方式:

<a></a>

你可能注意到blog post content type中沒有包含tags和comments. 的确是這樣, orchard系統是通過其它方式來實作添加tags和comments的.

點菜

site有個初始化的xml檔案, 在site setup的時候, 會根據這個配置來初始化content type, 下面是blog post的配置.

建立Part

這是一個為添加keyword和description的part, 可以用來提高SEO友好. 具體使用的樣子:

在上面填寫的内容會生成到頁面上:

The Record

第一步是要解決如何存儲這些資訊到資料庫. 嚴格的說, 并不是所有的part都需要record, 因為不是所有的part的資料都存在資料庫中.

下面是我們用來存儲keywords和description的MetaRecord:

繼承自ContentPartRecord不是必須的, 但是繼承的話比較友善. 這個類有2個屬性, 都是virtual的, 這是為了讓orchard在運作的時候能夠友善的生成proxy.

添加MetaHandler來實作資料庫存儲.

對于資料庫的修改migration

上面的代碼, 第一部分是建立表, 并且和record比對.

第二部分是說明任何content type都可以從Admin UI上attach MetaPart

The Part Class

實際的Part是另外一個類, 繼承自ContentPart

這裡的這個Part做成了MetaRecord的代理類. 如果沒有代理MetaRecord的屬性, 也可以通過父類ContentPart的Record屬性通路到.

任何使用了MetePart的Content item, 都能夠友善的通路到Keywords和Description屬性

var metaKeywords = item.As&lt;MetaPart&gt;().Keywords;

Parts也應該是你具體實作一些behavior的地方, 比如, 一個組裝機器的part, 可以添加方法或者property來列舉它的部件或者計算總價.

至于Part添加的這些behavior如何和使用者互動,這就是drivers要做的事情.

The Driver

Content item中的part都有機會參與到request的生命周期中和在asp.net MVC controller起作用. 但是隻能在request的部分生命周期中起作用, 而不是全部.

Content part driver扮演這個角色, 它不是一個完整意義上的controller, 沒有route比對到它的方法.

它是為一些事先定義好的events寫響應的方法, 比如Display, Editor.

Driver繼承自ContentPartDriver.

這個driver實際上不是典型的, 因為大部分的drivers result是rendering, 這裡要把meta part呈現到head的meta标簽中.

HTML的head section是shared resource, 是以有一些特殊處理.

Orchard提供了API通路這些shared resource. 這裡我使用了resource manager來設定metatags. resource manager會呈現實際的tags.

之是以這個方法傳回null是因為它不需要呈現任何東西到頁面上. 一般driver的方法需要傳回一個稱做shape的dynamic type, 類似于asp.net mvc中的 view model.

它是一個非常flexible的對象, 你能夠接上任何東西, 比對對應的template來呈現它, 并不需要建立一個特定的view model類

Editor方法是用來呈現改part editor UI的. 比較典型的是傳回一個特殊的shape對象用來, 組合成edition UI.

driver中的最後一個方法是處理從editor發送回來的post請求:

這個方法中的代碼調用了TryUpdateModel自動地更新part資料. 當更新完成, 再調用Editor方法來傳回同樣的editor shape.

Rendering Shapes

通過調用所有的parts的drivers, Orchard能夠建立一個shapes tree, 在整個request中建立一個龐大的動态的view model.

下一個任務是搞清楚如何通過templates來呈現這些shapes. 它是通過每個shape的名字(如果是editor方法, 就是Parts_Meta_Edit)在整個系統定義範圍内尋找模闆檔案, 比如目前的theme和module的views檔案夾.

這是非常重要的擴充點, 因為它允許你能夠重寫系統的呈現, 隻需要你在你的theme中放入正确name的template 檔案即可.

在Views\EditorTemplates\Parts下的我的module檔案夾下, 我寫了一個Meta.cshtml檔案

所有的都是content

在我講到其它擴充的時候, 我想提醒一旦你懂了content item type系統, 你就懂得了Orchard中最重要的部分. 很多系統中重要的部分都是定義成了content item.

比如, a user是content item, 這樣我們能夠友善的添加properties到profile modules中. 我們也有widget content item, 能夠呈現到theme定義的zones中. 這是orchard中如何顯示search form, blog archives, tag clouds和其它的sidebar UI的方式.

但最使人意外應該是site本身也使用了content items. orchard中的 site settings也是content items, 這也是orchard的優勢所在. 當你想添加自己的site settings的時候, 你所要做的就隻是再添加一個新的part到site content type中, 然後添加一個admin edition UI. 一個統一擴充的content type系統是一個非常好的概念.

打包Extensions

Extensions都是以modules的方法分發的, 和實作相關的是以themes分發.

典型的Theme是一堆圖檔, stylessheets和templates, 打包放到Themes檔案夾下. 一般也有一個theme.txt檔案來定義一些metadata資訊.

類似的, module是在Modules檔案夾下. 它也是一個asp.net mvc area, 包含了一些配置. 比如, 它需要一個module.txt來說明module的metadata。

作為一個大網站的area, module需要能夠處理好和一些share resources的關系. 比如, routes必須定義在一個繼承IRouteProvider的類中. Orchard會取所有modules的route來建構整個網站的route. 類似地, modules能夠實作INavigationProvider來建立新的admin menu.

有意思的是, module的代碼通常不是以編譯好的二進制釋出(雖然這是可行的). 這是一個有意的安排, 我們鼓勵對于module的修改, 當你從gallery下載下傳一個module的時候,你可以動手修改來滿足你的需求.

可以自己動手修改代碼是一些PHP CMS的強大之處, 比如Drupal, wordpress, 是以我們也想在Orchard中提供這個. 當你下載下傳一個module的時候,你下載下傳了它的源代碼, 然後動态編譯. 當你改動了代碼, 改動立馬生效,然後module會重新編譯.

依賴注入

目前,我們都在關注type system擴充, 因為這是orchard modules的主要功能, 但是orchard有很多其它的擴充點. 我想說一些使用這個架構的重要的原則.

一個重要的是在這個松散的module系統中做正确的事情. 在Orchard中, 機會所有低級别至上的都是module. 甚至modules都是由某個module來管理的. 如果你想這些modules之間不互相耦合, 那麼你實作的時候,就要注意解耦合.

實作這個的方法是使用依賴注入. 當你需要使用一個class的時候, 你不要直接執行個體化它, 那樣會導緻你直接依賴于那個class. 你需要建立一個接口來抽象那個class, 然後用這個接口對象作為構造參數.

通過上面的例子, 你依賴于接口,而不是class, 不管這個接口的實作如何, 你都不需要修改你的代碼.

具體使用這個接口的代碼中不需要具體指明如何執行個體化. 這樣就實作了控制反轉, 具體提供什麼執行個體則是有framework來決定的.

當然, 這不限于orchard定義的接口. 任何module都能夠提供它們自己的擴充點, 隻需要指明繼承自IDependency, 非常簡單.

一些其它的擴充點

這裡, 我隻是揭示一下擴充點. Orchard中有很多的接口可以用于擴充. 更加誇張的說, orchard什麼都不是, 隻是一個可以随意擴充的engine. 系統中所有的東西都包裝成了擴充.

在結束本文之前, 我想說一下系統中一些非常有用的接口. 由于沒有更大的篇幅來說的更深, 但是可以指明一個方向, 你可以深入代碼中去看看這些接口的用法.

IWorkContextAccessor 可以讓你的代碼來通路目前request的work context. work context提供了HttpContext, current layout, site configuration, user, theme和culture資訊. 它也提供了方法取得某個接口的具體實作.

IContentManager提供了你要查詢和管理content items的所有東西

IRepository&lt;T&gt; 提供了方法通路更低級别的資料, 如果IContentManager不夠用, 可以用這個.

IShapeTableProvider 是用來提供shape的. 你可以再shapes中攔截事件, 可以修改shapes, 添加members, 在layout上移動shapes.

IBackgroundTask, IScheduledTask and IScheduled­TaskHandler 是一些接口來實作諸如在背景執行一些時間長,或者定期執行的任務的

IPermissionsProvider 運作你自己的module來定義你module中的權限.

本文轉自JustRun部落格園部落格,原文連結:http://www.cnblogs.com/JustRun1983/archive/2013/04/12/3015900.html,如需轉載請自行聯系原作者