Skip to content

Introduction

介绍

As a composable CMS, Orchard has the ability to load an arbitrary set of modules (also known as "extensions") at run-time. One of the goals of the 0.5 release was to make the process of installing and updating modules as easy as possible.

作为可组合的CMS,Orchard能够在运行时加载任意模块集(也称为“扩展”)。 0.5版本的目标之一是尽可能简化安装和更新模块的过程。

Orchard, like any ASP.NET MVC application, supports loading modules compiled as assemblies using Visual Studio. Orchard also offers a customized module loading strategy which, for example, allows loading assemblies for modules without having to deploy them in the ~/bin folder.

与任何ASP.NET MVC应用程序一样,Orchard支持使用Visual Studio加载编译为程序集的模块。 Orchard还提供定制的模块加载策略,例如,允许加载模块的程序集,而不必将它们部署在〜/ bin文件夹中。

In addition to that, Orchard supports the ability to dynamically compile modules deployed as source code only (this is still somewhat experimental). This is more flexible than deploying binaries, and enables some interesting scenarios such as "in place" code customization without having to use Visual Studio. This is somewhat similar to the ASP.NET App_Code directory, except Orchard supports multiple "logical folders" (typically one per module) independently.

除此之外,Orchard还支持动态编译仅作为源代码部署的模块的能力(这仍然是一些实验性的)。这比部署二进制文件更灵活,并且可以启用一些有趣的方案,例如“就地”代码自定义,而无需使用Visual Studio。这有点类似于ASP.NETApp_Code目录,除了Orchard独立支持多个“逻辑文件夹”(通常每个模块一个)。

The goal of this section is to describe at a technical level how Orchard loads modules in the 0.5 release. This feature is often referred to as "Orchard Dynamic Compilation", even though technically dynamic compilation is only involved in very specific cases.

本节的目标是在技术层面描述Orchard如何在0.5版本中加载模块。此功能通常称为“Orchard动态编译”,即使技术上动态编译仅涉及非常具体的情况。

High Level Overview

高级概述

When an Orchard application starts, the Orchard Framework (the ExtensionLoaderCoordinator class to be precise) needs to figure out what are the modules installed in the Web Site and activate them (typically by loading their assembly).

当Orchard应用程序启动时,Orchard Framework(确切地说是“ExtensionLoaderCoordinator”类)需要弄清楚Web站点中安装的模块是什么并激活它们(通常通过加载它们的程序集)。

At a high level, this process can be divided in 3 distinct phases:

从较高的层面来看,这个过程可分为3个不同的阶段:

  • Discovery: figure out what are the modules present in the web site

  • Discovery:弄清楚网站上的模块是什么 *

  • Activation: figure out what strategy to use to "activate" (or load) each module

  • Activation:找出用于“激活”(或加载)每个模块的策略 *

  • References Resolution: figure out what are the assembly references needed to be activated for each module. This phase is technically part of the "Activation" phase, but it is easier to think about the problem of reference resolution as a separate concern.

  • References Resolution:找出每个模块需要激活的程序集引用。此阶段在技术上是“激活”阶段的一部分,但更容易将参考分辨率问题视为一个单独的问题。 *

Once modules are properly activated, they are further examined to detect and enable individual features, but this is a topic for another section.

一旦模块被正确激活,它们将被进一步检查以检测并启用单个_features_,但这是另一部分的主题。

Discovery

发现

The list of available extensions in an Orchard installation is built by searching various folders of the file system for Module.txt and Theme.txt files. The folders looked at by default are listed in the following sections.

通过在“Module.txt”和“Theme.txt”文件中搜索文件系统的各种文件夹来构建Orchard安装中的可用扩展列表。默认情况下查看的文件夹将在以下部分中列出。

~/Modules Folder

〜/ Modules文件夹

The ~/Modules folder is intended to contain the vast majority of Orchard modules. The convention is that each module is stored in a sub-folder named <ModuleName> containing a single Module.txt file. Packaging, distribution and sharing of modules is only supported for modules in the ~/Modules folder.

〜/ Modules文件夹旨在包含绝大多数Orchard模块。惯例是每个模块都存储在一个名为<ModuleName>的子文件夹中,该子文件夹包含一个Module.txt文件。模块的打包,分发和共享仅支持〜/ Modules文件夹中的模块。

~/Core Folder

〜/ Core文件夹

The ~/Core folder contains, by convention, modules defined in the Orchard.Core assembly. These modules are part of the "Core" Orchard system and are not intended to be modified as freely as modules in the ~/Modules folder.

