İçeriğe geç

Action Filters: ASP.NET MVC’de Cross-Cutting Concern’ler

ASP.NET geliştiricileri için uygulama mantığını düzenli, sürdürülebilir ve yeniden kullanılabilir bir yapıda tutmak kritik öneme sahiptir. Bu bağlamda, “Action Filter”lar, kontrolörlerin veya eylem metodlarının yürütülmesinden önce veya sonra belirli mantıkları uygulamamızı sağlayan güçlü bir mekanizmadır. Bu filtreler, yetkilendirme, hata yönetimi, önbellekleme, günlükleme (logging) ve validasyon gibi kesişen endişeleri (cross-cutting concerns) ana iş mantığından ayırarak kodun daha temiz ve odaklanmış kalmasına yardımcı olur. Bu makalede, Action Filter’ların temel prensiplerini, ASP.NET platformunda nasıl çalıştıklarını, yaygın olarak kullanılan yerleşik (built-in) filtreleri ve kendi özel filtrelerimizi nasıl oluşturacağımızı ayrıntılı bir şekilde inceleyeceğiz. Bu sayede, uygulamalarınızda daha modüler ve yönetilebilir bir yapıya kavuşmanız için gerekli bilgi birikimini edineceksiniz.

Action filter’lar nedir ve nasıl çalışır?

Action Filter’lar, ASP.NET MVC ve ASP.NET Core uygulamalarında, belirli bir eylem metodunun (action method) çağrılmasından önce veya sonra yürütülen özel kod bloklarıdır. Bunlar aslında birer öznitelik (attribute) olup, kontrolör seviyesine veya tek tek eylem metodlarına uygulanabilirler. Temel amaçları, uygulamanın çekirdek iş mantığından ayrılması gereken kesişen endişeleri (örneğin güvenlik, günlükleme, performans izleme) yönetmektir. Bu sayede, her eylem metoduna aynı mantığı tekrar tekrar yazmak yerine, bu mantığı bir filtrede toplayıp gerekli yerlere uygulayarak kod tekrarını önler ve bakım kolaylığı sağlarlar.

Bir HTTP isteği ASP.NET çerçevesine ulaştığında, isteğin işlenmesi bir filtreleme işleminden geçer. Bu süreçte Action Filter’lar, “Action Executing” ve “Action Executed” aşamalarında devreye girer. IActionFilter arayüzü, OnActionExecuting(ActionExecutingContext context) ve OnActionExecuted(ActionExecutedContext context) olmak üzere iki ana metot tanımlar. OnActionExecuting metodu, eylem metodu çağrılmadan hemen önce çalışır ve burada isteği durdurma, model verilerini değiştirme veya yetkilendirme kontrolü gibi işlemler yapılabilir. OnActionExecuted metodu ise eylem metodu çalıştıktan ve sonuç hazırlandıktan sonra çalışır; burada sonuç üzerinde değişiklikler yapmak, hata durumlarını ele almak veya günlükleme gibi son işlemler yapılabilir. Bu arayüz sayesinde geliştiriciler, isteğin yaşam döngüsü boyunca hassas kontrol elde ederler. ASP.NET Core’da ayrıca asenkron işlemler için IAsyncActionFilter arayüzü de bulunur.

Yerleşik (built-in) action filter’lar

ASP.NET çerçevesi, geliştiricilerin sıkça ihtiyaç duyduğu belirli işlevsellikleri kolayca uygulamalarını sağlayan bir dizi yerleşik Action Filter sunar. Bu filtreler, geliştirme sürecini hızlandırır ve yaygın görevler için sağlam çözümler sunar. İşte bunlardan bazıları:

  • Authorize filter

    [Authorize] özniteliği, bir kontrolörün veya eylem metodunun yalnızca kimliği doğrulanmış ve/veya belirli rollere sahip kullanıcılar tarafından erişilmesini sağlamak için kullanılır. Bu filtre, kullanıcı isteği eylem metoduna ulaşmadan önce yetkilendirme kontrolünü yapar. Eğer kullanıcı yetkili değilse, istek ya bir oturum açma sayfasına yönlendirilir ya da bir 401 Unauthorized HTTP durum koduyla reddedilir. Örneğin, bir kontrolörün tamamına [Authorize] uygulamak, o kontrolördeki tüm eylemlerin yetkilendirme gerektirmesini sağlar. Belirli roller için [Authorize(Roles = "Admin, Editor")] şeklinde kullanılabilir.

  • HandleError filter

    [HandleError] özniteliği (özellikle ASP.NET MVC’de yaygın), bir eylem metodu veya kontrolör yürütülürken oluşabilecek işlenmemiş (unhandled) istisnaları yakalamak ve kullanıcıya dostça bir hata sayfası sunmak için kullanılır. Bu filtre, bir istisna meydana geldiğinde varsayılan olarak Error.cshtml görünümünü render eder. Hata detaylarını doğrudan kullanıcıya göstermek yerine, daha güvenli ve kullanıcı dostu bir deneyim sağlar. ASP.NET Core’da ise benzer işlevsellik genellikle UseExceptionHandler middleware’i veya özel bir IExceptionFilter implementasyonu ile sağlanır ve genellikle global olarak kaydedilir.

  • OutputCache filter

    [OutputCache] özniteliği, bir eylem metodunun ürettiği HTML çıktısını belirli bir süre boyunca önbelleğe almak için kullanılır. Bu, özellikle sık güncellenmeyen ancak çok sayıda istek alan sayfalarda sunucu yükünü azaltarak performansı önemli ölçüde artırabilir. Örneğin, [OutputCache(Duration = 60, VaryByParam = "id")] kullanımı, ilgili eylemin çıktısını 60 saniye boyunca önbelleğe alır ve id parametresine göre önbelleği çeşitlendirir. Bu sayede her yeni istekte aynı içerik tekrar tekrar üretilmek yerine önbellekten servis edilir.

