Zongsoft.Plugins.Web 7.10.0

dotnet add package Zongsoft.Plugins.Web --version 7.10.0
                    
NuGet\Install-Package Zongsoft.Plugins.Web -Version 7.10.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Zongsoft.Plugins.Web" Version="7.10.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Zongsoft.Plugins.Web" Version="7.10.0" />
                    
Directory.Packages.props
<PackageReference Include="Zongsoft.Plugins.Web" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Zongsoft.Plugins.Web --version 7.10.0
                    
#r "nuget: Zongsoft.Plugins.Web, 7.10.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Zongsoft.Plugins.Web@7.10.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Zongsoft.Plugins.Web&version=7.10.0
                    
Install as a Cake Addin
#tool nuget:?package=Zongsoft.Plugins.Web&version=7.10.0
                    
Install as a Cake Tool

Zongsoft.Plugins.Web Web Plugin Library

License NuGet Version NuGet Downloads GitHub Stars

English | 简体中文


Overview

Zongsoft.Plugins.Web connects the Zongsoft plugin runtime to ASP.NET Core. It creates a web host, initializes the plugin tree, discovers controllers and SignalR hubs contributed by plugins, and establishes a request-aware application context.

Use this package when a web application is assembled from Zongsoft plugins. Use Zongsoft.Web directly when only its MVC, binding, formatting, authentication, or file-access helpers are required.

How the Host Is Composed

flowchart LR
	A[Application.WebAsync] --> B[WebApplicationBuilder]
	B --> C[Load host and plugin configuration]
	C --> D[Build the service provider]
	D --> E[Initialize WebApplicationContext]
	E --> F[Load plugin web parts]
	F --> G[Map controllers and SignalR hubs]

The package deliberately owns this ordering. Plugin components must be available before MVC endpoints are mapped, while request-bound values such as HttpContext, the principal, and the session are resolved only while a request is active.

Installation

dotnet add package Zongsoft.Plugins.Web

The package brings in Zongsoft.Core, Zongsoft.Plugins, and Zongsoft.Web. A deployable application normally also contains its plugin manifests and option files in the application directory.

Quick Start

using Zongsoft.Web;

var application = await Application.WebAsync(args, builder =>
{
	builder.Services.AddHttpContextAccessor();
});

await application.RunAsync();

Like daemon and terminal hosts, Application.WebAsync first loads the application-named .option, also loads the entry-assembly-named .option when the names differ, and finally loads web.option. Missing files are optional; later configuration overrides earlier keys. It then builds the plugin-aware service provider, initializes WebApplicationContext, installs the framework middleware pipeline, maps controllers, and maps discovered SignalR hubs. The named overload sets the application name without excluding the entry assembly configuration.

💡 Keep application-specific service registration in the builder callback. Put reusable components and their relationships in plugin manifests so other hosts can compose them in the same way.

Controller and Hub Discovery

The ApplicationConvention integrates plugin components with MVC application models. Controllers contributed by loaded plugin assemblies are activated through the framework service container. SignalR hub types are collected as application features and mapped during host startup.

The built-in PluginController exposes plugin information for framework tooling. Treat that endpoint as operational metadata and protect it according to the deployment's authorization policy.

Real Use Case: The Discussions Web Plugin

1. Understand the Existing Controller's Consumption Boundary

ForumController belongs to the real Web class library and inherits the framework's service controller. This excerpt preserves one actual action and omits the others:

[ControllerName("Forums")]
public class ForumController : ServiceController<Forum, ForumService>
{
	[ActionName("Moderators")]
	[HttpGet("{id}/[action]")]
	public IEnumerable<UserProfile> GetModerators(ushort id)
	{
		return this.DataService.GetModerators(id, this.Request.Headers.GetDataSchema());
	}
}

Forum, UserProfile and ForumService come from Discussions rather than types invented for this guide. The controller consumes its domain service through the base DataService property and passes the request schema. It constructs no data engine, database driver or cache implementation. See ForumService.cs.

2. Use Real Manifests and Deployment Artifacts

The manifest excerpt from Zongsoft.Discussions.Web.plugin:

<manifest>
	<dependencies>
		<dependency name="Zongsoft.Discussions" />
	</dependencies>
	<assemblies>
		<assembly name="Zongsoft.Discussions.Web" />
	</assemblies>
</manifest>

Use the domain deployment manifest and Web deployment manifest, preserving business options, mappings, identity extensions and templates. This package-composition fragment still requires the host, Data, Security, a database driver and file storage from the complete deployment plan:

[plugins zongsoft discussions]
nuget:Zongsoft.Discussions

[plugins zongsoft discussions web]
nuget:Zongsoft.Discussions.Web

The Web manifest depends on the domain plugin, whose project targets its public dependencies. Configuration and plugins locate data providers. See the plugin guide for module composition.

3. Check Actual Requests and Prerequisites

forum.http contains maintained forum request templates, including the list route /Discussions/Forums. The moderator action appends {id}/Moderators to the base route; confirm the complete route through host controller descriptors.

Prepare a compatible host, dedicated initialized database, Discussions connection, test site, appropriate identity and required storage. Use forum identifiers from your test data rather than assuming a fixed ID exists. This is a source-backed use case, not a database-free probe or a promise of success in an uninitialized environment.

🚨 Do not remove identity transformation, data validators or business permissions to make an example succeed. Even read requests may expose forum data. Use an isolated identity/site and never copy repository addresses or credentials into real requests.

