DEV Community

Welcome Bonginhlahla Sithole
Welcome Bonginhlahla Sithole

Posted on • Edited on

Meet AppPipe: The Lightweight, On-Premises Alternative to .NET Aspire

Modern cloud-native developer environments are fantastic. Frameworks like .NET Aspire have revolutionized local development by providing a unified developer dashboard, automatic service discovery, and OTLP telemetry collection.

But what happens when it's time to deploy your microservice topology on-premises?

If your target is IIS on Windows Server, shared IIS hosting environments, or a systemd service on Linux, you've likely realized that deploying the standard .NET Aspire stack on-prem is a complex puzzle. There is no native hosting model for IIS, gRPC telemetry port mapping is fragile, and the dashboard's constant WebSocket connections can consume excessive resources on on-premises virtual machines.

Enter AppPipe.Hosting—a lightweight, developer-friendly NuGet package designed specifically to bring the best features of .NET Aspire to your on-premises environments.


The Problem: On-Premises Microservice Orchestration is Hard

While cloud platforms have native orchestration (like Kubernetes or ECS), traditional Windows and Linux environments still host a massive volume of enterprise applications. When running microservices on IIS or Linux servers, developers face three major friction points:

  1. Port Conflicts & Service Discovery: Dynamically assigning ports to multiple microservices in IIS or systemd and injecting them into dependent services is tedious.
  2. Telemetry Aggregation: Running an OpenTelemetry Collector just to aggregate traces, logs, and metrics for a small on-prem cluster is heavy and complex to configure.
  3. Resource Exhaustion: Standard Blazor Interactive Server dashboards maintain constant WebSockets and high memory usage, which quickly drains hosting environments.

The Solution: AppPipe

AppPipe is a lightweight alternative that integrates a routing gateway, a persistent telemetry database store, and a visual dashboard directly into a single library.

Key Capabilities:

  • ⚡ Service Discovery & Routing via YARP: Under the hood, AppPipe uses Microsoft's YARP (Yet Another Reverse Proxy). It serves as a single entry point for your client, proxying traffic to backend microservices automatically using clean, virtual paths.
  • 📊 OTLP Telemetry Collection: AppPipe exposes a dedicated HTTP/2 Kestrel endpoint that acts as a local OTLP collector. Your microservices export standard traces, logs, and metrics directly to the AppPipe Gateway, which parses and displays them in the dashboard.
  • 🖥️ Gorgeous Blazor Dashboard: View traces as waterfall flamegraphs, inspect console logs, and monitor metrics over time in a responsive Light/Dark theme dashboard.
  • 💾 Persistent Telemetry & Diagnostics: Telemetry logs, traces, and metrics are persistent by default using an integrated local SQLite database, surviving gateway restarts and IIS application pool recycles.
  • 🔒 Dashboard Security: Opt-in basic authentication protection to secure your logs and trace panels in intranet environments.
  • 📈 Ingestion & Diagnostics Panel: A dedicated diagnostics page showing real-time telemetry ingestion rates, active connections, database sizes, and host system information.
  • ⚡ Dual Render Modes: Run the dashboard in full WebSocket InteractiveServer mode for real-time updates during development, or swap to Server-Side Rendering (SSR) mode in production to drastically reduce CPU and memory consumption.
  • 🚀 Built-in On-Prem Deployment Pipeline: Using ModularPipelines, AppPipe provides automatic scripts to publish your services, spin up dedicated IIS Application Pools, configure Windows sub-applications, and inject service endpoints and telemetry tokens safely.

🚀 Scaffold Your Solution with .NET Templates

To make starting a brand-new project simple, AppPipe includes an installable .NET template package (AppPipe.Hosting.Templates). It scaffolds a complete solution with a pre-configured AppHost orchestrator, an ApiService backend, and a Web frontend:

1. Install the Template Pack

dotnet new install AppPipe.Hosting.Templates
Enter fullscreen mode Exit fullscreen mode

2. Scaffold Your Solution

dotnet new apppipe-system -n MySystem
Enter fullscreen mode Exit fullscreen mode

This generates a fully functional solution (MySystem.sln) with the three pre-integrated projects. You can open and build it instantly, and it is ready to run locally or deploy to IIS.


How Easy Is It to Use?

Setting up AppPipe in your orchestration host project takes just a few lines of C#:

using AppPipe.Hosting;

var builder = AppPipeHostingApp.CreateBuilder(args);