Özel (custom) action filter oluşturma

ASP.NET’in yerleşik filtreleri birçok senaryoyu kapsasa da, bazen uygulamaya özgü ve daha karmaşık ihtiyaçlar için kendi özel Action Filter’larımızı oluşturmamız gerekir. Bu, kod tekrarını önlemek, cross-cutting concern’leri merkezi bir yerde yönetmek ve uygulamanın modülerliğini artırmak için güçlü bir yaklaşımdır.

Özel bir Action Filter oluşturmak için genellikle ActionFilterAttribute sınıfından türetilir veya IActionFilter (veya IAsyncActionFilter) arayüzünü doğrudan implemente edilir. ActionFilterAttribute sınıfı, IActionFilter, IResultFilter, IExceptionFilter ve IOrderedFilter arayüzlerinin temel implementasyonlarını içerdiği için çoğu durumda tercih edilen bir başlangıç noktasıdır.

Basit bir günlükleme (logging) filtresi örneği üzerinden bu süreci inceleyelim:

using Microsoft.AspNetCore.Mvc.Filters;
using System.Diagnostics;
using System;

public class LogActionFilter : ActionFilterAttribute
{
    // Eylem metodu çalışmadan hemen önce çağrılır
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        var controllerName = context.Controller.GetType().Name;
        var actionName = context.ActionDescriptor.DisplayName;
        Debug.WriteLine($"[LogActionFilter] Executing: {controllerName}.{actionName} at {DateTime.Now}");
        base.OnActionExecuting(context); // Temel sınıfın metodunu çağırın
    }

    // Eylem metodu çalıştıktan ve sonuç hazırlandıktan sonra çağrılır
    public override void OnActionExecuted(ActionExecutedContext context)
    {
        var controllerName = context.Controller.GetType().Name;
        var actionName = context.ActionDescriptor.DisplayName;
        Debug.WriteLine($"[LogActionFilter] Executed: {controllerName}.{actionName} at {DateTime.Now}");

        if (context.Exception != null)
        {
            Debug.WriteLine($"[LogActionFilter] Action {actionName} threw an exception: {context.Exception.Message}");
        }
        base.OnActionExecuted(context); // Temel sınıfın metodunu çağırın
    }
}

Bu LogActionFilter sınıfı, OnActionExecuting metodunda eylem çalışmadan önce, OnActionExecuted metodunda ise eylem çalıştıktan sonra konsola bilgi yazdırır. Ayrıca OnActionExecuted içinde bir istisna olup olmadığını kontrol ederek hata durumlarını da günlüğe kaydedebiliriz.

Bu özel filtreyi kullanmak için, onu bir kontrolöre veya belirli bir eylem metoduna öznitelik olarak eklemeniz yeterlidir:

using Microsoft.AspNetCore.Mvc;

[LogActionFilter] // Kontrolördeki tüm eylemler için uygulanır
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    [LogActionFilter] // Sadece bu eylem için uygulanır
    public IActionResult Privacy()
    {
        return View();
    }
}

Bu örnekte, LogActionFilter hem HomeController sınıfına hem de Privacy eylem metoduna uygulanmıştır. HomeController sınıfına uygulandığında, bu kontrolördeki tüm eylemler bu filtreden geçecektir. Privacy eylem metoduna özel olarak uygulandığında ise sadece bu eylem için devreye girecektir. Bu şekilde, uygulamanızdaki belirli iş akışlarını izlemek, hata ayıklama bilgilerini toplamak veya özel güvenlik kontrolleri uygulamak için kendi filtrelerinizi esnek bir şekilde tasarlayabilirsiniz.

Sonuç

Action Filter’lar, ASP.NET MVC ve ASP.NET Core geliştiricileri için vazgeçilmez bir araç seti sunar. Bu filtreler sayesinde, yetkilendirme, önbellekleme, hata yönetimi ve günlükleme gibi kesişen endişeler, uygulamanın temel iş mantığından ayrılarak daha düzenli ve sürdürülebilir bir kod yapısı elde edilir. Makalemizde incelediğimiz [Authorize], [HandleError] ve [OutputCache] gibi yerleşik filtreler, yaygın ihtiyaçlar için hızlı ve etkili çözümler sunarken, kendi özel Action Filter’larımızı oluşturma yeteneği, uygulamaya özgü karmaşık gereksinimleri esnek ve modüler bir şekilde karşılamamıza olanak tanır. Özellikle günlükleme örneğiyle gösterildiği gibi, özel filtreler kodu DRY (Don’t Repeat Yourself) prensibine uygun hale getirerek, bakım maliyetlerini düşürür ve geliştirme verimliliğini artırır. Action Filter’ları doğru bir şekilde anlamak ve uygulamak, daha güvenli, performanslı ve yönetilebilir ASP.NET uygulamaları geliştirmek için temel bir adımdır. Uygulama mimarinizde bu güçlü mekanizmayı etkin bir şekilde kullanarak, hem mevcut kod kalitenizi yükseltebilir hem de gelecekteki geliştirmeler için sağlam bir temel oluşturabilirsiniz.

Resim Sahibi: Anamul Rezwan
https://www.pexels.com/@rezwan

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir