PlugNBlaze.Hosting.Blazor
1.0.0
dotnet add package PlugNBlaze.Hosting.Blazor --version 1.0.0
NuGet\Install-Package PlugNBlaze.Hosting.Blazor -Version 1.0.0
<PackageReference Include="PlugNBlaze.Hosting.Blazor" Version="1.0.0" />
<PackageVersion Include="PlugNBlaze.Hosting.Blazor" Version="1.0.0" />
<PackageReference Include="PlugNBlaze.Hosting.Blazor" />
paket add PlugNBlaze.Hosting.Blazor --version 1.0.0
#r "nuget: PlugNBlaze.Hosting.Blazor, 1.0.0"
#:package PlugNBlaze.Hosting.Blazor@1.0.0
#addin nuget:?package=PlugNBlaze.Hosting.Blazor&version=1.0.0
#tool nuget:?package=PlugNBlaze.Hosting.Blazor&version=1.0.0
A plugin system for Blazor (.NET) applications. It discovers, loads, signs, and verifies plugins packaged as .pnbp archives, integrating them as dynamic Razor components inside a Blazor host (static SSR or Interactive Server), with permission control and hot-reload during development.
Features
- Plugin contracts: simple
IPlugininterface with a JSON manifest (PluginManifest). - Component slots: plugins ship Blazor components that render automatically in
<PluginSlotRenderer TZone="...">placeholders. - Packaging: plugins are distributed as signed
.pnbparchives. - Permission system: declarative permissions (
read,write,network:outbound,storage:*,unsafe) enforced at runtime. - Hot-reload: watch the plugin directory and reload changes during development (no restart needed).
- Static asset serving: plugins can include
wwwroot/assets served via middleware at/_plugins/<PluginName>/. - CLI tooling:
pnbhandles scaffolding, building, packing, signing, and verifying plugins. - Blazor-native: plugins render as regular Razor components via dynamic routing and slot rendering.
Project structure
| Project | Description |
|---|---|
PlugNBlaze.Core |
Base contracts: IPlugin, PluginManifest, IPluginComponent, permissions, and security context. |
PlugNBlaze.Abstractions |
Shared types (re-exports Core types via [TypeForwardedTo]). |
PlugNBlaze.Loader |
Plugin loading (PluginManager, PluginCatalog), sources (directory, URL), and signature validation. |
PlugNBlaze.Hosting.Blazor |
Blazor integration: DI extensions (AddPlugNBlaze), PluginSlotRenderer, component registry, hot-reload, and static asset middleware. |
PlugNBlaze.SDK |
SDK with pnb-plugin project template. |
PlugNBlaze.SDK.CLI (pnb) |
CLI to create, build, pack, sign, and verify plugins. |
NuGet packages
| Package | Version | Description |
|---|---|---|
PlugNBlaze.Core |
1.0.0 | Base interfaces and types for plugin development. |
PlugNBlaze.Abstractions |
1.0.0 | Shared types (convenience re-exports of Core). |
PlugNBlaze.Loader |
1.0.0 | Plugin discovery, loading, and signature validation. |
PlugNBlaze.Hosting.Blazor |
1.0.0 | Blazor host integration (DI, rendering, middleware). |
PlugNBlaze.SDK |
1.0.0 | Project template for scaffolding plugins. |
PlugNBlaze.SDK.CLI |
1.0.0 | pnb command-line tool (dotnet tool). |
Requirements
- .NET 9 SDK or later
Quick start (host app)
Install the hosting package:
dotnet add package PlugNBlaze.Hosting.Blazor
Then in Program.cs:
builder.Services.AddPlugNBlaze(options =>
{
options.PluginDirectory = Path.Combine(AppContext.BaseDirectory, "Plugins");
options.EnableHotReload = true; // development only
});
var app = builder.Build();
app.UsePlugNBlaze();
var pluginAssemblies = await app.InitializePlugNBlazeAsync(typeof(Program).Assembly);
app.MapRazorComponents<App>()
.AddAdditionalAssemblies(pluginAssemblies);
Place a slot renderer in any page:
@* Renders all plugin components implementing IDashboardWidget *@
<PluginSlotRenderer TZone="IDashboardWidget" />
Running the demo
The demo includes a Blazor dashboard host and a chart plugin:
cd demo/PlugNBlaze.Demo.Dashboard
dotnet run
Then open http://localhost:5000/dashboard. The dashboard loads the chart plugin (PlugNBlaze.Demo.ChartPlugin.pnbp) from demo/Plugins/ and renders a bar chart using Chart.js.
Demo structure
| Project | Role |
|---|---|
PlugNBlaze.Demo.Dashboard |
Blazor SSR host app with AddPlugNBlaze and <PluginSlotRenderer TZone="IDashboardWidget" />. |
PlugNBlaze.Demo.Shared |
Shared contracts (IDashboardWidget : IPluginComponent) referenced by both host and plugin. |
PlugNBlaze.Demo.ChartPlugin |
Plugin with a Blazor component (DashboardChart) that implements IDashboardWidget and includes wwwroot/chartPlugin.js for client-side Chart.js rendering. |
Creating a plugin
1. Define a zone interface (in a shared library)
public interface IDashboardWidget : IPluginComponent { }
2. Implement the plugin
public class Plugin : IPlugin
{
public PluginManifest Manifest { get; } = new()
{
Name = "MyPlugin",
Version = "1.0.0",
DisplayName = "My Plugin",
Entry = "MyPlugin.Plugin, MyPlugin",
Permissions = ["read"],
};
public Task StartAsync(IPluginContext context, CancellationToken ct = default)
{
context.Logger.LogInformation("MyPlugin started!");
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken ct = default) => Task.CompletedTask;
}
3. Create a Blazor component
@implements IDashboardWidget
<h3>Hello from MyPlugin</h3>
4. Build and pack
dotnet publish -c Release
pnb pack
This produces a .pnbp file in the output directory.
CLI (pnb)
Install as a global tool:
dotnet tool install --global PlugNBlaze.SDK.CLI
Or run locally:
cd PlugNBlaze.SDK.CLI
dotnet run -- help
Commands
| Command | Description |
|---|---|
new |
Scaffolds a new plugin project (interactive or via flags). |
build |
Builds the project in the current directory. |
pack |
Packages a published build into a .pnbp file. |
sign |
Signs a .pnbp with a key file. |
verify |
Verifies a .pnbp signature. |
info |
Displays the manifest of a .pnbp file. |
Examples
# Scaffold a new plugin
pnb new MyPlugin --author txrbo --description "My first plugin"
# Build and pack
cd MyPlugin
pnb build
pnb pack
# Sign with a key
pnb sign MyPlugin.pnbp --key mykey.pfx --password pass
# Verify
pnb verify MyPlugin.pnbp --key mykey.pfx
Component slot system
PlugNBlaze discovers Blazor components in plugin assemblies and renders them in slots defined by the host.
How it works
- Define a zone: create an empty marker interface inheriting from
IPluginComponent(e.g.,IDashboardWidget,ISidebarWidget). - Implement in a plugin: a Razor component implements the zone interface.
- Register:
PluginComponentRegistry.Register(assembly)scans each loaded plugin assembly for types that implement anyIPluginComponent-derived interface. - Render:
<PluginSlotRenderer TZone="IDashboardWidget" />queries the registry and renders each matching component via<DynamicComponent>.
Components can be ordered with [SlotOrder]:
[SlotOrder(Order = 10)]
public class MyWidget : IDashboardWidget { ... }
Permissions
Each plugin declares its required permissions in the manifest:
{
"name": "MyPlugin",
"permissions": ["read", "write", "network:outbound"]
}
Checked at runtime via PluginSecurityContext.Demand(...):
context.Security.Demand(PluginPermissions.StorageWrite);
Available permissions
| Permission | Description |
|---|---|
read |
Read files within the plugin sandbox. |
write |
Write files within the plugin sandbox. |
network:outbound |
Make outbound HTTP requests. |
storage:read |
Read from host-provided storage. |
storage:write |
Write to host-provided storage. |
unsafe |
Execute arbitrary code (full trust). |
.pnbp archive format
A .pnbp (PlugNBlaze Package) is a ZIP archive containing:
MyPlugin.pnbp
manifest.json # PluginManifest in JSON
MyPlugin.dll # Compiled plugin assembly
MyPlugin.pdb # Debug symbols (optional)
wwwroot/ # Static assets (optional)
chartPlugin.js
MyPlugin.deps.json # Dependencies manifest
MyPlugin.runtimeconfig.json # Runtime config (for .NET apps)
When the plugin is signed, the archive also contains a signature file.
Hot-reload
When EnableHotReload = true, the plugin directory is watched for changes. When a .pnbp file is added, removed, or modified:
PluginManagerdetects the change viaFileSystemWatcher.- The affected plugin is started or stopped as needed.
- The Blazor host re-renders with the updated components.
This is intended for development only.
Troubleshooting
Chart not appearing after navigation
If a plugin component uses JavaScript to render UI (e.g., Chart.js), the script runs on page load but not during Blazor enhanced navigation. Ensure your script handles the blazor:enhancedload event or uses a MutationObserver. See demo/PlugNBlaze.Demo.ChartPlugin/wwwroot/chartPlugin.js for a reference implementation.
Plugin not loaded
- Check that the
.pnbpfile is in the configuredPluginDirectory. - Check the application logs for plugin load errors.
- If signature validation is enabled, ensure the plugin is signed with a trusted key.
DynamicComponent errors with Interactive Server
System.Type is not JSON-serializable, so components using <DynamicComponent Type="..." /> (like PluginSlotRenderer) cannot be placed inside an @rendermode="InteractiveServer" boundary. Use static SSR for pages with plugin slots.
Status
Actively under development. The API may change between versions.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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 was computed. 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. |
-
net9.0
- Microsoft.Extensions.Http (>= 9.0.0)
- PlugNBlaze.Core (>= 1.0.0)
- PlugNBlaze.Loader (>= 1.0.0)
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 |
|---|---|---|
| 1.0.0 | 107 | 7/1/2026 |