// Configure the Gateway Dashboard Host Project
builder.HostProject = new AppPipeHostingProjectResource(AppPipeProjects.HostProject)
    .WithEndpoint(7001)
    .WithIISSite("Default Web Site")
    .WithAppPath("/")
    .WithAppPool("AppPipeDashboardPool");

// Define a backend worker microservice using compile-safe generated constant
var backend = builder.AddProject(AppPipeProjects.BackendWorker);

// Define a frontend API and declare its reference to BackendWorker
var frontend = builder.AddProject(AppPipeProjects.FrontendApi)
                      .WithReference(backend); // Injects service discovery variables automatically

var app = builder.Build();

// Run the host using AppPipeDevHostRunner
var runner = new AppPipeDevHostRunner(app);
await runner.RunAsync();
Enter fullscreen mode Exit fullscreen mode

[!WARNING]
Host Project SDK Requirement: The host project (e.g. MySystem.AppHost.csproj) must use the <Project Sdk="Microsoft.NET.Sdk.Web"> SDK. If it is configured as a standard console app SDK (Microsoft.NET.Sdk), Razor compilation and Blazor routes will fail, leading to 404 Not Found errors when attempting to access the dashboard.

Inside your microservices, register the standard OpenTelemetry exporter:

builder.Services.AddOpenTelemetry()
    .WithTracing(tracing => tracing
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation()
        .AddOtlpExporter()) // Automatically routes to AppPipe telemetry port
    .WithMetrics(metrics => metrics
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation()
        .AddOtlpExporter());
Enter fullscreen mode Exit fullscreen mode

💾 Telemetry Database Persistence & Custom Stores

By default, AppPipe persists all logs, traces, and metrics in a local SQLite database (SqliteTelemetryStore), which is automatically created and hydrated on startup.

If you are running in production and want to disable database persistence or plug in another database (such as PostgreSQL, SQL Server, or ClickHouse), you can implement the ITelemetryStore interface and register it:

namespace AppPipe.Gateway.Services;

public interface ITelemetryStore
{
    ConcurrentDictionary<string, ParsedTrace> Traces { get; }
    ConcurrentQueue<ParsedLog> Logs { get; }
    ConcurrentQueue<ExportMetricsServiceRequest> Metrics { get; }

    void AddTrace(ExportTraceServiceRequest request);
    void AddLog(ExportLogsServiceRequest request);
    void AddMetric(ExportMetricsServiceRequest metric);

    event Action? OnTelemetryReceived;
}
Enter fullscreen mode Exit fullscreen mode

Implementing and Configuring a Custom Database

  1. Write Your Implementation: Create a class implementing ITelemetryStore that persists traces, logs, and metrics to your chosen database (e.g. PostgreSQL, SQLite, or ClickHouse):
public class SqliteTelemetryStore : ITelemetryStore
{
    // Implement parsing, writing, and querying logic here...
    public void AddTrace(ExportTraceServiceRequest request)
    {
        // Save to SQLite DB
        OnTelemetryReceived?.Invoke();
    }
    // ...
}
Enter fullscreen mode Exit fullscreen mode
  1. Register It in the DI Container: Register your custom telemetry store with the gateway builder during startup:
var builder = AppPipeHostingApp.CreateBuilder(args);

// Configure the Gateway Dashboard Host Project
builder.HostProject = new AppPipeHostingProjectResource(AppPipeProjects.HostProject)
    .WithEndpoint(7001)
    .WithAppPath("/AppHost");

// Register custom Telemetry Store on the Gateway's DI container:
builder.ConfigureGateway(gatewayBuilder =>
{
    gatewayBuilder.Services.AddSingleton<ITelemetryStore, SqliteTelemetryStore>();
});

var app = builder.Build();

// Run the host using AppPipeDevHostRunner
var runner = new AppPipeDevHostRunner(app);
await runner.RunAsync();
Enter fullscreen mode Exit fullscreen mode

Built for the Realities of On-Prem Hosting

When deploying to production IIS environments, AppPipe features specific optimizations to ensure maximum reliability and low overhead:

1. IIS Token Overwrite Filter

IIS integration validates incoming requests using an MS-ASPNETCORE-TOKEN pairing token. Since outgoing HTTP calls from your microservices carry mismatched pairing tokens from different AppPools, IIS natively rejects telemetry exports. AppPipe implements a custom startup filter at index 0 that overrides these headers for loopback connections on the telemetry port, allowing OTLP traffic to flow without compromising security.

2. High-Performance SSR Mode

