Webframeworkk/ASP.NET Core/Middleware: Unterschied zwischen den Versionen

Aus Dokument
Zur Navigation springen Zur Suche springen
Die Seite wurde neu angelegt: „Dieses Tutorial erklärt das Konzept der Middleware in ASP.NET Core, wie sie funktioniert, wie man sie konfiguriert und wie man eigene Middleware-Komponenten erstellt. Es basiert auf den bereitgestellten Notizen und ergänzendem Expertenwissen. == Was ist Middleware? == Middleware in ASP.NET Core ist eine Software-Pipeline, durch die jede HTTP-Anfrage (Request) und jede Antwort (Response) fließt. Man kann sich diese Pipeline wie eine Reihe von hinterei…“
 
imported>Import
Version 181
Zeile 9: Zeile 9:


Jede Middleware-Komponente hat drei Hauptaufgaben:
Jede Middleware-Komponente hat drei Hauptaufgaben:
# '''Untersuchen''' der eingehenden Anfrage.
# '''Untersuchen''' der eingehenden Anfrage.
# '''Bearbeiten''' der Anfrage oder der Antwort.
# '''Bearbeiten''' der Anfrage oder der Antwort.
Zeile 15: Zeile 16:
Dies ermöglicht eine saubere Modularisierung von Funktionen wie Authentifizierung, Logging, Fehlerbehandlung und Routing.
Dies ermöglicht eine saubere Modularisierung von Funktionen wie Authentifizierung, Logging, Fehlerbehandlung und Routing.


----


== Grundlagen: app.Use vs. app.Run ==
-----
 
== Grundlagen: app.Use vs. app.Run ==


Es gibt zwei grundlegende Methoden, um Middleware zur Pipeline hinzuzufügen:
Es gibt zwei grundlegende Methoden, um Middleware zur Pipeline hinzuzufügen:


=== 1. <code>app.Run</code> (Terminale Middleware) ===
=== 1. <code>app.Run</code> (Terminale Middleware) ===
Diese Methode fügt eine '''terminale''' Middleware hinzu. Das bedeutet, sie beendet die Pipeline. Es wird kein <code>next</code>-Delegat aufgerufen, und nachfolgende Middleware-Komponenten werden nicht ausgeführt.
Diese Methode fügt eine '''terminale''' Middleware hinzu. Das bedeutet, sie beendet die Pipeline. Es wird kein <code>next</code>-Delegat aufgerufen, und nachfolgende Middleware-Komponenten werden nicht ausgeführt.


'''Beispiel:'''
'''Beispiel:'''
<syntaxhighlight lang="csharp">
 
app.Run(async (context) => {
<syntaxhighlight lang="csharp">app.Run(async (context) => {
     await context.Response.WriteAsync("Ende der Pipeline");
     await context.Response.WriteAsync("Ende der Pipeline");
});
});</syntaxhighlight>
</syntaxhighlight>
 
Warnung: Wenn Sie zwei <code>app.Run</code>-Aufrufe hintereinander haben, wird nur der erste ausgeführt!
Warnung: Wenn Sie zwei <code>app.Run</code>-Aufrufe hintereinander haben, wird nur der erste ausgeführt!


=== 2. <code>app.Use</code> (Verkettbare Middleware) ===
=== 2. <code>app.Use</code> (Verkettbare Middleware) ===
Diese Methode dient dazu, Aufgaben zu erledigen und dann (meistens) die nächste Komponente in der Kette aufzurufen.
Diese Methode dient dazu, Aufgaben zu erledigen und dann (meistens) die nächste Komponente in der Kette aufzurufen.


'''Beispiel:'''
'''Beispiel:'''
<syntaxhighlight lang="csharp">
 
