Orchard作为一个组件化的CMS,它能够在运行时加载任意模块。
Orchard和其它ASP.NET MVC应用一样,支持通过Visual Studio来加载已经编译为程序集的模块,且它还提供了自定义的模块加载策略,如允许加载没有部署到"~/bin"目录下的程序集模块。
另外,Orchard还支持直接部署源代码然后动态编译的功能,这个功能比这届部署二进制文件更灵活,而且还可以在一些适合的地方在不使用Visual Studio的情况下自定义代码,类似与ASP.NET的App_Code目录,但是Orchard支持多个独立的目录(一个模块一个)。
本章的目的是在技术层次描述Orchard如何加载模块,这个功能经常被认为是Orchard的动态编译,即使动态编译技术仅用于非常特殊的场景。
概述
当Orchard应用程序启动时,Orchard框架(确切的将是ExtensionloaderCoordinator)计算出那些模块被安装并激活它们(加载相应程序集)。
在顶层看来,这个过程主要有三个步骤:
- 查找:找出这个网站有那些模块。
- 激活:找出使用什么策略来加载这些模块。
- 解决引用依赖:找出哪些引用程序集用于激活模块。这个是激活部分,但是需要在这里就考虑如何处理模块的依赖问题。
搜索
Orchard通过搜索不同目录下的"module.txt"和"theme.txt"文件来获取到一个可用的拓展列表。这些目录主要有:
"~/Modules"目录
该目录下面包含了大量的Orchard模块,并约定每一个模块存放在一个以模块名称命名的子目录下,每一个目录下有一个"module.txt"文件,这个目录仅支持模块的打包、分配和共享。
"~/Core"目录
这个目录包含了一个"Orchard.Core"的程序集,该程序集中包含的模块是Orchard系统中的核心部分,这些模块不能像"~/Modules"目录下的模块那样自由修改。
"~/Themes"目录
这个目录下面包含了Orchard主题,关于动态编译,主题和模块基本类似,除了主题不需要代码。
自定义目录
在Orchard1.10版本中提供了新的功能,允许从自定义的目录下加载拓展模块。自定义的目录可以在AppSetting中配置。
例子
下面这个例子中Common和Localization是Core模块,Orchard.Azure和Orchard.Caching是内置的模块,SafeMode和TheAdmin是内置主题,MyModule1和MyModule2是自定义路径中的自定义模块,MyBase和MyTheme是自定义主题目录下的自定义主题。
激活
当Orchard收集到所有的"Module.txt"后,Orchard将使用不同策略来将这些模块加载到内存中。在程序内部,"加载模块"这个动作是一个以"module.txt"文件作为输入然后将一个类型为"System.Type"的列表作为输出的操作。这将比简单的返回一个"System.Assembly"更通用,这样Orchard可以支持在一个程序集中包含多个模块,如Orchard.Core.dll中包含了大约10个模块。
"引用模块"加载器
这个加载器查找"~/bin"目录下的和"module.txt"文件中指定模块名称一致的程序集,如果这个程序集存在,那么将这个模块加载然后返回它所有的类型。这个加载器用于通过"ASP.NET的方式"加载一些已经预编译好在"~/bin"目录下的程序集(注:这里一般是因为Orchard的根程序引用了其中某一些模块,以致于根程序编译时会将该程序集放置到~/bin目录下,这种情况ASP.NET就会自动加载该程序集,而加载器的功能主要用于获取该程序集的所有类型)。
"核心模块"加载器
如果"module.txt"文件是从"~/Core"目录下来的,那么CoreExtensionLoader将从Orchard.Core程序集的"Orchard.Core.<模块名称>"的命名空间下返回所有类型。Orchard.Core包含多个被称为核心的模块,它们在Orchard Framework上提供了一些基础功能。
"预编译模块"加载器
如果"module.txt"来自"~/Modules"目录,那么该加载器就会到"~/Modules/<ModuleName>/bin"目录下根据模块名称查找程序集文件,如果存在,那么将它复制到"~/App_Data/Dependencies"目录下,这个目录是一个特殊的目录,它用于ASP.NET应用程序在"~/bin"目录之外查找附加的程序集。
"动态模块"加载器
如果"module.txt"来自"~/Modules"目录,且在"~/Modules/<ModuleName>"目录下存在".csproj"文件,那么该加载器就会使用Orchard build manager编译这个.csproj文件,并返回该程序集的所有类型。
注:该加载器是Orchard中唯一一个使用"动态编译"的加载器,而且如果该模块已经预编译,那么它是可选的。
加载器二义性处理
因为有可能出现一个给定模块被多个加载器加载,所以Orchard有一个处理歧义的方法,如选择"正确的"加载器。每一个加载器在加载模块时都能够返回一个模块"最新修改时间"。对于一个给定模块,如果存在多个加载器,那么Orchard将选择返回的"最新修改时间"最近的加载器。
例如,一个给定模块即存在包含.csproj文件的源代码且bin目录下也存在编译好的程序集。模块的第一次加载,Orchard会加载"bin"目录下的程序集,虽然可能这个程序集不是最新的(代码编译后,代码被修改)。但是对于Orchard来说如果代码在编译后产生任何的修改,"动态模块"加载器将返回一个文件最近的修改时间(代码或csproj文件),然后Orchard将根据时间来选择正确的加载器(预编译加载器还是动态编译加载器)。
需要注意的是对于Core模块来说,它只有一种加载方式,所以不会出现二义性。
例子
禁用"动态模块"加载器
在生产环境应该禁用动态加载,因为生成环境不应该动态的安装、加载模块,而另一些原因是因为动态加载会创建很多FileSystemWatcher(影响性能)来检测模块变化。
禁用该加载器需要在HostComponents.config文件中加入以下内容:
然后部署该文件并重启应用池。
注:你必须检查每一个模块的bin目录是否已经存在编译后的程序集。
配置的变化检测
正如上面介绍的,Orchard应用程序在启动时将加载相关模块。然而一旦应用程序启动,可能会发生变化,如:可能安装新模块、手动改变源代码、删除模块等等。为了检测这些改变,Orchard让每一个加载器监控变化然后在发生变化时发送通知。
当变化被检测到,当前模块的配置将被废弃然后在应用程序再一次启动时重新验证、加载、激活模块。一些情况下,这些改变需要ASP.NET应用域重启(如新版本程序集的加载)。Orchard监听这些情况并强制重启ASP.NET应用程序域。
~/App_Data/Dependencies/Dependencies.xml文件
这个文件包含了模块的列表、这些模块的加载器和模块最后一次正确的引用配置,它是Orchard最后一次运行成功的所有模块的配置信息。它可以用于检查新版本模块是否被加载等等。
原文:
翻译这篇文档的原因是,它详细的对Orchard拓展模块加载内容进行了介绍,而接下来将从代码层面分析以上内容是如何实现的。
- Orchard详解--第八篇 拓展模块及引用的预处理
从上一篇可以看出Orchard在处理拓展模块时主要有两个组件,一个是Folder另一个是Loader,前者用于搜索后者用于加载. 其中Folder一共有三个:Module Folder.Core Fo ...
- Orchard详解--第三篇 依赖注入之基础设施
Orchard提供了依赖注入机制,并且框架的实现也离不开依赖注入如模块管理.日志.事件等.在前一篇中提到在Global.asax中定义的HostInitialization创建了Autofac的IoC ...
- Orchard详解--第六篇 CacheManager 2
接上一篇,关于ICacheContextAccessor先看一下默认实现,用于保存一个获取上下文,且这个上下文是线程静态的: public class DefaultCacheContextAcces ...
- Orchard详解--第五篇 CacheManager
上一篇文章介绍了Orchard中的缓存,本篇主要针对CacheManager进行分析,CacheManager在Orchard中用于存储应用程序的配置信息以及框架内部的一些功能支持,包括整个拓展及拓展 ...
- Orchard详解--第四篇 缓存介绍
Orchard提供了多级缓存支持,它们分别是: 1. 应用程序配置级缓存ICacheManager: 它用来存储应用程序的配置信息并且可以提供一组可扩展的参数来处理缓存过期问题,在Orchard中默认 ...
- PE文件格式详解(七)
PE文件格式详解(七) Ox00 前言 前面好几篇在讲输入表,今天要讲的是输出表和地址的是地址重定位.有了前面的基础,其实对于怎么找输出表地址重定位的表已经非常熟悉了. 0x01 输出表结构 ...
- IIS负载均衡-Application Request Route详解第四篇:使用ARR实现三层部署架构(转载)
IIS负载均衡-Application Request Route详解第四篇:使用ARR实现三层部署架构 系列文章链接: IIS负载均衡-Application Request Route详解第一篇: ...
- [转]ANDROID L——Material Design详解(动画篇)
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 转自:http://blog.csdn.net/a396901990/article/de ...
- appledoc导出iOS代码文档的使用和问题详解(干货篇)
appledoc导出iOS代码文档的使用和问题详解(干货篇) 1. 简单说一下背景和自己感受 背景: 项目好像突然黄了,公司让详细写项目代码的注释并且导出文档,弄完之后就要封版. 说实话:听到这个消息 ...
随机推荐
- TCP/IP 笔记 - TCP数据流和窗口管理
TCP流量控制机制通过动态调整窗口大小来控制发送端的操作,确保路由器/接收端消息不会溢出. 交互式TCP连接 交互式TCP连接指该连接需要在客户端和服务器之间传输用户输入信息,如按键操作.短消息.操作 ...
- 使用Expression进行动态排序分页
Expression动态查询.分页 Expression,表达式树,以lamda表达式创建,就以表达式目录树的形式将强类型的lambda表达式标识为数据结构. 排序 /// <summary&g ...
- [NewLife.XCode]数据初始化
NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netstandard,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量结合示 ...
- 简单快速的让你的json解析速度快上加快
背景 最近小编在做公司的一个需求.要求是把系统内的一些大型文本文件上传到第三方那里,而且第三方要求的交互数据的方式是采用post请求发送json串的形式进行的. 问题 做到中途才发现问题,由于单个文本 ...
- 解读经典-《C#高级编程》第七版-Chapter1-.Net体系结构-Page1-6
前言 大家好.这是开通本号的第一篇文章.从事IT行业已经20年了,从使用PowerBuilder做企业信息系统开始,做了七八年开发,然后转型Java不是很成功,从07年之后,我转做产品经理,机缘巧合, ...
- 聊聊数据库~2.SQL环境篇
传统数据库 上篇文章:聊聊数据库~开篇 https://www.cnblogs.com/dotnetcrazy/p/9690466.html 本来准备直接开讲NoSQL的(当时开篇就是说的NoSQL) ...
- Flask入门第二天
一.请求钩子 在客户端和服务器交互的过程中,有些准备工作或稍微工作是需要处理的,比如:在请求开始时,建立数据库连接:在请求开始时,根据需求进行权限校验:在请求结束时,指定数据的交互格式等.为了让每个视 ...
- 分享一个用QT实现的Mjpeg-streamer客户端(简易版)
mainWindow代码如下(由于篇幅问题,子窗口代码不贴出了,有需要源码的可以留下邮箱): /* * Author : 博客园 Lance# */ #include "mainwindow ...
- 数据分析面试题之Pandas中的groupby
昨天晚上,笔者有幸参加了一场面试,有一个环节就是现场编程!题目如下: 示例数据如下,求每名学生(ID)对应的成绩(score)最高的那门科目(class)与ID,用Python实现: 这个题目 ...
- Python图像处理之图片文字识别(OCR)
OCR与Tesseract介绍 将图片翻译成文字一般被称为光学文字识别(Optical Character Recognition,OCR).可以实现OCR 的底层库并不多,目前很多库都是使用共同 ...