.NET Core'da Middleware Nedir ve Gerçek Dünya Kullanım Örnekleri

Middleware Nedir?

Middleware, bir web uygulamasına gelen her HTTP isteğini ve yanıtını işleyen, isteği belirli kurallara göre yönlendiren ve gerektiğinde sonlandıran "ara katmanlar"dır. Bu katmanlar isteği bir sonraki aşamaya iletir ya da işlemi burada sonlandırır. Bu yapı, web uygulamaları için oldukça önemli bir unsurdur çünkü her isteği modüler bir şekilde işleyip yönetmemize olanak tanır.

Bir örnekle düşünelim: Bir e-ticaret sitesinde kullanıcı "Sipariş Ver" butonuna tıkladığında, bu istek çeşitli aşamalardan geçer:

  1. Güvenlik Kontrolü: Kullanıcı giriş yapmış mı?
  2. Doğrulama: Girilen bilgiler doğru mu?
  3. Loglama: Sipariş kaydedildi mi?

Bu işlemleri gerçekleştiren her bir adım bir middleware’dir.

.NET Core'da Middleware Nasıl Yazılır?

.NET Core’da middleware katmanları "pipeline" adını verdiğimiz bir yapıda sıralanır. Gelen istek sırayla bu katmanlardan geçer ve her middleware kendine ait işlemi gerçekleştirir. .NET Core, çeşitli hazır middleware bileşenleri sunar, ancak bazen ihtiyaca göre özel middleware yazmanız gerekebilir.

Şimdi, gerçek dünyada kullanılan middleware örneklerine bakalım ve her bir kullanım için bir kod örneği görelim.

1. Güvenlik Kontrolleri (Authentication/Authorization Middleware)

Bu middleware, kullanıcının yetkili olup olmadığını kontrol eder. Örneğin, yalnızca giriş yapmış kullanıcıların belirli sayfalara erişmesini sağlayabilirsiniz. Admin paneline yalnızca "admin" rolüne sahip kullanıcılar girebilsin istiyorsanız, bu middleware işinizi görecektir.

Kod Örneği:

public class AdminAuthorizationMiddleware
{
    private readonly RequestDelegate _next;

    public AdminAuthorizationMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // Kullanıcının giriş yapıp yapmadığını ve admin rolünde olup olmadığını kontrol et
        if (!context.User.Identity.IsAuthenticated || !context.User.IsInRole("Admin"))
        {
            context.Response.StatusCode = 403;
            await context.Response.WriteAsync("Admin paneline erişim izniniz yok.");
            return;
        }

        // Yetkili ise bir sonraki middleware'e devam et
        await _next(context);
    }
}

// Startup.cs'de middleware'i kullanmak için:
public void Configure(IApplicationBuilder app)
{
    app.UseMiddleware<AdminAuthorizationMiddleware>();
    app.UseRouting();
    app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}

Bu middleware, kullanıcının "Admin" rolünde olup olmadığını kontrol eder ve eğer yetkisizse "403 Forbidden" hatası verir.

2. Veri Doğrulama (Validation Middleware)

Veri doğrulama middleware'i, kullanıcının gönderdiği verilerin geçerli olup olmadığını kontrol eder. Örneğin, bir formun gerekli alanlarının doldurulup doldurulmadığını ya da sipariş formundaki ürün miktarının sıfırdan büyük olup olmadığını kontrol edebilir.

Kod Örneği:

public class FormValidationMiddleware
{
    private readonly RequestDelegate _next;

    public FormValidationMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // Sadece POST isteklerinde form doğrulama yap
        if (context.Request.Method == "POST")
        {
            context.Request.EnableBuffering();
            var body = await new StreamReader(context.Request.Body).ReadToEndAsync();

            // Form verilerinin boş olup olmadığını kontrol et
            if (string.IsNullOrWhiteSpace(body))
            {
                context.Response.StatusCode = 400;
                await context.Response.WriteAsync("Form verileri boş olamaz.");
                return;
            }

            context.Request.Body.Position = 0;
        }