app.Use(async (context, next) => {
<syntaxhighlight lang="csharp">app.Use(async (context, next) => {
     // Logik VOR dem nächsten Middleware-Aufruf (Request)
     // Logik VOR dem nächsten Middleware-Aufruf (Request)
     await context.Response.WriteAsync("Hallo ");
     await context.Response.WriteAsync("Hallo ");
Zeile 47: Zeile 49:
     // Logik NACH dem nächsten Middleware-Aufruf (Response)
     // Logik NACH dem nächsten Middleware-Aufruf (Response)
     // Hier können wir die Antwort noch bearbeiten, nachdem der Rest der Pipeline fertig ist.
     // Hier können wir die Antwort noch bearbeiten, nachdem der Rest der Pipeline fertig ist.
});
});</syntaxhighlight>
</syntaxhighlight>


----
-----


== Die Reihenfolge der Middleware (The Middleware Order) ==
== Die Reihenfolge der Middleware (The Middleware Order) ==
Zeile 59: Zeile 60:


# '''Exception Handler''' (<code>UseDeveloperExceptionPage</code>, <code>UseExceptionHandler</code>): Sollte ganz oben stehen, um Fehler aus jedem Teil der Pipeline abzufangen.
# '''Exception Handler''' (<code>UseDeveloperExceptionPage</code>, <code>UseExceptionHandler</code>): Sollte ganz oben stehen, um Fehler aus jedem Teil der Pipeline abzufangen.
# '''HSTS & HTTPS Redirection''' (<code>UseHsts</code>, <code>UseHttpsRedirection</code>): Sicherheit geht vor.
# '''HSTS &amp; HTTPS Redirection''' (<code>UseHsts</code>, <code>UseHttpsRedirection</code>): Sicherheit geht vor.
# '''Static Files''' (<code>UseStaticFiles</code>): Statische Dateien sollten schnell ausgeliefert werden, ohne unnötige Verarbeitung durch spätere Logik.
# '''Static Files''' (<code>UseStaticFiles</code>): Statische Dateien sollten schnell ausgeliefert werden, ohne unnötige Verarbeitung durch spätere Logik.
# '''Routing''' (<code>UseRouting</code>): Ermittelt, welcher Endpunkt passt.
# '''Routing''' (<code>UseRouting</code>): Ermittelt, welcher Endpunkt passt.
Zeile 68: Zeile 69:
# '''Endpunkte''' (<code>MapControllers</code>, <code>UseEndpoints</code>, <code>app.Run</code>): Die eigentliche Verarbeitung der Anfrage.
# '''Endpunkte''' (<code>MapControllers</code>, <code>UseEndpoints</code>, <code>app.Run</code>): Die eigentliche Verarbeitung der Anfrage.


----
 
-----


== Custom Middleware erstellen ==
== Custom Middleware erstellen ==
Zeile 78: Zeile 80:
Diese Methode ist stark typisiert und nutzt Dependency Injection voll aus. Die Klasse muss im DI-Container registriert werden (z.B. als Transient).
Diese Methode ist stark typisiert und nutzt Dependency Injection voll aus. Die Klasse muss im DI-Container registriert werden (z.B. als Transient).


<syntaxhighlight lang="csharp">
<syntaxhighlight lang="csharp">using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using System.Threading.Tasks;


Zeile 90: Zeile 91:
         await context.Response.WriteAsync("Factory Middleware Ende\n");
         await context.Response.WriteAsync("Factory Middleware Ende\n");
     }
     }
}
}</syntaxhighlight>
</syntaxhighlight>
'''Registrierung:'''


'''Registrierung:'''
<syntaxhighlight lang="csharp">// In Program.cs
<syntaxhighlight lang="csharp">
// In Program.cs
builder.Services.AddTransient<MyFactoryMiddleware>();
builder.Services.AddTransient<MyFactoryMiddleware>();
// ...
// ...
app.UseMiddleware<MyFactoryMiddleware>();
app.UseMiddleware<MyFactoryMiddleware>();</syntaxhighlight>
</syntaxhighlight>
 
=== 2. Konventionelle Middleware ===
=== 2. Konventionelle Middleware ===


