🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)
🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)

🔧 Programmierung 🕛 kürzlich 7 Min Lesezeit
0

.NET 9 Middleware Pipeline: Advanced Patterns and Performance 🚀

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht




.NET 9 Middleware Pipeline: Advanced Patterns and Performance 🚀




TL;DR — The ASP.NET Core middleware pipeline is where your app does its real work, but most developers only scratch the surface. In .NET 9, you've got new tools like MapStaticAssets, better exception handling, and the same old performance patterns still apply: short-circuit early, order cheap before expensive, and never sync-over-async. Let's look at the patterns actually worth knowing.










Pipeline Basics



Here's the mental model that actually helps: your middleware pipeline is a series of functions. Every incoming HTTP request flows through them in order. Each one can:




  • Do some work

  • Decide whether to pass the request downstream

  • Short-circuit and return immediately



You wire it up with three extension methods:





  • Use — does work, then calls next() to continue down the pipeline


  • Map — forks the pipeline based on a URL path


  • Run — terminal. No next(). The pipeline ends here.




CODE
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// 1. Use — passes through to next middleware
app.Use(async (context, next) =>
{
Console.WriteLine($"Before: {context.Request.Path}");
await next();
Console.WriteLine($"After: {context.Response.StatusCode}");
});

// 2. Map — forks on path, terminal
app.Map("/health", async ctx =>
{
await ctx.Response.WriteAsync("OK");
});

// 3. Run — terminal fallback
app.Run(async ctx =>
{
await ctx.Response.WriteAsync("Hello, World!");
});

app.Run();






Simple enough. The trap people fall into is treating the pipeline as a "it just works" abstraction. The order you register middleware is the only thing determining execution flow. Get the order wrong, and you're paying for work that never needed to happen.









UseWhen vs MapWhen: The Branching Difference



This is the single most confused topic in ASP.NET middleware. The names look similar. They work completely differently.



UseWhen creates a temporary branch. If the predicate is true, the branch executes and then rejoins the main pipeline.



MapWhen creates a permanent fork. If the predicate is true, the branch executes and never returns to the main pipeline.



Here's how that looks in practice:




CODE
// UseWhen: branch executes, then rejoins main pipeline
app.UseWhen(
context => context.Request.Path.StartsWithSegments("/api"),
branch =>
{
branch.Use(async (context, next) =>
{
Console.WriteLine("API branch entering");
await next();
Console.WriteLine("API branch exiting — pipeline continues");
});
}
);

// After UseWhen, all middleware below still runs
app.UseAuthentication();
app.UseAuthorization();

// ---

// MapWhen: permanent fork, main pipeline is abandoned
app.MapWhen(
context => context.Request.Host.Value?.Contains("admin") == true,
branch =>
{
branch.Use(async (context, next) =>
{
Console.WriteLine("Admin subdomain branch");
await next();
});

// This is the terminal endpoint for the fork
branch.Run(async ctx =>
{
await ctx.Response.WriteAsync("Admin panel");
});
}
);

// ❌ If MapWhen fires, nothing below here runs
app.UseAuthentication();






Real-world guidance: Use UseWhen when you want to layer conditional behavior (e.g., enable request logging only in development, then let the rest of the pipeline continue). Use MapWhen when you need a completely separate pipeline for a subset of traffic (e.g., a subdomain, a health check endpoint, a WebSocket handler).



Conditional activation based on environment is a common pattern ().



The fix is implementing IMiddleware, which activates the middleware per request through the DI container:




CODE
public class AuditMiddleware : IMiddleware
{
private readonly ILogger<AuditMiddleware> _logger;
private readonly IRepository _repository;

// Scoped services are safe here — fresh instance per request
public AuditMiddleware(ILogger<AuditMiddleware> logger, IRepository repository)
{
_logger = logger;
_repository = repository;
}

public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var sw = Stopwatch.StartNew();

await next();

sw.Stop();
_logger.LogInformation(
"{Method} {Path} completed in {ElapsedMs}ms",
context.Request.Method,
context.Request.Path,
sw.ElapsedMilliseconds);
}
}






Registration looks a little different — you register the middleware class as a service before adding it to the pipeline:




CODE
var builder = WebApplication.CreateBuilder(args);

