Orchard是如何工作的?

weixin_34293059發表於2017-10-19
對Orchard的理解還不深刻,翻譯可能有不好的地方.
 
 
開發CMS不同於開發其它的web專案,CMS的首要目標就是要支援擴充套件.
 
Orchard 架構
Modules
Core
Orchard Framework
ASP.NET MVC NHibernate Autofac Castle
.NET ASP.NET
IIS or Windows Azure
 
 
Orchard的地基
Asp.net MVC
NHibernate
Autofac
Castle Dynamic Proxy
 
Orchard Framework
Orchard Framework是最複雜的部分, 包含了Orchard的引擎和一些不能劃分到模組的部分. 幾乎所有的Module都依賴於它, 你可以將它看成是Orchard類庫。
 
啟動Orchard
當Orchard啟動的時候,會建立一個Host, host是App domain 級別的單例
下一步, host通過ShellContextFactory取得當前tanant的Shell.
tannat是一個程式例項, 不同的tannat有不同的使用者,他們分屬於不同的tannant而不知道其它tannat的存在。這個的目的是為了增加網站的密度。
shell是tanant級別的單例, 是tanant的具體呈現, 也是具體實現tannant隔離性的.
shell一旦建立, 將從ExtensionManager中獲取所有可用擴充套件, 這些擴充套件包括Module和Theme. 預設的實現是會自動掃描Module和Theme資料夾.
同時shell會從ShellSettingsManager獲取tannat的setting, 預設的實現會從Appdata的子資料夾中獲取。但是可以修改實現從其它地方獲取, 比如你有Azure 的實現, 使用blob storage而不是Appdata, 因為Appdata在那個環境下不可寫
shell然後取CompositionStrategy物件, 使用它構建IoC容器, 包含當前host的擴充套件和當前tanant的setting. 結果不是shell的IoC容器, 而是ShellBlueprint, 一個包含依賴項, controller和record的藍圖.
 
依賴注入
典型的在Orchard中使用依賴注入的方法是建立一個介面繼承IDependency或者它的子介面,然後建立類實現這個介面。
在使用依賴注入的地方, 你可以把這個介面型別作為建構函式引數, 這樣程式就能夠自動的發現依賴, 建立例項注入
 
有3中不同的生命週期, 所以要選擇好從哪個介面繼承:
Request生命週期: 每個Request請求的時候,建立一個,這樣的依賴必須建立的開銷要小。從IDependency介面繼承.
Object生命週期: 這要使用到了,就建立新instance, 這個依賴的必須建立的開銷更小. 從ITransientDependency介面繼承
Shell 生命週期: 一個shell/tanant才一個例項, 從ISingletonDependency繼承。注意只能要來儲存一些shell/tanant級別的型別
 
替換已有的依賴
可以通過使用OrchardSuppressDependency  attribute包裝你的類來達到替換現有依賴的目的。
 
依賴排序
有些依賴不是一個物件,有可能是一個List.
有時候,你想修改它們的順序, 這個可以通過修改module的manifest實現, 使用Priority屬性, 如下例:
Features:
    Orchard.Widgets.PageLayerHinting:
        Name: Page Layer Hinting
        Description: ...
        Dependencies: Orchard.Widgets
        Category: Widget
        Priority: -1
 
 
Asp.net MVC
Orchard是asp.net mvc實現的,但是為了實現Theme和tanant, 我們新增了一層.
 
比如, 當需要呈現某個view的時候,LayoutAwareViewEngine會先介入. 嚴格的說,這不是一個新的View Engine, 它不關注如何具體呈現,而是關注如何根據當前的Theme幫助尋找正確的view, 然後通知View Engine渲染.
 
這個類似於route providers, model binders和controller factories, 他們都是實現根據具體請求來實現分發的功能。
 
Content type系統
Orchard中的Content是由真實的型別系統管理, 比.net中的型別系統更加豐富和動態。為了在CMS中提供靈活性,Orchard中的content type必須在執行時組合。
 