Dies ist der häufigste Weg. Die Klasse benötigt kein Interface, muss aber einer bestimmten Struktur folgen:
Dies ist der häufigste Weg. Die Klasse benötigt kein Interface, muss aber einer bestimmten Struktur folgen:
* Einen öffentlichen Konstruktor, der <code>RequestDelegate</code> als Parameter nimmt.
* Einen öffentlichen Konstruktor, der <code>RequestDelegate</code> als Parameter nimmt.
* Eine Methode <code>Invoke</code> oder <code>InvokeAsync</code>, die <code>HttpContext</code> nimmt und einen <code>Task</code> zurückgibt.
* Eine Methode <code>Invoke</code> oder <code>InvokeAsync</code>, die <code>HttpContext</code> nimmt und einen <code>Task</code> zurückgibt.


<syntaxhighlight lang="csharp">
<syntaxhighlight lang="csharp">public class HelloCustomMiddleware
public class HelloCustomMiddleware
{
{
     private readonly RequestDelegate _next;
     private readonly RequestDelegate _next;
Zeile 130: Zeile 127:
         await _next(httpContext);  
         await _next(httpContext);  
     }
     }
}
}</syntaxhighlight>
</syntaxhighlight>
'''Extension Method für saubere Registrierung:''' Es ist “Best Practice”, eine Extension-Methode für <code>IApplicationBuilder</code> zu erstellen.


'''Extension Method für saubere Registrierung:'''
<syntaxhighlight lang="csharp">public static class MiddlewareExtensions
Es ist "Best Practice", eine Extension-Methode für <code>IApplicationBuilder</code> zu erstellen.
 
<syntaxhighlight lang="csharp">
public static class MiddlewareExtensions
{
{
     public static IApplicationBuilder UseHelloCustomMiddleware(this IApplicationBuilder builder)
     public static IApplicationBuilder UseHelloCustomMiddleware(this IApplicationBuilder builder)
Zeile 146: Zeile 139:


// Verwendung in Program.cs
// Verwendung in Program.cs
app.UseHelloCustomMiddleware();
app.UseHelloCustomMiddleware();</syntaxhighlight>
</syntaxhighlight>


----
-----


== Bedingte Ausführung mit <code>UseWhen</code> ==
== Bedingte Ausführung mit <code>UseWhen</code> ==
Zeile 156: Zeile 148:


'''Syntax:'''
'''Syntax:'''
<syntaxhighlight lang="csharp">
 
app.UseWhen(
<syntaxhighlight lang="csharp">app.UseWhen(
     context => context.Request.Query.ContainsKey("username"), // Bedingung (Predicate)
     context => context.Request.Query.ContainsKey("username"), // Bedingung (Predicate)
     appBuilder =>  
     appBuilder =>  
Zeile 168: Zeile 160:
         });
         });
     }
     }
);
);</syntaxhighlight>
</syntaxhighlight>
'''Szenarien für UseWhen:'''


'''Szenarien für UseWhen:'''
* Logging nur für bestimmte Pfade oder User.
* Logging nur für bestimmte Pfade oder User.
* Spezielle Header nur für API-Requests setzen.
* Spezielle Header nur für API-Requests setzen.
* Bedingte Diagnosetools.
* Bedingte Diagnosetools.


----
 
-----


== Zusammenfassung ==
== Zusammenfassung ==
Zeile 184: Zeile 176:
* <code>app.Use</code> kettet Komponenten aneinander, <code>app.Run</code> beendet die Kette.
* <code>app.Use</code> kettet Komponenten aneinander, <code>app.Run</code> beendet die Kette.
* '''Custom Middleware''' kann einfach als Klasse implementiert werden, um wiederverwendbare Logik zu kapseln.
* '''Custom Middleware''' kann einfach als Klasse implementiert werden, um wiederverwendbare Logik zu kapseln.
== Weblinks ==
* https://learn.microsoft.com/de-de/aspnet/core/fundamentals/middleware/