// Register in DI
builder.Services.AddTransient<AuditMiddleware>();

var app = builder.Build();

// Activate via UseMiddleware
app.UseMiddleware<AuditMiddleware>();

app.Run();






The tradeoff? Factory activation creates a new middleware instance per request, so there's a small overhead. For high-throughput services, that matters. For most apps, the safety of correct DI lifetimes is worth it ().






Improved IExceptionHandler



Exception handlers got a StatusCodeSelector attribute, making it easier to route exceptions to specific handlers by HTTP status code:




CODE
builder.Services.AddExceptionHandler<AppExceptionHandler>();

// Inside the handler:
public class AppExceptionHandler : IExceptionHandler
{
public async ValueTask<bool> TryHandleAsync(
HttpContext httpContext, Exception exception,
CancellationToken cancellationToken)
{
httpContext.Response.StatusCode = exception switch
{
NotFoundException => StatusCodes.Status404NotFound,
ValidationException => StatusCodes.Status422UnprocessableEntity,
_ => StatusCodes.Status500InternalServerError
};

await httpContext.Response.WriteAsJsonAsync(
new { error = exception.Message }, cancellationToken);

return true; // handled
}
}









Route Group Improvements



Route groups now support ProducesProblem consistently, so your API's error shape stays uniform without repeating yourself at every endpoint.









Performance Tips That Actually Matter



The middleware pipeline is where performance lives or dies. Not your database query, not your serializer — the pipeline, because it runs on every single request. These patterns consistently show up in production diagnostics:






1. Short-circuit early



If you can return a response without calling next(), do it immediately. Every skipped middleware is CPU cycles not spent.




CODE
app.Use(async (context, next) =>
{
// Cheap check first — skip the entire pipeline for OPTIONS
if (context.Request.Method == HttpMethods.Options)
{
context.Response.StatusCode = StatusCodes.Status204NoContent;
return; // no next() — short-circuit
}

await next();
});









2. Order is everything



Put cheap, high-skip-rate middleware first. Authentication, CORS, routing — these should run before expensive operations like request body parsing or logging.




CODE
// ✅ Good order — cheapest first
app.UseExceptionHandler(); // only fires on errors
app.UseHttpsRedirection(); // cheap redirect
app.UseRouting(); // essential
app.UseAuthentication(); // may short-circuit unauthorized
app.UseAuthorization(); // same
app.UseCustomAudit(); // expensive — last









3. Never sync-over-async



This one is non-negotiable. Using .Result, .Wait(), or GetAwaiter().GetResult() inside middleware will deadlock your thread pool. Always await:




CODE
// ❌ BAD — blocks thread pool
app.Use(async (context, next) =>
{
var data = GetSomethingAsync().Result;
await next();
});

// ✅ GOOD — truly asynchronous
app.Use(async (context, next) =>
{
var data = await GetSomethingAsync();
await next();
});









4. Avoid buffering large request bodies



Middleware that reads context.Request.Body into memory forces the entire body to be buffered. For file uploads or large payloads, process the stream directly or set a reasonable body size limit (source).






5. Go end-to-end async



Every layer of your stack should be async — database calls, HTTP client requests, serialization. If one piece sync-blocks, it bottlenecks the whole pipeline.









Wrapping Up



The middleware pipeline isn't mysterious — it's just functions in order. But the small decisions compound: where you short-circuit, how you activate middleware, whether you're accidentally capturing scoped services. Get those right, and your app runs tighter.



.NET 9 made it easier with MapStaticAssets, cleaner exception handling, and better route group support. But the fundamentals — order, async discipline, short-circuiting — haven't changed since ASP.NET Core 1.0.



What's the middleware mistake you've seen (or made) in production? Drop it in the comments — no judgment, we've all captured a scoped dependency in a singleton at least once. 😅

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Hackers Just Poisoned the Rust Supply Chain | Threat Wire
1 Quelle
Hackers Found a Way Into Humanoid Robots | Threat Wire
1 Quelle
Bits und so #1021 (Passwort für Laufwerk)
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten .NET 9 Middleware Pipeline: Advanced Patterns and Performance 🚀

Thematisch verwandte Begriffe: Middleware, Pipeline, Advanced, Patterns · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...