AppEnclave 1.2.0

dotnet add package AppEnclave --version 1.2.0
                    
NuGet\Install-Package AppEnclave -Version 1.2.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="AppEnclave" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="AppEnclave" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="AppEnclave" />
                    
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 AppEnclave --version 1.2.0
                    
#r "nuget: AppEnclave, 1.2.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 AppEnclave@1.2.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=AppEnclave&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=AppEnclave&version=1.2.0
                    
Install as a Cake Tool

AppEnclave πŸ›‘οΈ

A High-Performance Multi-tenant Application Micro-kernel for ASP.NET Core.

AppEnclave allows you to host multiple, fully independent ASP.NET Core "Child Apps" within a single "Master App" process, sharing the same port. Each child app operates within its own Enclaveβ€”possessing its own private Dependency Injection container (IServiceProvider), Middleware pipeline, and Configuration.


πŸš€ Key Features

  • Multi-tenant Micro-kernel: Run multiple instances of the same app or different modules side-by-side.
  • Total DI Isolation: Each enclave has its own private IServiceProvider. No service registration leaks.
  • Environment Injection: Each tenant gets its own IWebHostEnvironment injected into its DI during the build process, allowing for isolated ContentRoot and EnvironmentName.
  • Zero-Latency Internal Routing: Requests are routed in-memory directly to the child's pipeline. No network overhead, no sockets, just raw performance.
  • Low Memory Footprint: Designed without Assembly Load Contexts (ALC) to maximize JIT sharing and minimize RAM usage.

πŸ—οΈ Architecture & Constraints

AppEnclave is built for efficiency. To achieve the lowest possible memory overhead, it uses a shared-binary approach:

Feature AppEnclave Approach Benefit
Process Single Process Extremely low overhead, easy monitoring.
Assembly Loading No ALC (Single Context) Low Memory: Shared JIT code and type metadata.
Dependencies Shared Versions All apps must use the same library versions.
Isolation Logical & DI Container Complete separation of app logic and middleware.
Performance In-Process Faster than YARP or Nginx reverse proxying.

Because it does not use ALCs, the Master App and all Child Apps must target the same versions of shared libraries (e.g., EntityFramework, Newtonsoft.Json).


πŸ’» Quick Start

1. Create an Enclave plugin in Child app

using Microsoft.Extensions.FileProviders;

namespace AppEnclave.Examples.ChildApp
{
    public class EnclavePlugin : ITenantPlugin
    {
        public Task ConfigureServicesAsync(IServiceCollection services, IWebHostEnvironment environment,
            IConfigurationManager configuration)
        {
            // Add services to the container.
            services.AddControllersWithViews();

            services.AddAuthentication();
            services.AddAuthorization();

            return Task.CompletedTask;
        }

        public Task ConfigureAsync(IApplicationBuilder app, IWebHostEnvironment environment)
        {
            // Configure the HTTP request pipeline.
            if (!environment.IsDevelopment())
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseStaticFiles();

            if (!Directory.Exists(Path.Combine(environment.ContentRootPath, @"wwwroot/.well-known")))
            {
                Directory.CreateDirectory(Path.Combine(environment.ContentRootPath, @"wwwroot/.well-known"));
            }

            app.UseStaticFiles(new StaticFileOptions()
            {
                FileProvider =
                    new PhysicalFileProvider(Path.Combine(environment.ContentRootPath, @"wwwroot/.well-known")),
                RequestPath = new PathString("/.well-known"),
                ServeUnknownFileTypes = true
            });

            app.UseEndpoints(endpoints =>
            {               
                endpoints.MapControllerRoute(
                        name: "default",
                        pattern: "{controller=Home}/{action=Index}/{id?}")
                    .WithStaticAssets();
            });

            return Task.CompletedTask;
        }
    }
}

You can even use that in Program.cs to keep the option to run the child app by itself

using AppEnclave.Examples.ChildApp;

var builder = WebApplication.CreateBuilder(args);

var plugin = new EnclavePlugin();

await plugin.ConfigureServicesAsync(builder.Services, builder.Environment, builder.Configuration);

var app = builder.Build();

await plugin.ConfigureAsync(app, builder.Environment);

app.Run();

2. Register an Enclave in Master app Program.cs

You can map an enclave to a specific path or entire hostname. AppEnclave handles the creation of the isolated container.

using System.Net;
using AppEnclave;

var builder = WebApplication.CreateBuilder(args);

// Master services (shared across all enclaves)

var httpContextAccessor = new HttpContextAccessor();
builder.Services.AddSingleton<IHttpContextAccessor>(httpContextAccessor);