----
----
''Hinweis: Diese Inhalte wurden mit Unterstützung von Künstlicher Intelligenz erstellt und redaktionell überprüft (Transparenzhinweis gemäß Art. 50 EU AI Act).''
''Hinweis: Diese Inhalte wurden mit Unterstützung von Künstlicher Intelligenz erstellt und redaktionell überprüft (Transparenzhinweis gemäß Art. 50 EU AI Act).''

Version vom 15. Februar 2026, 23:58 Uhr

Hinweis: Diese Inhalte wurden mit Unterstützung von Künstlicher Intelligenz erstellt und redaktionell überprüft (Transparenzhinweis gemäß Art. 50 EU AI Act).


Dieses Tutorial erklärt das Konzept der Middleware in ASP.NET Core, wie sie funktioniert, wie man sie konfiguriert und wie man eigene Middleware-Komponenten erstellt. Es basiert auf den bereitgestellten Notizen und ergänzendem Expertenwissen.

Was ist Middleware?

Middleware in ASP.NET Core ist eine Software-Pipeline, durch die jede HTTP-Anfrage (Request) und jede Antwort (Response) fließt. Man kann sich diese Pipeline wie eine Reihe von hintereinander geschalteten Rohren oder Ventilen vorstellen.

Jede Middleware-Komponente hat drei Hauptaufgaben:

  1. Untersuchen der eingehenden Anfrage.
  2. Bearbeiten der Anfrage oder der Antwort.
  3. Weiterleiten an die nächste Middleware oder Beenden (Short-Circuit) der Pipeline.

Dies ermöglicht eine saubere Modularisierung von Funktionen wie Authentifizierung, Logging, Fehlerbehandlung und Routing.



Grundlagen: app.Use vs. app.Run

Es gibt zwei grundlegende Methoden, um Middleware zur Pipeline hinzuzufügen:

1. app.Run (Terminale Middleware)

Diese Methode fügt eine terminale Middleware hinzu. Das bedeutet, sie beendet die Pipeline. Es wird kein next-Delegat aufgerufen, und nachfolgende Middleware-Komponenten werden nicht ausgeführt.

Beispiel:

app.Run(async (context) => {
    await context.Response.WriteAsync("Ende der Pipeline");
});

Warnung: Wenn Sie zwei app.Run-Aufrufe hintereinander haben, wird nur der erste ausgeführt!

2. app.Use (Verkettbare Middleware)

Diese Methode dient dazu, Aufgaben zu erledigen und dann (meistens) die nächste Komponente in der Kette aufzurufen.

Beispiel:

app.Use(async (context, next) => {
    // Logik VOR dem nächsten Middleware-Aufruf (Request)
    await context.Response.WriteAsync("Hallo ");
    
    // Ruft die nächste Middleware auf
    await next(context); 
    
    // Logik NACH dem nächsten Middleware-Aufruf (Response)
    // Hier können wir die Antwort noch bearbeiten, nachdem der Rest der Pipeline fertig ist.
});

Die Reihenfolge der Middleware (The Middleware Order)

Die Reihenfolge, in der Middleware in Program.cs registriert wird, ist entscheidend. Die Pipeline wird in der Reihenfolge der Registrierung durchlaufen (für den Request) und in umgekehrter Reihenfolge wieder zurück (für die Response).

Empfohlene Reihenfolge

  1. Exception Handler (UseDeveloperExceptionPage, UseExceptionHandler): Sollte ganz oben stehen, um Fehler aus jedem Teil der Pipeline abzufangen.
  2. HSTS & HTTPS Redirection (UseHsts, UseHttpsRedirection): Sicherheit geht vor.
  3. Static Files (UseStaticFiles): Statische Dateien sollten schnell ausgeliefert werden, ohne unnötige Verarbeitung durch spätere Logik.
  4. Routing (UseRouting): Ermittelt, welcher Endpunkt passt.
  5. CORS (UseCors): Cross-Origin Resource Sharing.
  6. Authentication (UseAuthentication): Wer ist der Benutzer?
  7. Authorization (UseAuthorization): Darf der Benutzer das?
  8. Benutzerdefinierte Middleware: Ihre eigene Logik.
  9. Endpunkte (MapControllers, UseEndpoints, app.Run): Die eigentliche Verarbeitung der Anfrage.



