惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
爱范儿
爱范儿
J
Java Code Geeks
L
LangChain Blog
V
V2EX
大猫的无限游戏
大猫的无限游戏
S
SegmentFault 最新的问题
博客园 - Franky
Microsoft Azure Blog
Microsoft Azure Blog
Jina AI
Jina AI
Blog — PlanetScale
Blog — PlanetScale
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The Cloudflare Blog
博客园 - 司徒正美
B
Blog
G
Google Developers Blog
Stack Overflow Blog
Stack Overflow Blog
罗磊的独立博客
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
Engineering at Meta
Engineering at Meta
MyScale Blog
MyScale Blog
有赞技术团队
有赞技术团队
Hugging Face - Blog
Hugging Face - Blog

博客园 - 二十四画生

Orchard 1.3新功能之——规则(Rules) Orchard 1.3新功能之——Markdown编辑器 Orchard 1.3 发布了! Orchard中的计划任务功能(Schedule) Orchard网站App_Data目录里的文件介绍 在Orchard中使用样式及脚本 Orchard中的多站点功能(Multi-Tenant) Orchard中的多语言功能 Orchard中的列表功能 Orchard中的用户、角色及权限 自定义Orchard站点辅助工具——Shape Tracing Orchard中的形状候补(Alternates) Orchard是如何呈现内容的 理解Orchard中的placement.info文件 详解Orchard主题(Theme) 在Orchard中创建一个自定义字段类型 在Orchard中为命令行工具(Command-Line)添加一个新命令 在Orchard中处理一对多关系 在Orchard中创建一个主题(Theme)
Orchard动态编译机制
二十四画生 · 2011-07-27 · via 博客园 - 二十四画生

Posted on 2011-07-27 11:46  二十四画生  阅读(7406)  评论()    收藏  举报

Orchard作为一个可扩展的CMS系统,需要在运行时加载一些模块或主题(统称扩展)。从Orchard 0.5版起就致力于让安装和升级这些扩展变得更加简单。Orchard和其他任何一个ASP.NET MVC应用程序一样,都可以在Visual Studio环境下编译。但是Orchard还提供了另外一种模块加载策略,例如,它允许模块的dll无需部署在网站的bin目录下。此外Orchard还可以动态的根据模块源代码来编译模块。这样可以比较灵活的部署dll文件,并且可支持在没有Visual Studio环境的情况下随时编译所修改的模块源代码。这有点类似于ASP.NET的“App_Code”文件夹,只不过Orchard支持更多的这样的文件夹。本文将从技术层面上描述Orchard是如何加载模块并动态编译的。

概述

Orchard应用程序启动时,Orchard框架(具体由ExtensionLoaderCoordinator类负责)需要明白安装了那些模块并激活他们(就是加载这些模块的dll)。更细化的来说这个过程分为三个阶段:

1、发现:搞清楚目前网站都有哪些模块。

2、激活:搞清楚用什么策略来激活或加载每一个模块。

3、引用解析:搞清楚激活这些模块都需要引用那些程序集。这个阶段技术属于“激活”阶段的一部分,但它作为一个单独的部分更容易去思考关于引用解析的问题。

一旦模块被正取激活,它们将在进一步检查去检测并启用个别的功能,不过这个就不是本文需要讨论的主题了。

发现

列出Orchard中可用的模块是通过查询一些文件夹下面的“module.txt”文件获得的。下面将分别列举这些默认查询的文件夹:

"~/Modules" 文件夹

"~/Modules" 文件夹包含了大多数Orchard模块。Orchard约定每一个模块存储在一个名为<ModuleName>的子文件夹中,并且需要包含一个“module.txt”文件。打包、发布和分析模块只此次文件夹下的模块。这个文件夹就是用户自定义扩展Orchard模块的文件夹。

"~/Core"文件夹

"~/Core"文件夹包含一些Orchard中最核心的模块,这些模块有Orchard团队提供。用户通常不在这里添加新的模块。

"~/Themes"文件夹

"~/Themes"文件夹包含了Orchard主题。作为动态编译,主题几乎被当作模块一样处理,处理主题没有代码(bin 和 .csproj文件)。本文的其余部分,当我们提到“模块”时,他同样也适用于“主题”。

注:”~/”表示网站根目录。

示例

下面是一个Orchard安装实例,其中包含6个扩展:两个核心模块“Common”和“Localization”,两个应用模块“Foo”和“Bar”,还有两个主题“T1”和“T2”。

RootFolder
  Core
    Common
      module.txt  <= "Common" module from "Core"
    Localization
      module.txt  <= "Localization" module from "Core"
  Modules
    Foo
      module.txt  <= "Foo" module
    Bar
      module.txt  <= "Bar" module
  Themes
    T2
      theme.txt  <= "T1" theme
    T2
      theme.txt  <= "T2" theme

激活