按照惯例,〜/ Core文件夹包含在Orchard.Core程序集中定义的模块。这些模块是“Core”Orchard系统的一部分,不能像〜/ Modules文件夹中那样自由地修改。

~/Themes Folder

〜/ Themes文件夹

The ~/Themes folder is intended to contain Orchard Themes. With respect to dynamic compilation, Themes are treated almost exactly the same as Modules, except that Themes don't have to have code (assembly in bin or .csproj file). For the rest of this page, when we refer to "Module", it should be understand that the concept applies to "Theme" the same way.

〜/ Themes文件夹旨在包含Orchard主题。关于动态编译,主题被视为与模块几乎完全相同,除了主题不必具有代码(在bin.csproj文件中汇编)。对于本页的其余部分,当我们引用“模块”时,应该理解该概念以相同的方式应用于“主题”。

Custom Folders

自定义文件夹

Orchard 1.10 introduced a new feature that allows the loading of extensions from custom-defined folders outside of the ones listed above by adding the ExtensionLocations service that is utilised by each extension loader (see the Loaders in the Activation section below).

Orchard 1.10引入了一项新功能,允许通过添加每个扩展加载器使用的ExtensionLocations服务,从上面列出的文件夹之外的自定义文件夹中加载扩展(请参阅下面“激活”部分中的Loaders) )。

Additional extension folders can be configured by defining an AppSetting (e.g. by adding it to the root web.config file, which contains appropriate examples) with the key Modules and/or Themes with their respective value being e.g. ~/Modules.Custom and/or ~/Themes.Custom.

可以通过定义“AppSetting”(例如,将其添加到rootweb.config文件,其中包含适当的示例)来配置其他扩展文件夹,其中包含键“Modules”和/或“Themes”及其各自的value例如〜/ Modules.Custom和/或〜/ Themes.Custom

Example

Here is an example of an Orchard installation which contains the following extensions: Common and Localization (Core modules), Orchard.Azure and Orchard.Caching (built-in modules), SafeMode and TheAdmin (built-in themes), MyModule1 and MyModule2 (custom modules), MyBaseTheme and MyTheme (custom themes).

下面是一个Orchard安装示例,其中包含以下扩展:CommonLocalizationCore modules),Orchard.AzureOrchard.Caching(内置模块),SafeModeTheAdmin(内置主题),MyModule1MyModule2(自定义模块),MyBaseThemeMyTheme(自定义主题)。

Root (Orchard.Web)

  Core

    Common

      Module.txt  <= "Common" module from "Core"

    Localization

      Module.txt  <= "Localization" module from "Core"

  Modules

    Orchard.Azure

      Module.txt  <= "Orchard.Azure" module

    Orchard.Caching

      Module.txt  <= "Orchard.Caching" module

  Modules.Custom

<font color=#0099ff size=4 face="黑体">Modules.Custom</font>


    MyModule1

MyModule1

      Module.txt  <= "MyModule1" module

    MyModule2

MyModule2

      Module.txt  <= "MyModule2" module

  Themes

    SafeMode

      Theme.txt  <= "SafeMode" theme

    TheAdmin

      Theme.txt  <= "TheAdmin" theme

  Themes.Custom

<font color=#0099ff size=4 face="黑体">Themes.Custom</font>


    MyBaseTheme

      Theme.txt  <= "MyBaseTheme" theme

    MyTheme

      Theme.txt  <= "MyTheme" theme

Activation

激活

Once Orchard has collected all the Module.txt files from the discovery phase, Orchard uses distinct strategies (or "Module Loaders") to load these modules in memory. Internally, the act of "loading a module" is an activity that takes a Module.txt file as input and returns a list of System.Type as output. Note that this is slightly more generic than simply returning a System.Assembly, as it allows Orchard to support multiple modules per assembly. For example, the Orchard.Core.dll assembly currently contains about 10 modules.

一旦Orchard收集了发现阶段的所有Module.txt文件,Orchard就会使用不同的策略(或“模块加载器”)将这些模块加载到内存中。在内部,“加载模块”的行为是一个活动,它将Module.txt文件作为输入,并返回一个System.Type列表作为输出。请注意,这比仅返回System.Assembly稍微更通用,因为它允许Orchard支持每个程序集的多个模块。例如,Orchard.Core.dll程序集目前包含大约10个模块。

The Orchard framework currently implements the following loaders:

Orchard框架目前实现以下加载器:

"Referenced Module" Loader

“参考模块”装载机

This loader looks in ~/bin directory for a assembly name corresponding to the module name specified in Module.txt. If the assembly exists, it is loaded and all its types are returned. This loader is useful when someone wants to deploy an Orchard web site where all modules are pre-compiled and stored in ~/bin, in a typical "asp.net web application" way.

