ASP.NET Core integration for CShells. Provides middleware and extensions for shell/tenant resolution based on HTTP context, including host-based and route-based strategies for modular multi-tenant applications.
$ dotnet add package CShells.AspNetCoreASP.NET Core integration for CShells providing middleware and shell resolution based on HTTP context.
This package provides ASP.NET Core middleware, shell resolution strategies, and extensions for building multi-tenant web applications with CShells.
MapShells() extension - Automatically register endpoints from all shell featuresdotnet add package CShells
dotnet add package CShells.AspNetCore
using CShells.AspNetCore.Features;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
[ShellFeature("Weather", DisplayName = "Weather API")]
public class WeatherFeature : IWebShellFeature
{
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IWeatherService, WeatherService>();
}
public void MapEndpoints(IEndpointRouteBuilder endpoints, IHostEnvironment? environment)
{
endpoints.MapGet("weather", (IWeatherService weatherService) =>
weatherService.GetForecast());
}
}
{
"CShells": {
"Shells": [
{
"Name": "Default",
"Features": ["Weather"],
"Configuration": {
"WebRouting": {
"Path": ""
}
}
},
{
"Name": "Admin",
"Features": ["Admin"],
"Configuration": {
"WebRouting": {
"Path": "admin",
"RoutePrefix": "api/v1"
}
}
}
]
}
}
Simple setup:
var builder = WebApplication.CreateBuilder(args);
// Register CShells from configuration
builder.AddShells();
var app = builder.Build();
// Configure middleware and endpoints for all shells
app.MapShells();
app.Run();
Advanced setup with custom resolvers:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCShellsAspNetCore(cshells =>
{
cshells.WithConfigurationProvider(builder.Configuration);
cshells.WithWebRoutingResolver(options =>
{
options.ExcludePaths = new[] { "/api", "/health" };
options.HeaderName = "X-Tenant-Id";
});
});
var app = builder.Build();
app.MapShells();
app.Run();
Shells are resolved based on the URL path prefix:
{
"Configuration": {
"WebRouting": {
"Path": "admin"
}
}
}
Requests to /admin/* will be routed to this shell.
Configure shells to respond to specific hostnames:
{
"Configuration": {
"WebRouting": {
"Host": "admin.example.com"
}
}
}
Apply a route prefix to all endpoints in a shell:
{
"Configuration": {
"WebRouting": {
"Path": "tenant1",
"RoutePrefix": "api/v1"
}
}
}
With this configuration, an endpoint mapped at weather will be accessible at /tenant1/api/v1/weather.
Implement IShellResolver for custom resolution logic:
public class CustomShellResolver : IShellResolver
{
public Task<string?> ResolveShellIdAsync(HttpContext context)
{
// Custom logic to determine shell ID from HTTP context
var shellId = context.Request.Headers["X-Tenant-Id"].FirstOrDefault();
return Task.FromResult(shellId);
}
}
builder.Services.AddCShellsAspNetCore(cshells =>
{
cshells.WithResolver<CustomShellResolver>();
});
Configure routing behavior:
builder.Services.AddCShellsAspNetCore(cshells =>
{
cshells.WithWebRoutingResolver(options =>
{
// Exclude paths from shell resolution
options.ExcludePaths = new[] { "/api", "/health", "/swagger" };
// Use custom header for tenant ID
options.HeaderName = "X-Tenant-Id";
// Configure default shell
options.DefaultShell = "Default";
});
});