Custom Middleware erstellen

Es gibt zwei Hauptwege, eigene Middleware zu schreiben: als Klasse mit IMiddleware (Factory-based) oder als konventionelle Klasse.

1. Middleware mit IMiddleware (Factory-based)

Diese Methode ist stark typisiert und nutzt Dependency Injection voll aus. Die Klasse muss im DI-Container registriert werden (z.B. als Transient).

using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

public class MyFactoryMiddleware : IMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        await context.Response.WriteAsync("Factory Middleware Start\n");
        await next(context);
        await context.Response.WriteAsync("Factory Middleware Ende\n");
    }
}

Registrierung:

// In Program.cs
builder.Services.AddTransient<MyFactoryMiddleware>();
// ...
app.UseMiddleware<MyFactoryMiddleware>();

2. Konventionelle Middleware

Dies ist der häufigste Weg. Die Klasse benötigt kein Interface, muss aber einer bestimmten Struktur folgen:

  • Einen öffentlichen Konstruktor, der RequestDelegate als Parameter nimmt.
  • Eine Methode Invoke oder InvokeAsync, die HttpContext nimmt und einen Task zurückgibt.
public class HelloCustomMiddleware
{
    private readonly RequestDelegate _next;

    public HelloCustomMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        // Beispiel: Prüfen auf Query-Parameter
        if (httpContext.Request.Query.ContainsKey("firstname") && 
            httpContext.Request.Query.ContainsKey("lastname"))
        {
            string fullName = $"{httpContext.Request.Query[\"firstname\"]} {httpContext.Request.Query[\"lastname\"]}";
            await httpContext.Response.WriteAsync($"Hallo {fullName}\n");
        }

        // WICHTIG: Nächste Middleware aufrufen
        await _next(httpContext); 
    }
}

Extension Method für saubere Registrierung: Es ist “Best Practice”, eine Extension-Methode für IApplicationBuilder zu erstellen.

public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseHelloCustomMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<HelloCustomMiddleware>();
    }
}

// Verwendung in Program.cs
app.UseHelloCustomMiddleware();

Bedingte Ausführung mit UseWhen

Mit UseWhen können Sie eine Verzweigung in der Pipeline erstellen, die nur unter bestimmten Bedingungen ausgeführt wird. Die Haupt-Pipeline wird danach wieder zusammengeführt (im Gegensatz zu Map, das oft eine Sackgasse ist).

Syntax:

app.UseWhen(
    context => context.Request.Query.ContainsKey("username"), // Bedingung (Predicate)
    appBuilder => 
    {
        // Diese Middleware läuft nur, wenn die Bedingung wahr ist
        appBuilder.Use(async (context, next) =>
        {
            await context.Response.WriteAsync("Hallo vom Branch!\n");
            await next();
        });
    }
);

Szenarien für UseWhen:

  • Logging nur für bestimmte Pfade oder User.
  • Spezielle Header nur für API-Requests setzen.
  • Bedingte Diagnosetools.



Zusammenfassung

  • Middleware bildet das Rückgrat einer ASP.NET Core Anwendung.
  • Reihenfolge ist wichtig: Von globalen Anliegen (Error Handling) zu spezifischen (Routing, Auth) zu Endpunkten.
  • app.Use kettet Komponenten aneinander, app.Run beendet die Kette.
  • Custom Middleware kann einfach als Klasse implementiert werden, um wiederverwendbare Logik zu kapseln.

Hinweis: Diese Inhalte wurden mit Unterstützung von Künstlicher Intelligenz erstellt und redaktionell überprüft (Transparenzhinweis gemäß Art. 50 EU AI Act).