Common Pitfalls

  • DLL copied but controller absent: check manifest assembly entries, dependencies and the Web library's actual ASP.NET Core references.
  • Controller discovered but HTTP 404: check ControllerName, module ownership, base routes and action templates; class names alone do not determine URLs.
  • Service or data unavailable on first call: inspect service scanning, modules, connections, mappings and the database rather than hard-coding implementations into host startup.
  • Subscription, worker and data-resource shutdown follow host lifecycle; stop the test host before cleaning only its test resources.

Request Context

WebApplicationContext extends PluginApplicationContext with web-specific state:

  • the current HttpContext and authenticated principal;
  • the framework session abstraction;
  • configured web sites and host mappings;
  • initialization of web parts contributed by loaded plugins.

🚨 Do not retain request-scoped objects in singleton plugin components. HttpContext, principals, sessions, and scoped services are only valid for the active request and may be accessed concurrently by different requests.

Listener Configuration and Request Ranges

WebApplicationBuilder.BuildAsync() loads plugin configuration, registers services and builds the host. Application.WebAsync() loads the named host configuration followed by web.option before building, then composes the application pipeline. During the existing service scan, Plugins.Web's private WebEndpointExtension.Registration automatically enables endpoint conversion, request scopes and change monitoring when a Web host has entries under Kestrel:Endpoints. No change to the hosting program is required:

var app = await Zongsoft.Web.Application.WebAsync(args);
await app.RunAsync();

The registrar uses the existing IServiceRegistration contract. It does not run for non-Web hosts, and skips hosts without endpoint entries or with an already registered WebEndpointCollection. Without declarations, native urls/http_ports/https_ports, app.Urls and code Listen(...) retain ASP.NET Core behavior. Detection uses the configuration available during service scanning; endpoint declarations added after startup require a restart. The zongsoft.tools.binding processing instruction declares exposure to deployment tools; runtime registration consumes endpoint configuration.

Automatic registration calls AddWebEndpoints(configuration).AddWebEndpointMonitoring(). These methods register factories and callbacks without creating a temporary provider or capturing a snapshot. The final provider creates the snapshot on first consumption, including protocol policies registered later in the service scan. Invalid declarations or plugin conflicts fail when resolving endpoint/server options or starting the host; do not rely on BuildAsync() throwing immediately.


<options>
	<option path="Kestrel">
		<endpoints>
			<endpoint endpoint.name="api" url="http://127.0.0.1:8069/api" protocols="http1" />
		</endpoints>
	</option>
</options>

The extension calls the independent KestrelUtility.Convert to produce logical endpoints and separate configuration from the same input. Source URLs retain /api, physical URLs omit it, and logical scope remains /api. Certificates, SNI and other server options follow the Web endpoint contract. Both configuration and request scopes are startup snapshots; DI owns the projected configuration.

Different values for the same server key across plugins fail with the key and two entry paths, without values. Entry paths do not identify individual import fragments. Explicit imports within one plugin may override values; equal cross-plugin values are allowed. These checks belong to the endpoint extension, whether registered automatically or explicitly, and do not change generic plugin configuration rules.

Projection uses PostConfigure with reload disabled. Do not manually Load() the original path-bearing configuration beforehand. ConfigureKestrel callbacks run before post-configuration. Other PostConfigure<KestrelServerOptions> callbacks retain normal registration order: register them before this extension to avoid replacing its projection afterwards. The extension neither wraps listener factories nor prohibits native address sources. Kestrel controls additional listeners and duplicate binds; scope enforcement rejects requests that match no declaration. Empty collections are valid and reject all requests when enforcement is enabled. Actual HTTP/3 startup remains subject to platform and TLS requirements.

The extension calls AddWebEndpointPipeline() to register a private IStartupFilter, placing scope checks before application initializer middleware, automatic routing and static files. Do not call UseWebEndpoints() again. Custom startup-filter ordering remains the host's responsibility. Authentication and authorization retain their roles; controller and Hub routes do not gain prefixes automatically. Use KestrelUtility directly for conversion only. Non-plugin hosts can independently use Web endpoint registration and its startup-filter extension.

AddWebEndpointMonitoring() is included in automatic registration. For explicit registration it remains optional and must follow endpoint registration; repeated calls are harmless. It subscribes at host startup and unsubscribes on stop or disposal. Network changes or new plugin conflicts produce one WebEndpointsChanged warning without refreshing listeners or routes; business changes stay quiet. Without monitoring, snapshots still remain fixed but no restart warning is emitted. Initialization failure disposes the constructed host.

Explicit registration is available for a custom configuration section or for independent control of monitoring. Register it in the builder callback before service scanning. Automatic registration then preserves this choice, without adding another snapshot or monitor. The default section is Kestrel:

using Zongsoft.Web.Hosting;

var app = await Zongsoft.Web.Application.WebAsync(args, builder =>
{
	builder.Services.AddWebEndpoints(builder.Configuration, "Server");
	// Optional for explicit registration.
	builder.Services.AddWebEndpointMonitoring();
});

Startup and Extension Points

The generated pipeline enables CORS, localization, method override, routing, authentication, authorization, response compression, static files, controllers, and SignalR. IApplicationInitializer<IApplicationBuilder> implementations run before the standard middleware is added and are the supported hook for reusable startup behavior.

If middleware order is security-sensitive, inspect Application.cs before adding an initializer: authentication and authorization depend on routing, and endpoint mapping occurs after the standard middleware chain.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
7.10.0 138 10/22/2026
7.9.0 92 10/20/2026
7.8.0 124 10/16/2026
7.7.0 250 5/5/2026
7.6.0 147 4/29/2026
7.5.0 185 2/26/2026
7.4.0 442 8/28/2025
7.3.0 320 8/4/2025
7.2.0 701 7/22/2025
7.1.0 737 3/26/2025
7.0.0 337 2/24/2025
Loading failed