Types, Parts和Fields
Orchard能夠處理任意的content type, 即使是由網站管理員在coe-free manner中動態建立的. 這些Content type都是為了應付某個特定需求的.
 
比如, 一篇blog,產品和視訊都有address, comment和tag. 所以, address, comment和tags在Orchard中被區分為不同的content type. 這樣,comment管理模組就只需開發一次然後應用到任意的conent type.
 
Fields比parts的粒度更小. 比如, Field可能只是用於描述一個電話號碼, 而part會用來描述comment, tag這樣一個完整的部分.重要的區別是, part表示的是"is a"的概念,而field表示的是"has a"的概念
比如, 衣服是產品, 它有SKU和price, 所以衣服這個Content type是由產品part組成, 而產品part是由Money型別的price和sting型別的SKU組成.
另外一個說法是part是一堆fields的字典,每個field有對應的name. content type是有一堆part type組成的。
 
這裡給出瞭如何判斷選擇part還是field, 如果你的content type是會有多個例項, 那麼就應該選擇field
 
剖析Content Type
Content type是由Content parts組成的. Content Parts一般有下面組成:
  • a record, 以POCO的方式來呈現part的資料
  • 一個model類繼承自ContentPart<T>, 這裡的T就是Record的資料型別
  • a repository. 這個repository不是必須有module來提供, 因為Orchard會預設會使用通用的
  • handlers. handlers繼承自IContentHandler, 包含一系列的event handlers, 比如OnCreated和OnSaved. 它們是content生命週期的hook, 達到在content生命週期中完成一些任務的目的。它們也可以通過content的建構函式來參與構建content. 在Base ContentHandler中, 有一個Filters的集合, 通過這個集合handlers可以為content type新增一些行為. 比如, Orchard提供了StorageFilter, 使得一個content type非常容易的宣告如何實現持久化, 只需要Filters.Add(StorageFilter.For(myPartRepository))
  • drivers. Drivers是更加友好和特殊的handler. handlers不和特定的content type關聯, 而drivers可以看做是特定part的一組Controllers. 它們常用於構建shapes, 然後由theme engine渲染.
Content Manager
Orchard中的所有cnotent都是通過ContentManager物件訪問的, 這也使得我們能夠在不知道content的型別的時候,就能夠使用它.
ContentManager提供了方法訪問content store, 版本管理contents, 和管理content狀態
 
Transactions
Orchard會自動地為每個http request建立transaction. 這也意味著一個request過程中所有的操作都是在transaction管理下的. 如果request abort transaction, 那麼所有的資料操作都會回滾. 如果transaction沒有被取消,那麼在request結束的時候,所有的資料操作會自動提交。
 
Request生命週期
這裡,我們拿request獲取一篇部落格作為例子.
當接收到一個請求要獲取一個blog post, 程式首先在所有可用的routes中選擇匹配的route, 這些route是有各個modules提供的. 當找到匹配的blog module的route, route會解析到特定的action, action會從content manager中獲取post, 然後action從content manager中獲取一個Page物件(通過BuildDisplay方法)
 
blog post有它自己的controller, 但是並不是所有的content type都是這樣. 比如, 動態的content type是有Core Routable part中對的通用的ItemController來處理的.
 
Layout view enginge將會根據當前的theme和model的型別來使用正確的view. 通過view, 動態shape建立.
 
Widgets
Widgets是content type, 包含widget content part和widget stereotype. 和其它的content types一樣, 它也是由parts和fields組成的. 這意味著它們和其它的content type一樣編輯和渲染, 也意味著content part也能夠比widget使用.
 
widgets通過widget layers新增到pages中. Layers是widgets的組成. 它們有name, 有rule決定網站中的那些pages能夠顯示, 和一組widgets,相關的zone placement和ordering, settings.
 
layers的rules是以IronRuby expressions的形式表示. 這些expressions能夠使用任何從IRuleProvider繼承的類.
 
Site Settings
orchard中的site是一個content item, 這就使得modules可以為它拼接其它的parts. 這也是為什麼modules能夠改變site settings.
Site settings對於每個tenant是獨立的.
 
