Middleware pipeline dan Options Pattern
Ringkasan satu halaman. Dari Lesson 0005.
Pipeline [1]
- Setiap middleware: memilih meneruskan ke
nextatau tidak, dan bisa bekerja sebelum dan sesudahnext. - Urutan di
Program.cs= urutan request; response lewat urutan terbalik (A-B-C masuk, C-B-A keluar). - Short-circuit: tidak memanggil
next→ middleware itu menjadi terminal; endpoint tidak jalan. app.Usemenerimanext;app.Runterminal (tanpanext).- Padanan Express:
app.use((req, res, next) => …).
Urutan untuk Web API [1]
| # | Baris | Kenapa di posisi ini |
|---|---|---|
| 1 | UseExceptionHandler | paling luar, menangkap exception dari semua sesudahnya (Express: error handler justru terakhir) |
| 2 | UseHttpsRedirection | alihkan http → https sebelum kerja lain |
| 3 | UseRouting | pilih endpoint |
| 4 | UseCors | sesudah UseRouting, sebelum auth; sebelum UseResponseCaching [6] |
| 5 | UseAuthentication | siapa user ini (isi HttpContext.User) |
| 6 | UseAuthorization | boleh atau tidak; butuh hasil authentication |
| 7 | MapControllers | endpoint: Controller → Service → Repository |
.NET 8 menambah UseRouting/UseAuthentication/UseAuthorization otomatis bila tidak dipanggil, tetapi kalau memakai UseCors, panggil auth secara eksplisit sesudahnya.
Service Scoped di middleware [2]
public class AuditMiddleware(RequestDelegate next, ILogger<AuditMiddleware> log) // Singleton saja
{
public async Task InvokeAsync(HttpContext ctx, AppDbContext db) { … await next(ctx); } // Scoped di sini
}
Middleware dibuat sekali seumur aplikasi → service Scoped di constructor = captive dependency (lihat Service Lifetime).
Konfigurasi berlapis [3]
| Prioritas | Sumber | Padanan Node |
|---|---|---|
| tertinggi | argumen command-line | process.argv |
environment variable (Jwt__Key → Jwt:Key) | process.env | |
| User Secrets (hanya Development) | .env di .gitignore | |
appsettings.{Environment}.json | config/production.js | |
| terendah | appsettings.json | config/default.js |
- Secret tidak di kode/appsettings. Dev:
dotnet user-secrets init+dotnet user-secrets set "Jwt:Key" "…"(di luar repo, tidak terenkripsi). Prod: environment variable / Azure Key Vault. [5]
Options Pattern [4]
builder.Services.AddOptions<JwtOptions>()
.Bind(builder.Configuration.GetSection("Jwt"))
.ValidateDataAnnotations()
.ValidateOnStart(); // singkat: Configure<JwtOptions>(GetSection("Jwt"))
public class TokenService(IOptions<JwtOptions> o) { … o.Value.Key … }
| Interface | Lifetime | Nilai terbaru setelah start? |
|---|---|---|
IOptions<T> | Singleton | tidak |
IOptionsSnapshot<T> | Scoped (jangan ke Singleton) | ya, per request |
IOptionsMonitor<T> | Singleton | ya, reload + notifikasi |
Alasan: akses bertipe kuat; Encapsulation (class hanya bergantung pada setting miliknya) dan Separation of Concerns.
Jawaban 60–90 detik
Request lewat pipeline middleware sesuai urutan di Program.cs; tiap middleware bekerja sebelum dan sesudah next, atau short-circuit.
Exception handler paling awal (kebalikan Express), lalu HTTPS, routing, CORS, authentication, authorization, endpoint. Authentication sebelum authorization karena harus tahu siapa dulu.
Middleware dibuat sekali, jadi service Scoped masuk lewat InvokeAsync. Konfigurasi berlapis: appsettings → appsettings.{Env} → User Secrets → env var → command-line;
secret di User Secrets (dev) atau env var/Key Vault (prod); Service membacanya lewat IOptions<T>.
Sumber: [1] Middleware · [2] Write custom middleware · [3] Configuration · [4] Options pattern · [5] App secrets · [6] CORS