Web uygulamalarında, bir HTTP isteği gönderilir ve ardından bir HTTP yanıtı alınır. Bu basit görünen iletişimin arkasında, istekler ve yanıtlar bir dizi işlemden geçer. İşte bu işlemlerin gerçekleştiği sürece “pipeline” (işlem hattı) denir. Pipeline içindeki her bir bileşene ise “middleware” adı verilir.
Middleware’ler, gelen istekleri işlemek, yanıtları değiştirmek veya akışı kontrol etmek için kullanılır. Örneğin, bir middleware gelen her isteği loglayabilir, yanıt sürelerini ölçebilir, kullanıcı kimliğini doğrulayabilir veya yetki kontrolü yapabilir.
Havalimanı Örneği
Bu süreci, havalimanlarındaki güvenlik kontrollerine benzetebiliriz. Bir yolcu (HTTP request) uçağa binmeden önce bir dizi kontrolden geçer.
- Bilet kontrolü (Authentication)
- Çanta kontrolü (Request Validation)
- Güvenlik kontrolü (Authorization)
- Uçağa biniş (HTTP Response)
Bu adımların tümüne pipeline, her bir kontrol noktasına ise middleware diyoruz.
Middleware Pipeline Nasıl Çalışır
Uygulamaya gelen her istek, pipeline’a girer. Pipeline’daki middleware’ler sırayla çalıştırılır ve ardından yanıt oluşturulur.
Middleware'ler tanımlandıkları sırayla çalışır.
Her bir middleware, kendi işlemini yaptıktan sonra isteği bir sonraki middleware’e iletebilir veya yanıtı doğrudan dönebilir. Bu noktada aşağıdaki gibi bir akış olur.
- Middleware isteği işler veya kontrol eder.
next()
ile bir sonraki middleware’a geçirir.- Tüm middleware’ler tamamlandıktan sonra response oluşur.
- Response, aynı middleware zincirinden geriye döner.
Örnek Bir ASP.NET Core API Projesinin Middleware Pipeline’ı
Minimal API ile İlk Middleware
İlk middleware’ımızı en sade haliyle yazalım. Bu middleware, uygulamaya gelen her isteği konsola yazdıracak.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Request Logging Middleware
app.Use(async (context, next) =>
{
Console.WriteLine($"Request: {context.Request.Method} {context.Request.Path}");
await next(); // Next middleware
});
app.MapGet("/", () => "Hello World!");
app.Run();
Console Output
Request: GET /
Request: GET /hello
Bu örnekte, her gelen isteğin HTTP metodunu ve yolunu konsola loglayan basit bir middleware oluşturduk.
context
nedir?
context
, gelen HTTP request ve gönderilecek HTTP response hakkında tüm bilgilere erişmemizi sağlayan bir nesnedir.
next
nedir?
next
, ilgili middleware’ den sonra çalışacak olan middleware’i temsil eder. next();
diyerek istek akışını ilerletiriz. Bu yapı sayesinde middleware’ler zincir gibi birbirine bağlanır: her biri isterse isteği işler, değiştirebilir ya da tamamen durdurabilir.
Middleware Örnek 2: Sıralı Çalışma
Middleware’ler sırasıyla çalışır. Her bir middleware içerisindeki next()
çağrısından önce ve sonra yazılan kodlar, bu işlem sırasına göre çalıştırılır.
Aşağıdaki örnekte, ilk middleware’de önce bir ifade konsola yazdırılır, ardından next()
ile bir sonraki middleware çağırılır. Bu süreç tamamlandıktan sonra (buradaki örneğimizde ikinci middleware tamamlandığında), next()
sonrasındaki kodlar çalıştırılır.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// First Middleware
app.Use(async (context, next) =>
{
Console.WriteLine("➡️ Entering First Middleware");
await next();
Console.WriteLine("⬅️ Exiting First Middleware");
});
// Second Middleware
app.Use(async (context, next) =>
{
Console.WriteLine("➡️ Entering Second Middleware");
await next();
Console.WriteLine("⬅️ Exiting Second Middleware");
});
app.MapGet("/", () => "Hello World!");
app.Run();
Console Output
➡️ Entering First Middleware
➡️ Entering Second Middleware
⬅️ Exiting Second Middleware
⬅️ Exiting First Middleware
Middleware Örnek 3: Yanıt Süresini Ölçme
Şimdi, gelen isteğe verilen yanıtın süresini ölçen bir middleware yazalım. Bu middleware’i daha profesyonel bir hale getirmek için ayrı bir sınıf olarak oluşturacağız.
using System.Diagnostics;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Using the ResponseTimeMiddleware
app.UseMiddleware<ResponseTimeMiddleware>();
app.MapGet("/", () => "Hello World!");
app.Run();
// ResponseTimeMiddleware codes written as a class
public class ResponseTimeMiddleware
{
private readonly RequestDelegate _next;
public ResponseTimeMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext context)
{
var stopwatch = Stopwatch.StartNew();
var method = context.Request.Method;
var path = context.Request.Path;
await _next(context);
stopwatch.Stop();
var elapsedMs = stopwatch.ElapsedMilliseconds;
Console.WriteLine($"[{DateTime.Now}] {method} {path} - Response time: {elapsedMs}ms (HTTP {context.Response.StatusCode})");
}
}
Console Output
[7.04.2025 15:39:21] GET / - Response time: 2ms (HTTP 200)
[7.04.2025 15:39:35] GET / - Response time: 1ms (HTTP 200)
[7.04.2025 15:45:14] GET / - Response time: 3ms (HTTP 200)
InvokeAsync
nedir?
InvokeAsync
, custom middleware sınıflarında tanımlanması gereken özel bir metottur. ASP.NET Core, middleware sınıfını çalıştırmak için bu metodu otomatik olarak çağırır.
Middleware Örnek 4: IP Filtresi
Şimdi de gelen isteklerin yalnızca localhost (127.0.0.1)
üzerinden yapılmasına izin veren bir middleware yazalım.
using System.Net;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseMiddleware<IpFilterMiddleware>();
app.MapGet("/", () => "Hello World!");
app.Run();
public class IpFilterMiddleware
{
private readonly RequestDelegate _next;
public IpFilterMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext context)
{
var clientIp = context.Connection.RemoteIpAddress;
// Uncomment below line to test access from a different IP
// clientIp = IPAddress.Parse("203.0.113.5");
bool isLocalhost = IPAddress.IsLoopback(clientIp);
if (isLocalhost)
{
await _next(context);
}
else
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
await context.Response.WriteAsync("This API is only accessible from localhost.");
}
}
}
✅ HTTP Response (Request from local IP)
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Date: Mon, 07 Apr 2025 13:24:36 GMT
Server: Kestrel
Transfer-Encoding: chunked
Hello World!
❌ HTTP Response (Request from different IP)
HTTP/1.1 403 Forbidden
Date: Mon, 07 Apr 2025 13:26:15 GMT
Server: Kestrel
Transfer-Encoding: chunked
This API is only accessible from localhost.
GitHub Proje Bağlantısı
Tüm bu örnekleri içeren bir GitHub reposu hazırladım. Repoyu klonlayarak kodları kolaylıkla çalıştırabilirsiniz.
GitHub – Middleware Geliştirme 101