Middleware Nedir? .NET Core'da Middleware Kullanımı

Can Yüksel

Erdoğancan Yüksel

2 dakika 38 saniye okuma süresi

Middleware, yazılım geliştirme sürecinde istemci(client) ile sunucu(server) arasındaki iletişimin yönetilmesinde kullanılan en önemli bileşenlerden birisidir. Bir isteği middleware aracılığıyla değiştirebilir veya durdurabiliriz.

middleware-nedir

Middleware Nedir?

Middleware, istemci(client) ile sunucu(server) arasındaki iletişimi yönetmek için kullanılan en önemli bileşenlerden birisidir. ASP.NET Core başta olmak üzere modern framework'ler, middleware yapısını temel bir mimari prensip olarak benimsemişlerdir. İstemci tarafından gönderilen bir request isteği ile server tarafından dönülecek olan response arasına girerek bu kısımda bir işlem yapmak isteniyorsa bu işlemler middleware'ler aracığılığıyla yapılmaktadır. Bir middleware işleme girdiğinde ilgili middleware içerisindeki işlem sona ermeden başka bir middleware'i tetikleyebilir ve tetiklediği middleware işlemini sonlandırdıktan sonra kendi işlemini sonlandırabilir.

Middleware'ler şu görevlerde kullanılabilir:

  • Kimlik doğrulama (Authentication): Kullanıcının kimlik doğrulaması için.
  • Yetkilendirme (Authorization): Kullanıcının hangi kaynaklara erişim sağlayacağının belirlenmesi için.
  • Loglama (Logging): İşlem sırasındaki hatalar veya işlem adımı bilgilerinin kayıt edilmesi ve performans ölçümlerinin yapılabilmesi için.
  • Hata Yönetimi (Exception Handling): Hataların anlamlı bir şekilde son kullanıcıya yansıtılması için.
  • Cache ve performans iyileştirme: Sık kullanılan verilerin önbelleğe alınarak sunucu tarafından hızlı yanıt verilmesi için.
  • Response Manipülasyonu: Örneğin JSON formatındaki veriyi XML olarak dönüştürmek veya gelen isteklerdeki verileri normalize etmek için.

ASP.NET Core Middleware Metotları

ASP.NET Core'da middleware bileşenleri IApplicationBuilder üzerinden zincir halinde eklenir. Ekleme işlemi için üç temel metot bulunmaktadır:

1. Use()

Middleware için hem öncesinde hem sonrasında işlem yapabilme imkanı verir. Bu metot ile bir sonraki middleware üyesine erişim yapılabilir. await _next(context) çağrısı ile pipeline'daki bir sonraki middleware'e geçilir.

2. Run()

Pipeline'ın sonlandırıcısıdır. Kendisinden sonra middleware çalıştırmaz ve akış kesilir.

3. Map()

Map metodu belirli bir route için middleware tanımlamaya yaramaktadır. Örneğin /api-old ile başlayan istekleri farklı bir pipeline'a yönlendirebiliriz.

ASP.NET Core Middleware Kullanımı

1. Hazır Middleware Kullanımı

ASP.NET Core birçok hazır middleware ile birlikte gelmektedir. Program.cs dosyası içerisinde hazır olarak gelen bazı middleware'ler:

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseMiddleware<RequestLoggingMiddleware>(); // Kendi eklediğimiz middleware

app.UseRouting(); // Routing middleware
app.UseAuthentication(); // Kimlik doğrulama
app.UseAuthorization(); // Yetkilendirme
app.MapControllers();

app.Run();

2. Kendi Middleware'imizi Yazmak

// C# 12 ve .NET 8 sonrası için Primary Constructor
public class RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
{
    public async Task InvokeAsync(HttpContext context)
    {
        logger.LogInformation("Request: {method} {url}", context.Request.Method, context.Request.Path);

        await next(context); // Bir sonraki middleware'a geç

        logger.LogInformation("Response Status: {statusCode}", context.Response.StatusCode);
    }
}

// Öncesi için

public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<RequestLoggingMiddleware> _logger;

    public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
    {
        _logger = logger;
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        _logger.LogInformation("Request: {method} {url}", context.Request.Method, context.Request.Path);

        await _next(context); // Bir sonraki middleware'a geç

        _logger.LogInformation("Response Status: {statusCode}", context.Response.StatusCode);
    }
}

Yukarıdaki kod örneğini incelediğimizde bir middleware için Invoke(HttpContext context) veya InvokeAsync(HttpContext context) imzası şarttır. HttpContext ile gelen isteğin(request) ve giden cevabın(response) bütün detayları taşınır. (context.request.Path, context.Request.Headers, context.Response.StatusCode, context.User gibi.)

Middleware Kullanımında En İyi Pratikler

ASP.NET Core projelerinde middleware yapısını kullanırken dikkat edilmesi gereken bazı önemli noktalar vardır. Bunlar, hem uygulamanın performansını hem de sürdürülebilirliğini doğrudan etkilemektedir:

  • Tek Sorumluluk Prensibi (Single Responsibility):Her middleware tek bir iş yapmalıdır. (Sadece loglama yapmak, sadece yetkilendirme işlemi veya sadece kimlik doğrulama gibi.)
  • Sıralamaya Dikkat Edilmesi: Middleware'lerin çalıştığı sıra çok önemlidir. Aksi durumda yanlış konumlandırılan middleware'ler istek-yanıt sürecinde beklenmeyen sonuçlar doğurabilir. (Örneğin; UseRouting() middleware'i UseAuthorization()'dan önce gelmelidir. UseAuthorization() middleware'i UseAuthentication()'dan önce gelmelidir.)
  • Global Exception Handling Kullanımı: Her middleware için ayrı bir try-catch kullanmak yerine global bir hata yakalama middleware'i eklemek daha doğru bir yaklaşımdır.
  • Gereksiz Middleware’lerden Kaçınmak: Pipeline'a eklenen her middleware istek-yanıt süresini uzattığı için kullanılmayan middleware'ler kaldırılmalıdır.
  • Test Edilebilir Olmasına Dikkat Etmek: ILogger, IConfiguration, DbContext gibi servisleri constructor injection ile almak unit test yazmayı kolaylaştıracaktır.

 Sonuç olarak Middleware'ler ASP.NET Core uygulamaları için oldukça önemlidir. İstek-yanıt döngüsünü yönetmek ve uygulamaları daha bakımı kolay, güvenli ve esnek hale getirmek için middleware kullanımı önemlidir.