Event Bus
Orchard和它的modules通過interfaces來暴露擴充套件點, 實現這些interface可以達到注入的目的.
為擴充套件點擴充套件可以通過繼承這些interfaces, 或者通過實現一個介面,名字一樣,方法也一樣. 也就是說, orchard對型別沒有強制要求.
 
Commands
Orchard中的很多action可以通過admin UI和命令列執行. 這些命令通過類繼承ICommandHandler, decorated with CommandName attribute.
 
Orhcard command line tool在執行時發現可用的命令, 模擬web site的環境.
 
Search and Indexing
search和indexing是通過預設使用Lucene, 你也一個通過替換成其它的indexing engine.
 
Caching
Orchard中的cache是基於asp.net的cache, 通過介面ICache的Get方法. Get提供一個key和一個function用來生成物件,如果沒有對應key的物件,就用function建立一個.
使用Orchard API的優勢是cache對於每個tenant是獨立的.
 
File Systems
Orchard中的File system是抽象的, 所以儲存可以放到物理儲存中, 或者其它的替代, 比如Azure blob storage.
Media module是使用抽象file sytem的一個例子.
 
Users and Roles
在Orchard中, Users是content items, 所以可以非常方便的擴充套件其它的fields. Roles是content part 用來拼接到Users.
 
Permissions
每個module能夠暴露一組permissions, 這些permissions對於orchard的預設roles如何設定
 
Tasks
模組能夠建立tasks通過呼叫IScheduledTaskManager中的CreateTask方法. Task能夠被實現IScheduledTaskHandler的執行. 執行處理的方法會檢查task的型別和name來決定是否處理這個task.
 
Tasks在一個獨立的,從asp.net thread pool上的一個thread上執行.
 
Notifications
模組能夠呈現message到admin UI上, 通過INotifier的實現的方法.
 
Localization
程式的Localization是通過包裝string資源, <%: T("This string can be localized") %>.
Orchard的資源管理能夠從PO檔案中載入本地化資源.
Content Item的localization通過其它的方法:localized的content item是通過一個獨立的part來實現的.
當前的culture是通過culture manager來決定的. 預設的是通過site settings配置的, 但是可以被user profile和browser's settings覆蓋.
 
Logging
Logging是通過ILogger的實現來將日誌儲存不同的介質的.
 
Orchard Core
Orchard.Core assembly中包含了Orchard必須的modules. 其它的模組可以依賴於這些一定存在的模組.
core modules比如: feeds, navigation, routeable.
 
Modules
Orchard有一些內建的模組, 比如blogging, pages.
modules是一個asp.net mvc area 和manifest.txt檔案, 用來擴充套件orchard.
module典型的包含handlers, content types和預設模板和admin UI.
modules當csproj檔案有變動的時候,就能夠被動態編譯,
 
 
Themes
Orchard的設計的基本原則是所有的Html都是能夠通過替換theme來替換的.
Orchard渲染的基礎是Shapes. theme engine的工作是找到當前的theme和如何最好的渲染每個shape. 每個shape有個default渲染, 在module中的模板view資料夾或者程式碼中的shape方法中. default渲染能夠被theme重寫.
 
Themes可以有個parent.
Themes能夠和modules一樣包含程式碼, 能夠有自己的csproj檔案, 能夠動態編譯.
選擇當前theme是通過IThemeSelector實現, 會返回一個theme name和針對request的priority. Orchard有4種實現IThemeSelector:
 
  • SiteThemeSelector使用在Site或者tenant中的設定, 優先順序低.
  • AdminThemeSelector如果當前是admin URL, 使用admin theme. 優先順序高
  • PreviewThemeSelector是如果當前是預覽模式下使用預覽的theme
  • SafeModeThemeSelector是隻有當程式執行在"safe mode"的時候才使用的. 級別低.
theme selector的使用的一個例子是當發現請求是從mobile過來的,就是用mobile theme.
 

相關文章