Menulis Middleware Kustom
Buat middleware inline dengan Use/Run/Map dan middleware berbasis kelas dengan InvokeAsync untuk komponen yang dapat digunakan kembali.
Menulis Middleware Kustom adalah pelajaran C# Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar C# Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus C# Academy mencakup 4 pelajaran total.
Mengapa Middleware Khusus?
Middleware khusus menangani hal-hal lintas fungsi yang berlaku untuk banyak permintaan: pencatatan, pengukuran waktu, penanganan kesalahan, autentikasi, kompresi, dan penyimpanan dalam cache. Menulisnya satu kali membuat logika tersebut berjalan otomatis untuk setiap permintaan yang cocok.
Middleware Sebaris dengan Use
Cara tercepat untuk menambahkan middleware adalah meneruskan delegasi ke app.Use(). Cara ini cocok untuk pembuatan purwarupa atau logika yang benar-benar sederhana.
app.Use(async (context, next) =>
{
var start = DateTimeOffset.UtcNow;
await next(context);
var elapsed = DateTimeOffset.UtcNow - start;
context.Response.Headers.Append(
"X-Elapsed", elapsed.TotalMilliseconds.ToString("F0") + "ms");
});Middleware Berbasis Kelas (Konvensi)
Kelas middleware konvensional memiliki konstruktor yang menerima RequestDelegate dan metode publik InvokeAsync. Parameter konstruktor tambahan dapat disuntikkan dari DI.
public class SecurityHeadersMiddleware
{
private readonly RequestDelegate _next;
public SecurityHeadersMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext context)
{
var headers = context.Response.Headers;
headers.Append("X-Content-Type-Options", "nosniff");
headers.Append("X-Frame-Options", "DENY");
headers.Append("X-XSS-Protection", "1; mode=block");
headers.Append("Referrer-Policy", "strict-origin-when-cross-origin");
await _next(context);
}
}
// Extension method for clean registration:
public static class SecurityHeadersExtensions
{
public static IApplicationBuilder UseSecurityHeaders(
this IApplicationBuilder app) =>
app.UseMiddleware<SecurityHeadersMiddleware>();
}IMiddleware untuk Dependensi Bercakupan
Jika middleware Anda memerlukan layanan bercakupan, seperti DbContext, implementasikan IMiddleware. Daftarkan sebagai layanan bercakupan agar kerangka kerja membuat resolusi baru untuk setiap permintaan.
public class AuditMiddleware : IMiddleware
{
private readonly AuditDbContext _db;
private readonly IHttpContextAccessor _http;
public AuditMiddleware(AuditDbContext db, IHttpContextAccessor http)
{
_db = db;
_http = http;
}
public async Task InvokeAsync(HttpContext ctx, RequestDelegate next)
{
await next(ctx);
if (ctx.Request.Method != "GET")
{
_db.AuditLogs.Add(new AuditLog
{
User = ctx.User.Identity?.Name,
Path = ctx.Request.Path,
Status = ctx.Response.StatusCode,
At = DateTime.UtcNow
});
await _db.SaveChangesAsync();
}
}
}
builder.Services.AddScoped<AuditMiddleware>();
app.UseMiddleware<AuditMiddleware>();Middleware dengan Opsi
Teruskan konfigurasi ke middleware melalui objek opsi dalam konstruktor. Daftarkan opsi dengan kontainer DI atau teruskan secara langsung saat mendaftarkan middleware.
public class ThrottleOptions
{
public int MaxRequestsPerSecond { get; set; } = 100;
public string[] ExcludedPaths { get; set; } = Array.Empty<string>();
}
public class ThrottleMiddleware
{
private readonly RequestDelegate _next;
private readonly ThrottleOptions _options;
public ThrottleMiddleware(RequestDelegate next, ThrottleOptions options)
{
_next = next;
_options = options;
}
// ...
}
// Registration with options:
app.UseMiddleware<ThrottleMiddleware>(new ThrottleOptions
{
MaxRequestsPerSecond = 50
});Middleware Penanganan Pengecualian
Middleware penanganan pengecualian khusus menangkap semua pengecualian yang tidak tertangani dan mengembalikan respons kesalahan terstruktur.
public class GlobalExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<GlobalExceptionMiddleware> _logger;
public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> l)
{
_next = next;
_logger = l;
}
public async Task InvokeAsync(HttpContext ctx)
{
try { await _next(ctx); }
catch (NotFoundException ex)
{
ctx.Response.StatusCode = 404;
await ctx.Response.WriteAsJsonAsync(new { error = ex.Message });
}
catch (Exception ex)
{
_logger.LogError(ex, "Unhandled exception");
ctx.Response.StatusCode = 500;
await ctx.Response.WriteAsJsonAsync(new { error = "Internal server error" });
}
}
}Middleware Pencatatan Permintaan
Middleware pencatatan permintaan dan respons secara terstruktur merekam metode, jalur, kode status, dan waktu berlalu untuk setiap permintaan.
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestLoggingMiddleware> _log;
public RequestLoggingMiddleware(RequestDelegate n, ILogger<RequestLoggingMiddleware> l)
{ _next = n; _log = l; }
public async Task InvokeAsync(HttpContext ctx)
{
var sw = System.Diagnostics.Stopwatch.StartNew();
await _next(ctx);
sw.Stop();
_log.LogInformation(
"{Method} {Path} -> {Status} in {Ms}ms",
ctx.Request.Method,
ctx.Request.Path,
ctx.Response.StatusCode,
sw.ElapsedMilliseconds);
}
}Middleware Bersyarat dengan UseWhen
UseWhen membuat percabangan bersyarat dalam alur berdasarkan sebuah predikat, tanpa memisahkannya secara permanen. Setelah selesai, cabang tersebut bergabung kembali ke alur utama.
// Apply authentication middleware only to /api/* routes
app.UseWhen(
ctx => ctx.Request.Path.StartsWithSegments("/api"),
apiApp =>
{
apiApp.UseAuthentication();
apiApp.UseAuthorization();
});
// Public routes (/public/*) bypass authentication
app.MapGet("/public/health", () => "OK");
app.MapGet("/api/data", [Authorize] async (DataService s) => await s.GetAsync());Middleware Penyimpanan Respons dalam Cache
Middleware penyimpanan respons dalam cache bawaan menyimpan respons lengkap di memori. Konfigurasikan kebijakan cache untuk setiap titik akhir menggunakan header atau atribut.
builder.Services.AddResponseCaching();
app.UseResponseCaching();
app.MapGet("/products", async (AppDbContext db) =>
{
var products = await db.Products.AsNoTracking().ToListAsync();
return Results.Ok(products);
})
.CacheOutput(p => p.Expire(TimeSpan.FromMinutes(2)).Tag("products"));Di Dunia Nyata: Middleware Mode Pemeliharaan
Middleware mode pemeliharaan yang membaca penanda dari konfigurasi, dengan dukungan muat ulang langsung melalui IOptionsMonitor, dan menolak permintaan yang bukan pemeriksaan kesehatan selama pemeliharaan.
public class MaintenanceMiddleware
{
private readonly RequestDelegate _next;
private readonly IOptionsMonitor<MaintenanceOptions> _options;
public MaintenanceMiddleware(RequestDelegate next,
IOptionsMonitor<MaintenanceOptions> opts)
{ _next = next; _options = opts; }
public async Task InvokeAsync(HttpContext ctx)
{
if (_options.CurrentValue.IsEnabled
&& !ctx.Request.Path.StartsWithSegments("/health"))
{
ctx.Response.StatusCode = 503;
ctx.Response.Headers.Append("Retry-After", "300");
await ctx.Response.WriteAsJsonAsync(
new { message = "Service under maintenance" });
return;
}
await _next(ctx);
}
}Pemeriksaan Singkat
Mengapa Anda sebaiknya mengimplementasikan IMiddleware, bukan pendekatan berbasis konvensi, saat memerlukan layanan bercakupan seperti DbContext?
Rangkuman: Menulis Middleware Khusus
Inti penting:
- Sebaris (delegasi Use): cepat, cocok untuk satu baris; berbasis kelas: dapat digunakan kembali dan diuji
- Kelas konvensional: konstruktornya menerima RequestDelegate; InvokeAsync(HttpContext)
- IMiddleware: resolusi DI per permintaan — diperlukan untuk dependensi bercakupan
- UseWhen: percabangan bersyarat yang bergabung kembali ke alur utama
- Tulis middleware penanganan pengecualian terlebih dahulu, sebagai lapisan paling luar, untuk menangkap semua kesalahan
- Buat metode ekstensi (UseXxx) untuk pendaftaran yang rapi dan mudah ditemukan
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Menulis Middleware Kustom” gratis?
Ya — teks lengkap “Menulis Middleware Kustom” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus C# Academy, upgrade ke CoddyKit PRO. Kursus C# Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Menulis Middleware Kustom”?
Buat middleware inline dengan Use/Run/Map dan middleware berbasis kelas dengan InvokeAsync untuk komponen yang dapat digunakan kembali. Kamu berlatih C# Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai C# Academy?
Tidak diperlukan pengalaman sebelumnya. C# Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “Menulis Middleware Kustom” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran C# Academy ini?
Ya. Setiap pelajaran C# Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Gambaran Umum Alur ASP.NET Core
- Menulis Middleware Kustom
- Penghentian Singkat & Percabangan
- Urutan Middleware & Middleware Bawaan