        await _next(context);
    }
}

// Startup.cs'de middleware'i kullanmak için:
public void Configure(IApplicationBuilder app)
{
    app.UseMiddleware<FormValidationMiddleware>();
    app.UseRouting();
    app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}

Bu middleware, gelen form verilerini kontrol eder ve boş form gönderilmişse "400 Bad Request" hatası döndürür.

3. Hata Yönetimi (Error Handling Middleware)

Hata yönetimi middleware'i, uygulama içerisinde oluşan hataları yakalar ve kullanıcıya anlamlı bir hata mesajı gösterir. Özellikle büyük web uygulamalarında global bir hata yönetim mekanizması son derece faydalıdır.

Kod Örneği:

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

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

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Bir hata meydana geldi.");
            context.Response.StatusCode = 500;
            await context.Response.WriteAsync("Bir sorun oluştu, lütfen daha sonra tekrar deneyin.");
        }
    }
}

// Startup.cs'de middleware'i kullanmak için:
public void Configure(IApplicationBuilder app)
{
    app.UseMiddleware<GlobalExceptionMiddleware>();
    app.UseRouting();
    app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}

Bu middleware, uygulamada oluşan hataları yakalar ve kullanıcıya "500 Internal Server Error" mesajı gösterir. Aynı zamanda hataları loglar.

4. Caching (Önbellekleme Middleware)

Önbellekleme middleware'i, sık yapılan istekleri önbellekte tutar ve aynı istek tekrar geldiğinde sunucuya gitmeden hızlıca yanıt verir. Özellikle statik içeriklerde (resimler, dosyalar) kullanışlıdır.

Kod Örneği:

public class SimpleCacheMiddleware
{
    private readonly RequestDelegate _next;
    private static readonly Dictionary<string, string> _cache = new();

    public SimpleCacheMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var cacheKey = $"{context.Request.Method}_{context.Request.Path}";

        if (_cache.ContainsKey(cacheKey))
        {
            // Eğer cache'de varsa yanıtı cache'den al ve döndür
            await context.Response.WriteAsync(_cache[cacheKey]);
            return;
        }

        // Cache'de yoksa işlemi devam ettir ve cache'e kaydet
        var originalResponseBody = context.Response.Body;
        using (var newResponseBody = new MemoryStream())
        {
            context.Response.Body = newResponseBody;

            await _next(context);

            context.Response.Body = originalResponseBody;
            newResponseBody.Seek(0, SeekOrigin.Begin);
            var responseText = await new StreamReader(newResponseBody).ReadToEndAsync();

            _cache[cacheKey] = responseText;
            await context.Response.WriteAsync(responseText);
        }
    }
}

// Startup.cs'de middleware'i kullanmak için:
public void Configure(IApplicationBuilder app)
{
    app.UseMiddleware<SimpleCacheMiddleware>();
    app.UseRouting();
    app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}

Bu middleware, HTTP isteklerini önbelleğe alır ve aynı istek tekrar geldiğinde, sunucuyu yormadan önbellekten yanıt döndürür.

Sonuç

.NET Core'da middleware, web uygulamaları için oldukça güçlü bir araçtır. Yukarıda verdiğimiz örnekler, middleware’in gerçek dünyada nasıl kullanıldığını göstermektedir. Bu örnekler, güvenlikten hata yönetimine, önbelleklemeden statik dosya sunumuna kadar birçok alanda middleware'in nasıl işlevsel olduğunu ortaya koyuyor.

Middleware kullanarak uygulamanızı daha modüler, daha performanslı ve daha güvenli hale getirebilirsiniz. Her bir middleware’in görevini iyi tanımlayıp doğru sırada çalışmasını sağladığınızda, uygulamanız daha esnek ve kolay yönetilebilir olacaktır.