SilverLABS.SilverSHELL.AMS 1.1.0
SilverLABS.SilverSHELL.AMS
App Module Service (AMS) - A powerful plugin system for building modular Blazor applications.
Features
- Dynamic Module Loading - Load and unload modules at runtime
- Navigation Endpoints - Modules can register navigation menu items
- Dashboard Widgets - Modules can provide dashboard widgets
- Search Providers - Integrated search across all modules
- Module Testing - Built-in test framework for module validation
- Dependency Management - Automatic dependency resolution
- Module Context - Shared context for cross-module communication
Installation
dotnet add package SilverLABS.SilverSHELL.AMS
Quick Start
1. Create a Module
using SilverSHELL.AMS.Interfaces;
using SilverSHELL.AMS.Models;
public class MyModule : IAppModule
{
public string Name { get; set; } = "My Module";
public bool Enabled { get; set; } = true;
public string Icon { get; set; } = "📦";
public Version Version => new Version(1, 0, 0);
public string Description { get; set; } = "My custom module";
public List<string> Dependencies { get; set; } = new();
public List<ModuleEndPoint> EndPoints { get; } = new()
{
new ModuleEndPoint
{
Name = "My Page",
Path = "/mypage",
Icon = "📄",
RequiredRoles = new[] { "User" }
}
};
public List<ModuleWidget> Widgets { get; } = new();
public IModuleSearchProvider? SearchProvider => null;
public IModuleTest? Tests => null;
public Task InitializeAsync(ModuleContext context)
{
// Initialize module
return Task.CompletedTask;
}
public Task DisposeAsync()
{
// Cleanup resources
return Task.CompletedTask;
}
}
2. Register Module Service
using SilverSHELL.AMS.Extensions;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
// Register AMS
builder.Services.AddSilverShellAMS(options =>
{
options.EnableAutoDiscovery = true;
options.ModulesPath = "/modules";
});
// Register your modules
builder.Services.AddModule<MyModule>();
await builder.Build().RunAsync();
3. Configure Router for Module Components
IMPORTANT: If your modules contain Razor components (pages with @page directive), you must register their assemblies with Blazor's Router.
In your App.razor:
@using SilverSHELL.AMS
@inject IServiceProvider ServiceProvider
<Router AppAssembly="@typeof(App).Assembly"
AdditionalAssemblies="AMSAssemblyReference.GetModuleAssemblies(ServiceProvider)">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
</Router>
Alternative: If you know your module types at compile time:
@using SilverSHELL.AMS
<Router AppAssembly="@typeof(App).Assembly"
AdditionalAssemblies="AMSAssemblyReference.GetModuleAssemblies(
typeof(MyModule),
typeof(AnotherModule)
)">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
</Router>
Note: This step is only required if your modules contain Razor components. If your modules only provide services or logic without UI components, you can skip this step.
4. Use Module Registry
@inject ModuleRegistry Registry
<h3>Loaded Modules</h3>
@foreach (var module in Registry.GetAllModules())
{
<div>
<h4>@module.Icon @module.Name</h4>
<p>@module.Description</p>
<p>Version: @module.Version</p>
</div>
}
Module Components
Navigation Endpoints
public List<ModuleEndPoint> EndPoints { get; } = new()
{
new ModuleEndPoint
{
Name = "Dashboard",
Path = "/dashboard",
Icon = "📊",
Order = 1,
RequiredRoles = new[] { "Admin" }
}
};
Dashboard Widgets
public List<ModuleWidget> Widgets { get; } = new()
{
new ModuleWidget
{
Title = "Stats Widget",
ComponentType = typeof(StatsWidget),
Width = 6,
Order = 1
}
};
Search Provider
public class MySearchProvider : IModuleSearchProvider
{
public async Task<IEnumerable<SearchResult>> SearchAsync(string query)
{
// Implement search logic
return results;
}
}
Module Tests
public class MyModuleTests : IModuleTest
{
public async Task<TestResult> RunTestsAsync()
{
// Run module tests
return new TestResult { Passed = true };
}
}
API Reference
IAppModule Interface
string Name- Module namebool Enabled- Enable/disable modulestring Icon- Module iconVersion Version- Module versionstring Description- Module descriptionList<string> Dependencies- Module dependenciesList<ModuleEndPoint> EndPoints- Navigation endpointsList<ModuleWidget> Widgets- Dashboard widgetsIModuleSearchProvider? SearchProvider- Search providerIModuleTest? Tests- Test suiteTask InitializeAsync(ModuleContext context)- Initialize moduleTask DisposeAsync()- Dispose module
ModuleRegistry Service
void RegisterModule(IAppModule module)- Register a modulevoid UnregisterModule(string moduleName)- Unregister a moduleIAppModule? GetModule(string name)- Get module by nameIEnumerable<IAppModule> GetAllModules()- Get all modulesIEnumerable<ModuleEndPoint> GetAllEndPoints()- Get all navigation endpointsIEnumerable<ModuleWidget> GetAllWidgets()- Get all widgets
AMSAssemblyReference
Assembly[] GetModuleAssemblies(IServiceProvider serviceProvider)- Get all registered module assemblies from DI containerAssembly[] GetModuleAssemblies(params Type[] moduleTypes)- Get assemblies from specific module types
Changelog
v1.1.0
- ✨ NEW:
AMSAssemblyReferencehelper for automatic Blazor Router assembly registration - 🔧 IMPROVED: Simplified setup for modules with Razor components
- 📚 DOCS: Added Router configuration guide for module component discovery
- 🎯 FEATURE: Two methods for assembly registration - runtime (via IServiceProvider) and compile-time (via Type[])
v1.0.0
- Initial release
Documentation
Support
- Issues: GitLab Issues
- Email: support@silverlabs.uk
License
This project is licensed under the MIT License.
Made with ❤️ by SilverLABS
No packages depend on SilverLABS.SilverSHELL.AMS.
v1.1.0: NEW - Added AMSAssemblyReference helper for automatic Blazor Router assembly registration of modules with Razor components. Simplifies module setup by automatically collecting module assemblies for component discovery.
.NET 9.0
| Version | Downloads | Last updated |
|---|---|---|
| 1.2.2-ci.1020 | 3 | 10/26/2025 |
| 1.2.1 | 27 | 10/26/2025 |
| 1.2.1-ci.1016 | 1 | 10/26/2025 |
| 1.2.1-ci.1012 | 1 | 10/26/2025 |
| 1.2.1-ci.985 | 1 | 10/25/2025 |
| 1.2.1-ci.977 | 1 | 10/25/2025 |
| 1.2.1-ci.935 | 2 | 10/24/2025 |
| 1.2.1-ci.934 | 6 | 10/24/2025 |
| 1.2.1-ci.932 | 3 | 10/24/2025 |
| 1.2.1-ci.931 | 2 | 10/24/2025 |
| 1.2.1-ci.929 | 1 | 10/24/2025 |
| 1.2.1-ci.928 | 2 | 10/24/2025 |
| 1.2.1-ci.927 | 1 | 10/24/2025 |
| 1.2.1-ci.926 | 1 | 10/24/2025 |
| 1.2.1-ci.924 | 1 | 10/24/2025 |
| 1.2.1-ci.922 | 1 | 10/24/2025 |
| 1.2.1-ci.921 | 1 | 10/24/2025 |
| 1.2.1-ci.920 | 1 | 10/24/2025 |
| 1.2.1-ci.916 | 1 | 10/24/2025 |
| 1.2.1-ci.915 | 1 | 10/24/2025 |
| 1.2.1-ci.914 | 1 | 10/24/2025 |
| 1.2.1-ci.912 | 1 | 10/24/2025 |
| 1.2.1-ci.909 | 1 | 10/24/2025 |
| 1.2.1-ci.907 | 1 | 10/24/2025 |
| 1.2.1-ci.901 | 2 | 10/24/2025 |
| 1.2.1-ci.900 | 2 | 10/24/2025 |
| 1.2.1-ci.896 | 1 | 10/24/2025 |
| 1.2.1-ci.895 | 1 | 10/24/2025 |
| 1.2.1-ci.891 | 1 | 10/24/2025 |
| 1.2.1-ci.889 | 2 | 10/24/2025 |
| 1.2.1-ci.887 | 1 | 10/24/2025 |
| 1.2.1-ci.884 | 2 | 10/24/2025 |
| 1.2.1-ci.881 | 1 | 10/24/2025 |
| 1.2.1-ci.880 | 2 | 10/24/2025 |
| 1.2.1-ci.878 | 2 | 10/24/2025 |
| 1.2.1-ci.849 | 215 | 10/22/2025 |
| 1.2.1-ci.662 | 2 | 10/20/2025 |
| 1.2.1-ci.661 | 1 | 10/20/2025 |
| 1.2.1-ci.658 | 2 | 10/20/2025 |
| 1.2.1-ci.657 | 3 | 10/20/2025 |
| 1.2.1-ci.656 | 3 | 10/20/2025 |
| 1.2.1-ci.655 | 1 | 10/20/2025 |
| 1.2.1-ci.654 | 2 | 10/20/2025 |
| 1.2.1-ci.653 | 3 | 10/20/2025 |
| 1.2.1-ci.652 | 3 | 10/20/2025 |
| 1.2.1-ci.651 | 3 | 10/20/2025 |
| 1.2.1-ci.650 | 3 | 10/20/2025 |
| 1.2.1-ci.649 | 3 | 10/20/2025 |
| 1.2.1-ci.648 | 2 | 10/20/2025 |
| 1.2.1-ci.647 | 2 | 10/20/2025 |
| 1.2.1-ci.646 | 3 | 10/20/2025 |
| 1.2.1-ci.645 | 2 | 10/20/2025 |
| 1.2.1-ci.644 | 2 | 10/20/2025 |
| 1.2.1-ci.643 | 2 | 10/20/2025 |
| 1.2.1-ci.641 | 2 | 10/20/2025 |
| 1.2.0 | 46 | 10/19/2025 |
| 1.1.0 | 8 | 10/06/2025 |
| 1.0.0 | 1,176 | 09/26/2025 |