一旦Orchard从发现阶段收集了所有的“module.txt”文件,Orchard将使用不同的策略(或“模块装载机”)在内存中加载这些模块。在内部,加载模块的行为,是一种活动。作为输入“module.txt”文件并返回一个“System.Type”列表。请注意,这有别于返回一个“System.Assembly”列表,因为Orchard支持一个程序集包含多个模块,如:“Orchard.Core.dll”就包含了约10个Orchard模块。Orchard目前实现了以下模块加载策略(装载机):

“已引用模块”装载机

这个装载机在“~/bin”目录中查找“module.txt”文件中模块名对应的程序集,如果这个程序集存在,它将加载并返回改程序集的所有类型。这种加载机用于当所有模块都是预先编译好的,并且其dll都存储在“~/bin”目录中的情况,这是一种典型“asp.net mvc”应用程序方式。

“核心模块”装载机

如果“module.txt”文件来自于"~/Core"文件夹,核心模块装载机将返回来自于Orchard.Core.dll中,"Orchard.Core.<moduleMame>"命名空间下的所有类型。Orchard.Core.dll是一个特殊的程序集,它包含了Orchard核心模块,在Orchard框架基础上提供一些基本功能。

“预编译模块”装载机

如果“module.txt”文件来自于"~/Modules" 文件夹,预编译模块装载机将在“~/Modules/<ModuleName>/bin”中查找名为<moduleMame>的程序集。如果这个文件存在,它将被复制到"~/App_Data/Dependencies"文件夹下,这是一个特殊的文件夹,是用于ASP.net查找“~/bin”文件夹以外程序集的地方。

“动态模块”装载机

如果“module.txt”文件来自于"~/Modules" 文件夹,动态模块装载机将在“~/Modules/<ModuleName>/bin”中查找.csproj文件。如果这个文件存在,这个装载机将使用Orchard编译管理器根据.csproj文件来编译程序集并返回改程序集的所有类型。

注:这个装载机在系统执行的时候只有一个,常常被称为“动态编译”。事实上这是可以选择的,如果所有模块都是预编译好的,也可以选择其他的装载机。

装载机选择

既然可能有不止一个装载机能够加载一个指定的模块,Orchard是如何做到选择正确的呢?每个装载机都可以返回一个相应模块的 “最后修改时间”,对于存在多个装载机时,Orhcard根据最新的“最后修改时间”来决定使用何种装载机。例如:一个模块包含所有的源文件包括.csporj文件和已经编译到bin目录中的dll。第一次加载模块的时候,Orchard会在bin目录中加载程序集,应为源代码比程序集新的情况会比较少。然而,如果源代码有了任何改变后,动态模块装载机返回的“最后修改时间”大于在bin目录中加载程序集的“最后修改时间”,Orchard将采用动态模块装载机。值得注意的是这种分歧只存在于"~/Modules" 文件夹下的模块,因为"~/Core"文件夹下的模块只会采用核心模块装载机。

示例

RootFolder
  Bin
    Orchard.Web.dll
    Orchard.Core.dll
    Foo.dll
  Core           
    Common        <= "Core Module" loader
      module.txt
    Localization  <= "Core Module" loader
      module.txt
  Modules
    Foo           <= "Reference Module" loader (because a "~/bin/Foo.dll" file exists)
      module.txt
    Bar           <= "Precompiled Module" loader (because a "~/Modules/Bar/bin/Bar.dll" file exists)
      bin
        Bar.dll
      module.txt
    Baz           <= "Dynamic Module" loader (because a "~/Modules/Baz/Baz.csproj" file exists)
      Controller
         BazControler.cs
      Baz.csproj
      module.txt

引用解析

动态模块加载机将根据.csproj文件中References节点的内容在模块的Bin目录中查找模块所引用的其他程序集文件,并将其复制到"~/App_Data/Dependencies"文件夹下。注意模块所引用的其他dll需要复制到模块Bin目录下,并起引用位置也要在此目录中。

配置更改检测

正如上文所述,在应用程序启动时加载模块。然而,一旦应用程序启动,改变依然可能随时发生,如:一个模块的源代码可能手动更新,一个模块可能会在网站上安装或删除等。来检测这些变化,就需要Orchard提供一个“监视”潜在变化的机制并在发生变化是通知模块装载器。当检测到变化时,当前模块的配置将被丢弃并且将同时重新审查、加载和激活模块,就像应用程序重新启动一样。在某些情况下,这些变化需要一个ASP.net的AppDomain重新启动(如:一个新版本模块的程序集需要被加载),Orchard将检测这样的情况并让一个ASP.net AppDomain重新启动。

"~/App_Data/Dependencies/Dependencies.xml" 文件

这个文件包含了最后一次成功加载应用程序时的模块、装载机和模块所引用的程序集列表。查看这个文件的内容,可以用于调试,检测相应的dll是否被加载。 

参考文档

http://www.orchardproject.net/docs/Orchard-module-loader-and-dynamic-compilation.ashx