这个加载器在〜/ bin目录中查找与Module.txt中指定的模块名对应的程序集名。如果程序集存在,则会加载它并返回其所有类型。当有人想要部署一个Orchard网站时,这个加载器非常有用,其中所有模块都是以“〜/ bin”的形式预先编译并存储在典型的“asp.net web应用程序”中。

"Core Module" Loader

“核心模块”装载机

If Module.txt indicates a module from the ~/Core folder, the CoreExtensionLoader returns the types from the Orchard.Core.<ModuleName> namespace of the Orchard.Core assembly. Orchard.Core is a special assembly containing modules that are "core" to the system, i.e. offering basic functionality on top of the Orchard Framework.

如果Module.txt表示来自〜/ Core文件夹的模块,则CoreExtensionLoader从Orchard.Core程序集的Orchard.Core。<ModuleName>命名空间返回类型。 Orchard.Core是一个特殊的程序集,包含对系统“核心”的模块,即在Orchard框架之上提供基本功能。

"Precompiled Module" Loader

“预编译模块”加载器

If Module.txt indicates a module from the ~/Modules folder, the PrecompiledExtensionLoader looks for an assembly named <ModuleName> in the ~/Modules/<ModuleName>/bin folder. If the file exists, its is copied to the ~/App_Data/Dependencies folder, which is a special folder used by ASP.NET to look for additional assemblies outside of the traditional ~/bin folder.

如果Module.txt表示来自〜/ Modules文件夹的模块,PrecompiledExtensionLoader〜/ Modules / <ModuleName> / bin文件夹中查找名为<ModuleName>的程序集。如果该文件存在,则将其复制到〜/ App_Data / Dependencies文件夹,该文件夹是ASP.NET用于查找传统〜/ bin文件夹之外的其他程序集的特殊文件夹。

"Dynamic Module" Loader

“动态模块”装载程序

If Module.txt indicates a module from the ~/Modules folder, the "Dynamic Module" loader looks for a file named <ModuleName>.csproj in the ~/Modules/<ModuleName> folder. If the file exists, the loader will use the Orchard build manager for .csproj files to compile the file into an assembly and return all the types from that assembly.

如果Module.txt表示来自〜/ Modules文件夹的模块,则“Dynamic Module”加载器在〜/ Modules / <ModuleName>文件夹中查找名为<ModuleName> .csproj的文件。如果该文件存在,则加载器将使用Orchard构建管理器来处理.csproj文件,以将该文件编译为程序集并返回该程序集中的所有类型。

Note: This loader is the only one in the system performing what is often referred to as dynamic compilation, and is indeed optional if modules have been pre-compiled.

注意:这个加载器是系统中唯一一个执行通常称为“动态编译”的加载器,如果模块已经预编译,它确实是可选的。

Loader Disambiguation

装载机消歧

Since there is potentially more than one loader able to load a given module, Orchard has to have a way to resolve the ambiguity, i.e. pick the "right" loader. Each loader has the ability to return a "date of last modification" for each module they can load. For a given module, if there are multiple candidate loaders, Orchard will pick the loader which returns the most "recent" date of last modification.

由于可能有多个加载器能够加载给定模块,因此Orchard必须有办法解决模糊性,即选择“正确”加载器。每个加载器都能够为它们可以加载的每个模块返回“上次修改日期”。对于给定的模块,如果有多个候选加载器,Orchard将选择返回最后一次修改的“最近”日期的加载器。

For example, a given module can be distributed with both full source code (including .csproj file) and compiled into an assembly in its bin directory. The first time the module is loaded, Orchard will pick the loader for the assembly in bin since it's very likely the assembly was compiled after the last source code change was made. However, if any change was made to the source code afterward, the "Dynamic Module" loader will return the date of the most recently modified file (either the source file or .csproj), and Orchard will pick that loader for the given module.

例如,给定的模块可以与完整的源代码(包括.csproj文件)一起分发,编译到其bin目录中的程序集中。第一次加载模块时,Orchard将在bin中选择装配的加载程序,因为很可能在最后一次源代码更改后编译了程序集。但是,如果之后对源代码进行了任何更改,“动态模块”加载器将返回最近修改过的文件的日期(源文件或.csproj),Orchard将为给定的加载器选择该加载器模块。

Note that the "Core Module" loader is never ambiguous, because there is only one way to load these modules. The ambiguity can only arise for modules in the ~/Modules directory.

请注意,“核心模块”加载器永远不会模糊,因为只有一种方法可以加载这些模块。模糊性只能出现在〜/ Modules目录中的模块中。

Example

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

Disabling the "Dynamic Module" loader

禁用“动态模块”加载程序

The dynamic module loader should be useless when deploying a website in production, as a production enviroment it

在生产中部署网站时,动态模块加载器应该是无用的,作为生产环境

should not be able to install and load module dynamically. But another important reason why it should be disabled

不应该能够动态安装和加载模块。但它应该被禁用的另一个重要原因

is that it creates a lot of FileSystemWatcher instances to detect changes on the modules.

是它创建了很多FileSystemWatcher实例来检测模块的变化。

To disable the module, rename the file \Config\Sample.HostComponents.config to \Config\HostComponents.config,

要禁用该模块,请将文件\\ Config \\ Sample.HostComponents.config重命名为\\ Config \\ HostComponents.config

then check the content is:

然后查看内容是:

<?xml version="1.0" encoding="utf-8" ?>

<HostComponents>

  <Components>

    <Component Type="Orchard.Environment.Extensions.ExtensionMonitoringCoordinator">

      <Properties>

        <Property Name="Disabled" Value="true"/>

      </Properties>

    </Component>

  </Components>

</HostComponents>

Deploy this file and restart the App Pool.

部署此文件并重新启动应用程序池。

NB: You will have to ensure that the binaries for every modules are available in the /bin folder of each module,

注意:您必须确保每个模块的二进制文件在每个模块的/ bin文件夹中可用,

such that the Precompiled Module loader can use them directly. When using Visual Studio this should be the case.

这样预编译模块加载器可以直接使用它们。使用Visual Studio时应该是这种情况。

Otherwise use the command line tool to build the website, which will have the same effect.

否则使用命令行工具来构建网站,这将具有相同的效果。

References Resolution

参考决议

(TODO: Explain how Orchard figures out references by looking at the "References" section of the csproj file as well as looking at additional assembly binaries dropped in each module bin directory)

(TODO:解释Orchard如何通过查看csproj文件的“References”部分以及查看每个模块bin目录中删除的其他程序集二进制文件来确定引用)

Change of Configuration Detection

配置检测的变更

As explained above, modules are loaded at application startup. However, once the application is started up, changes can happen: a new module might be installed, the source code of a module might be manually updated, a module might be removed from the site, etc. To detect these changes, Orchard asks each module loader in the system to "monitor" potential changes, and notify when a change happens.

如上所述,在应用程序启动时加载模块。但是,一旦应用程序启动,可能会发生更改:可能会安装新模块,可能会手动更新模块的源代码,可能会从站点中删除模块等。要检测这些更改,Orchard会询问每个模块系统中的模块加载器“监视”潜在的变化,并在发生变化时通知。

When a change is detected, the current module configuration is discarded and modules are re-examined, loaded and activated as if the application was starting up again. In some cases, these changes require an ASP.NET AppDomain restart (e.g. a new version of a module assembly needs to be loaded). Orchard detects these situations and forces an ASP.NET AppDomain restart.

检测到更改时,将丢弃当前模块配置,并重新检查,加载和激活模块,就像应用程序再次启动一样。在某些情况下,这些更改需要重新启动ASP.NET AppDomain(例如,需要加载新版本的模块程序集)。 Orchard检测到这些情况并强制重新启动ASP.NET AppDomain。

Rendering Web Forms Views

呈现Web窗体视图

(TODO: Explain that Orchard uses a custom virtual path provider to insert custom Assembly Src=xx and Assembly Name=xxx directive when reading .ascx and .aspx files)

(TODO:解释Orchard使用自定义虚拟路径提供程序在读取.ascx.aspx文件时插入自定义Assembly Src = xxAssembly Name = xxx指令)

Rendering Razor Views

渲染剃刀视图

(TODO: Explain that Orchard uses a Razor custom API to add Module dependencies to Views)

(TODO:解释Orchard使用Razor自定义API向视图添加模块依赖项)

The ~/App_Data/Dependencies/Dependencies.xml file

〜/ App_Data / Dependencies / Dependencies.xml文件

This file contains the list of modules, their loader and their resolved references of the "last known good" configuration of module, i.e. the last time Orchard successfully loaded all modules of the application. Examining the content of this file can be useful for debugging purposes, e.g. if the latest version of a module doesn't seem to be loaded.

该文件包含模块列表,它们的加载器以及它们对模块的“最后已知良好”配置的已解析引用,即Orchard上次成功加载应用程序的所有模块。检查该文件的内容对于调试目的是有用的,例如,如果似乎没有加载模块的最新版本。