builder.Services.AddHttpsRedirection(options =>
{
    options.HttpsPort = 443;
});

builder.Services.AddAuthentication();
builder.Services.AddAuthorization();

builder.Services.ConfigureHttpClientDefaults(b =>
    b.ConfigureHttpClient(client =>
    {
        client.DefaultRequestVersion = HttpVersion.Version20;
        client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrLower;
    }).ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler()));

builder.Services.AddHttpClient();

// Child app for entire host localhost yet allowing subapps on same host

await builder.Services.AddAppEnclaveAsync(options =>
{
    options.UseAuthentication = true;
    options.AllowSubAppsOnSameHost = true;
    options.Hosts = new[] { "localhost" };
    options.Plugin = new AppEnclave.Examples.ChildApp.EnclavePlugin();
    options.Name = "AppEnclave.Examples.ChildApp";
    options.EnvironmentName = "Host";
    options.ContentRoot = builder.Environment.ContentRootPath.Replace("AppEnclave.Examples.MasterApp", "AppEnclave.Examples.ChildApp");
    options.BinRoot = builder.Environment.ContentRootPath.Replace("AppEnclave.Examples.MasterApp", "AppEnclave.Examples.ChildApp");
});

// Child app for /subapp1 path

await builder.Services.AddAppEnclaveAsync(options =>
{
    options.UseAuthentication = true;
    options.Hosts = new[] { "/subapp1" };
    options.Plugin = new AppEnclave.Examples.ChildApp.EnclavePlugin();
    options.Name = "AppEnclave.Examples.ChildApp";
    options.EnvironmentName = "SubApp1";
    options.ContentRoot = builder.Environment.ContentRootPath.Replace("AppEnclave.Examples.MasterApp", "AppEnclave.Examples.ChildApp");
    options.BinRoot = builder.Environment.ContentRootPath.Replace("AppEnclave.Examples.MasterApp", "AppEnclave.Examples.ChildApp");
});

// Child app for /subapp2 path

await builder.Services.AddAppEnclaveAsync(options =>
{
    options.UseAuthentication = true;
    options.Hosts = new[] { "/subapp2" };
    options.Plugin = new AppEnclave.Examples.ChildApp.EnclavePlugin();
    options.Name = "AppEnclave.Examples.ChildApp";
    options.EnvironmentName = "SubApp2";
    options.ContentRoot = builder.Environment.ContentRootPath.Replace("AppEnclave.Examples.MasterApp", "AppEnclave.Examples.ChildApp");
    options.BinRoot = builder.Environment.ContentRootPath.Replace("AppEnclave.Examples.MasterApp", "AppEnclave.Examples.ChildApp");
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

// Turns on routing middleware to enable enclaves to work

app.UseAppEnclave();

app.Run();

πŸ“‚ Examples

πŸ›  Why use AppEnclave?

AppEnclave fills the gap between a messy monolithic pipeline and the heavy resource overhead of Microservices. It is the ideal choice for Modular Monoliths and SaaS Multi-tenant systems where performance and isolation are both critical.

Feature Standard app.Map() Containers / Sidecars AppEnclave
DI Container Isolation ❌ Shared (Leaky) βœ… Total βœ… Total (Private)
Memory Footprint 🟒 Lowest πŸ”΄ High (Multiple Runtimes) 🟒 Minimal (Shared JIT)
Configuration Isolation ❌ No βœ… Yes βœ… Yes (Per-Enclave)
Custom IWebHostEnv ❌ No (Global) βœ… Yes βœ… Yes (Isolated)
Port Sharing βœ… Yes ❌ No (Requires Proxy) βœ… Yes (Native)
Network Latency Zero πŸ”΄ High (TCP/Socket) 🟒 Zero (In-Process)
Dependency Versioning βœ… Forced Same βœ… Independent ⚠️ Forced Same (No ALC)

When to choose AppEnclave?

  • Modular Monoliths: You want to keep the code in one repo and process, but you hate when Service A accidentally resolves a dependency meant for Service B.
  • SaaS Multi-tenancy: You need to run hundreds of instances of the same app with different appsettings.json and different WebRootPath without paying for massive RAM usage.
  • Legacy Migrations: You are merging multiple separate ASP.NET Core apps into one unified host without rewriting their internal DI registrations.
Product Compatible and additional computed target framework versions.
.NET 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.
  • net10.0

    • No dependencies.

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.2.0 92 3/6/2026
1.1.0 84 3/2/2026
1.0.0 85 3/2/2026