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
                    
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="PlugNBlaze.Hosting.Blazor" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PlugNBlaze.Hosting.Blazor" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="PlugNBlaze.Hosting.Blazor" />
                    
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 PlugNBlaze.Hosting.Blazor --version 1.0.0
                    
#r "nuget: PlugNBlaze.Hosting.Blazor, 1.0.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 PlugNBlaze.Hosting.Blazor@1.0.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=PlugNBlaze.Hosting.Blazor&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=PlugNBlaze.Hosting.Blazor&version=1.0.0
                    
Install as a Cake Tool

image

.NET Blazor NuGet License

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 IPlugin interface with a JSON manifest (PluginManifest).
  • Component slots: plugins ship Blazor components that render automatically in <PluginSlotRenderer TZone="..."> placeholders.
  • Packaging: plugins are distributed as signed .pnbp archives.
  • 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: pnb handles 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

  1. Define a zone: create an empty marker interface inheriting from IPluginComponent (e.g., IDashboardWidget, ISidebarWidget).
  2. Implement in a plugin: a Razor component implements the zone interface.
  3. Register: PluginComponentRegistry.Register(assembly) scans each loaded plugin assembly for types that implement any IPluginComponent-derived interface.
  4. 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:

  1. PluginManager detects the change via FileSystemWatcher.
  2. The affected plugin is started or stopped as needed.
  3. 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 .pnbp file is in the configured PluginDirectory.
  • 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 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. 
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
1.0.0 107 7/1/2026