Middleware adalah komponen perangkat lunak yang disusun dalam sebuah pipeline, masing-masing menangani sebagian dari proses request dan response sebelum diteruskan ke middleware berikutnya atau dikembalikan ke client. Setiap request yang masuk ke aplikasi ASP.NET Core selalu melewati pipeline ini.
Middleware bisa melakukan berbagai hal: memeriksa autentikasi, mencatat log, menangani error secara terpusat, mengompresi response, atau bahkan menghentikan pipeline lebih awal tanpa meneruskan request ke middleware berikutnya jika kondisi tertentu terpenuhi.
Artikel ini membahas cara kerja middleware pipeline, urutan eksekusinya yang penting diperhatikan, serta cara membuat middleware custom untuk kebutuhan spesifik yang tidak tersedia secara bawaan.
Urutan Middleware Sangat Menentukan Perilaku Aplikasi
Urutan middleware memengaruhi hasil akhir pemrosesan request
Request Delegate dan Konsep Next
Middleware bisa menjalankan kode sebelum dan sesudah next()
Membuat Middleware Custom
Middleware custom sebagai class terpisah untuk logika reusable
Menghentikan Pipeline Lebih Awal
Tidak memanggil next() menghentikan pipeline lebih awal
Selain Use dan UseMiddleware, ASP.NET Core juga menyediakan method Map dan MapWhen yang memungkinkan percabangan pipeline berdasarkan kondisi tertentu, misalnya mengarahkan request dengan path tertentu ke rangkaian middleware yang berbeda sama sekali dari pipeline utama, berguna untuk memisahkan penanganan request API dan request halaman statis dalam satu aplikasi yang sama.
Urutan Middleware dan Mengapa Posisinya Tidak Bisa Sembarangan
Urutan middleware yang benar pada Program.cs
Middleware di ASP.NET Core bekerja seperti rantai (chain of responsibility): setiap komponen menerima HttpContext, bisa melakukan sesuatu sebelum memanggil middleware berikutnya lewat delegate next(), dan bisa melakukan sesuatu lagi setelah middleware berikutnya selesai dieksekusi. Karena sifatnya berurutan, posisi pendaftaran middleware di Program.cs sangat menentukan perilaku aplikasi, bukan sekadar urutan kode yang bisa ditukar bebas.
Contoh paling konkret adalah UseAuthentication() yang wajib diletakkan sebelum UseAuthorization(), dan keduanya wajib berada setelah UseRouting() tetapi sebelum MapControllers(). Jika urutan ini dilanggar, ASP.NET Core versi modern akan langsung melempar exception saat aplikasi start karena middleware otorisasi membutuhkan informasi endpoint yang baru tersedia setelah proses routing selesai dijalankan.
UseStaticFiles() biasanya diletakkan di awal pipeline karena jika request menuju file statis seperti gambar atau CSS, middleware ini akan langsung menangani dan mengirim response tanpa perlu meneruskan request ke middleware berikutnya, sehingga menghemat proses routing dan autentikasi yang tidak relevan untuk permintaan file statis semacam itu.
Membuat Custom Middleware dengan Short-Circuiting
Middleware yang menghentikan pipeline lebih awal tanpa memanggil next()
Setiap middleware kustom di ASP.NET Core menerima RequestDelegate bernama next lewat constructor, yang mewakili middleware berikutnya dalam pipeline. Memanggil await _next(context) meneruskan request ke komponen selanjutnya, sedangkan tidak memanggilnya sama sekali, seperti pada contoh ApiKeyMiddleware di atas ketika validasi gagal, membuat pipeline berhenti di titik tersebut dan response langsung dikirim tanpa pernah mencapai controller atau middleware setelahnya. Instance middleware sendiri bersifat singleton sepanjang umur aplikasi, sehingga field yang disimpan langsung di dalam class middleware harus bersifat stateless atau thread-safe.
Teknik short-circuiting ini banyak dipakai untuk kebutuhan seperti validasi API key sederhana, rate limiting kustom, atau pengecekan maintenance mode yang harus memblokir seluruh request tanpa terkecuali sebelum masuk ke logika aplikasi. Karena middleware dieksekusi dalam urutan pendaftarannya, menempatkan middleware pemblokir ini di posisi paling awal pipeline memastikan request yang tidak valid tidak membebani proses routing atau autentikasi yang lebih berat di belakangnya. Dependency seperti IConfiguration pada contoh di atas disuntikkan lewat parameter method InvokeAsync, bukan lewat constructor, karena constructor middleware hanya dipanggil sekali saat aplikasi start.
Selain pola berbasis class seperti ApiKeyMiddleware yang membutuhkan method InvokeAsync, ASP.NET Core juga mendukung middleware inline lewat app.Use(async (context, next) => { ... }) langsung di Program.cs untuk logika singkat yang tidak perlu dipisah ke file tersendiri. Pendekatan class lebih disarankan ketika middleware membutuhkan dependency injection tambahan atau logikanya cukup kompleks untuk diuji secara terpisah lewat unit test. Middleware inline lebih cocok untuk eksperimen cepat atau logging sementara yang tidak akan menjadi bagian permanen dari arsitektur aplikasi.
Middleware vs Action Filter: Memilih Tempat yang Tepat untuk Logika Lintas Request
Middleware bekerja di level pipeline HTTP paling luar sehingga cocok untuk hal yang berlaku ke semua request tanpa memandang controller tujuannya, seperti logging mentah, penanganan header, atau autentikasi awal. Action filter bekerja lebih dekat dengan MVC pipeline sehingga punya akses ke ActionDescriptor, argumen yang sudah melalui model binding, dan hasil action sebelum diserialisasi menjadi response, akses yang tidak tersedia secara langsung di middleware biasa karena middleware belum tahu action mana yang akan dieksekusi.
Memilih salah satu pendekatan bergantung pada seberapa spesifik konteks yang dibutuhkan oleh logika tersebut. Validasi header API key lebih pas ditulis sebagai middleware karena berlaku global ke seluruh endpoint, sementara pengukuran durasi eksekusi action tertentu lebih mudah dibaca sebagai action filter karena punya akses langsung ke nama action yang sedang dieksekusi beserta parameter yang dikirimkan klien, sehingga log yang dihasilkan lebih informatif.
Kesalahan Umum yang Sering Terjadi
Mendaftarkan Middleware dalam Urutan yang Salah
Kesalahan urutan middleware, seperti UseAuthorization sebelum UseAuthentication, adalah salah satu penyebab paling umum bug autentikasi dan otorisasi yang membingungkan karena tidak ada error eksplisit yang muncul saat kompilasi.
Lupa Memanggil next() pada Middleware Custom
Middleware yang lupa memanggil next() tanpa maksud menghentikan pipeline secara sengaja akan membuat seluruh middleware dan controller setelahnya tidak pernah dieksekusi, menghasilkan response yang tidak sesuai ekspektasi tanpa pesan error yang jelas.
Menaruh Logika Berat di Middleware yang Dijalankan Setiap Request
Middleware dieksekusi untuk SETIAP request yang masuk ke aplikasi, sehingga menaruh operasi berat seperti query database kompleks di dalamnya tanpa pertimbangan matang bisa menjadi bottleneck performa pada aplikasi dengan trafik tinggi.
Kapan Pendekatan Ini Tidak Cocok Dipakai
Middleware bawaan ASP.NET Core sudah mencakup kebutuhan umum seperti autentikasi, routing, dan penanganan error, sehingga untuk kebanyakan kasus tidak perlu membuat middleware custom dari awal.
Middleware custom memberikan fleksibilitas penuh untuk kebutuhan spesifik aplikasi, namun menambah kompleksitas pipeline yang harus dipahami seluruh tim, sehingga sebaiknya dibuat hanya ketika kebutuhan tersebut benar-benar tidak tercakup oleh middleware bawaan yang sudah teruji.
Ringkasan
Middleware pipeline adalah jantung dari pemrosesan request di ASP.NET Core, dengan urutan pendaftaran yang sangat menentukan perilaku akhir aplikasi. Pahami konsep next() dan kemampuan menghentikan pipeline lebih awal untuk membangun middleware custom yang efektif sesuai kebutuhan spesifik aplikasi.
Seri Belajar .NET Core:
← Sebelumnya: Membuat Project ASP.NET Core Web API Pertama
→ Selanjutnya: Routing dan Controller di ASP.NET Core