To prevent Blazor Interactive Server from spawning idle WebSockets and consuming RAM on your servers, setting Dashboard:UseWebSockets to false configures the dashboard in pure SSR mode. All refreshes, trace waterfalls, and searches are handled cleanly with base-relative URLs that work perfectly under IIS sub-applications (e.g. /your-sub-app/).

3. Persistence Retention Pruning

AppPipe prunes database entries to the last 2,000 logs, metrics, and trace IDs to prevent database size from expanding indefinitely.

4. Shared IIS Hosting Support (iis-shared)

For shared hosting setups (such as cPanel, Plesk, or Azure App Service) where background processes and command execution are restricted, AppPipe compiles all microservice binaries into subdirectories of the Gateway.

  • Auto-Generated web.config: Generates isolated web.config configurations inside each subdirectory, enabling developers to run microservices in-process.
  • Remote Backup & Rollback: Optionally syncs build directories to the server over FTP/FTPS. If configured, AppPipe takes a remote backup before deploying and executes an automatic rollback (restoring original files using Mirror mode) if the deployment encounters an error.

5. Universal Selective Project Deployment

Deployments support filtering at runtime to compile, start, and restart only specified services, drastically speeding up pipelines when only single microservices change:

dotnet run --project AppHost.csproj -- --deploy iis --AppPipe:Deployment:FilterProjects "BackendWorker"
Enter fullscreen mode Exit fullscreen mode

🚀 Integrating AppPipe into DevOps Pipelines

In professional staging and production environments, you build your code once (generating DLLs) and deploy those pre-compiled artifacts across multiple environments. The target servers do not contain the source code or the .NET SDK.

AppPipe is built to accommodate this separation of concerns:

1. Build Once (CI)

On your build server, compile and publish your orchestrator and microservice projects:

dotnet publish samples/AppPipe.DevHost/AppPipe.DevHost.csproj -c Release -o ./publish/AppPipe.DevHost
dotnet publish samples/BackendWorker/BackendWorker.csproj -c Release -o ./publish/BackendWorker
dotnet publish samples/FrontendApi/FrontendApi.csproj -c Release -o ./publish/FrontendApi
Enter fullscreen mode Exit fullscreen mode

Package and upload the ./publish directory as a build artifact.

2. Deploy Anywhere (CD)

On the target machine, download your pre-compiled files and invoke the orchestrator with the --prepublished-dir option:

dotnet C:\inetpub\apps\AppPipe\AppPipe.DevHost.dll --deploy iis --prepublished-dir C:\inetpub\apps\AppPipe
Enter fullscreen mode Exit fullscreen mode

This flag tells the orchestrator to bypass .csproj checks and local compilation steps entirely, deploying direct to IIS or SCM from your pre-compiled DLLs.

3. Injecting Environment Configs & Secrets

To configure environment-specific settings (like AppPool names or site directories) and environment secrets (like service passwords), bind the topology definition to standard .NET Configuration:

var config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json", optional: true)
    .AddEnvironmentVariables(prefix: "APH__")
    .AddCommandLine(args)
    .Build();

// Configure the Gateway Dashboard Host Project
builder.HostProject = new AppPipeHostingProjectResource(AppPipeProjects.HostProject)
    .WithEndpoint(7001)
    .WithIISSite("Default Web Site")
    .WithAppPath("/")
    .WithAppPool("AppPipeDashboardPool");

var appPool = config["BackendWorker:AppPoolName"] ?? "ProdPool";
var password = config["BackendWorker:ServicePassword"];

builder.AddProject(AppPipeProjects.BackendWorker)
       .WithAppPool(appPool)
       .WithServiceAccount(@"DOMAIN\ServiceAccount")
       .WithServicePassword(password);
Enter fullscreen mode Exit fullscreen mode

During your CD release stage, you can inject these settings dynamically:

  • Environment Variables: Map DevOps secrets/variables as environment variables (e.g., APH__BackendWorker__ServicePassword $\rightarrow$ $(SecretPassword)).
  • Command Line Params: Pass them directly to the orchestrator:
  dotnet AppPipe.DevHost.dll --deploy iis --prepublished-dir C:\inetpub\apps\AppPipe --BackendWorker:AppPoolName "ProdPool" --BackendWorker:ServicePassword "$(SecretPassword)"
Enter fullscreen mode Exit fullscreen mode

Get Started Today

AppPipe is open-source and ready to streamline your on-premises microservices.

Top comments (0)