For the complete documentation index, see llms.txt. This page is also available as Markdown.

Core Concepts and Collaboration

Distinguish between host, plugin, module, service, provider, builtin and four types of metadata files.

This page uses a forum module that exposes a thread-query API to explain several similar framework terms. Understanding these concepts before reading configuration and code makes it easier to locate the stage at which a problem occurs.

Host and Content Root

hostis the process entry for starting applications, such as terminals, background services and web applications.content root is the base directory for applications to find configurations, plugins, etc. Starting a DLL using an absolute path will not automatically switch the current working directory to the directory where the DLL is located.

Therefore, after deployment, you should enter the runtime directory and then start, or specify the content root through the host configuration. When plugins/ cannot be found, check the content root first and do not change the business assembly immediately.

Plugins and Assembly

Assemblies contain executable .NET types. A plugin is described by a .plugin manifest that declares dependencies, assemblies, and extension points. A plugin can include multiple assemblies or contribute composition configuration alone.

Project references let the compiler see types; plugin manifests let the runtime know what to load; and deployment files let the necessary files appear in the correct location. These three links are not substitutes for each other. For example, the Discussions.Web project can be compiled, but the Zongsoft.Discussions.Web.plugin is not deployed, and its controller is still not loaded according to the manifest during runtime.

Plugin Tree and Builtin

plugin tree is the path structure of the extension point at runtime. A plugin can append builtin to an existing path without modifying the path owner's source code. For example, Discussions adds the site validator to the data validator extension point, and the data driver adds the driver to /Workbench/Data/Drivers.

builtin is a buildable definition on the plugin tree. The builder determines how to create the object, and the resolver interprets expressions in properties. The following real-life listing creates the Discussions data validator and hooks it to the data extension point.

Source: src/Zongsoft.Discussions.plugin (excerpt; see source for context).

Zongsoft.Discussions.plugin
<extension path="/Workbench/Data/Validators">
	<object name="Discussions" type="Zongsoft.Discussions.Data.DataValidator, Zongsoft.Discussions" />
</extension>

Builtin names are tree node names and do not automatically become service aliases in DI. The file directory is not the plugin tree path either. See Builtins and Services for detailed syntax.

Modules, Services and Providers

module expresses the business boundaries in the application, such as Discussions. A module can be provided by several plugins; plugin loading does not automatically create business modules for each plugin. The application defines its modules explicitly. To include a module in the application module collection, it can mount the module object at /Workbench/Modules.

💡 Mounting a module at /Workbench/Modules is equivalent to adding it to the ApplicationContext.Current.Modules collection. Although this is optional, a shared module collection lets the system provide consistent capabilities across modules. For example, Zongsoft.Web.OpenApi uses the application module collection to group API documentation by module.

serviceis an object that provides certain operations through a contract.service container is responsible for parsing these objects by type, alias, or matching parameters. The module container first searches for module services, and then falls back to apply shared services; its lifecycle is not equal to the Web request lifecycle.

provider solves another type of problem: an implementation needs to provision multiple instances by name. For example, the Redis provider can return different caches by connection name. At this time, select provider first, and then get the named instance.

Name
Example
decide what

Plugin name

Zongsoft.Externals.Redis

Which plugin does the manifest dependency point to?

module name

Discussions

Module service resolution domain

provider name

Redis

Which implementation creates or finds instances

connection/instance name

Defined by actual environment options

Which set of connection parameters to use

builtin name

Discussions validator node

The location of the object in the plugin tree

Configuration, Mapping and Deployment

File
Answered questions
reader

.plugin

Which assemblies are loaded? Where to contribute objects?

plugin framework

.option

What connections, parameters and run options are used?

Configure provider

.mapping

How do business entities correspond to data sources?

data engine metadata loader

.deploy

Which files or packages are copied where?

Deployment tools

The list of Discussions plugins can be kept stable with different connection configurations used for test and production environments. The deployment plan determines whether Redis and MySQL are included, and the run configuration determines which deployed implementation and connection to use. Names in the configuration must form consistent relationships with registrations, connection items, and business calls.

.option will not be loaded if you put it into the directory arbitrarily. The plugin configuration is associated with the file name of the loaded manifest, see Option Configuration Files for details.

Workers, Initializers and Ordinary Services

Initializers are used for configuration or assembly in the initialization phase of an application; workers are used for tasks that need to be started, run continuously, and stopped when shut down; ordinary services are used to perform an operation on a call basis. Writing "subscribe to messages and keep listening" in the constructor will make object assembly, external connections and failure handling entangled, which should usually be managed by workers.

Common types registered through service attribute scanning default to singleton. The creation and release of shared instances is determined by registration and provider contracts. When you need to call independent state each time, you should clarify the scope or use a factory, and do not deduce "new each time" from "named" and "modular".

Applicable Boundaries of Plugin Architecture

Plugin architecture is suitable for splitting by business capabilities, combining infrastructure by environment, and allowing multiple hosts to reuse services. It also requires the team to maintain common contracts, manifests, configurations, and deployment compatibility; a very small standalone program may not necessarily need all the mechanisms.

Continue reading: Design Principles, Plugin Application Model, Glossary.

Last updated