Mvc Filters (Action Filter,Result Filter, Authorization Filter, Exception Filter)

Daha çok action ve controller için kullanılır. Bir kodu birden çok kere yazmak veya aynı metodları farklı yerde yazıp kullanmak yerine metotların başına attribute koyarak yada metod basına attribute yazarak bazı kurallara uyması gerektiğini belirtiyoruz.
Action Filter,Result Filter, Authorization Filter, Exception Filter türleri var bunlar Interface dir.
Kendi class ımıza  implemente ederek bu filter kodlarını yazıyoruz.

Action Filter Tipleri

Mvc asagidaki actin filter tiplerini barindirmaktadir:
Authorization Filter: Bu filter bir action metod calistirildiginda bu metod ile ilgili oturum kontrolü veya validasyon (doğrulama) kontrolü gibi güvenlikle ilgili kararlarin alinmasini sağlar. Bu filtreye örnek olarak AuthorizeAttribute sinifini örnek gösterebiliriz.

Action filter: Bu filtre tipi action metodlarin calismasiyla alakalidir. Şöyle ki action metoda disaridan data gondermek, action metodun geri donüş tipini kontrol etmek veya action metodun calismasini iptal etmek gibi ek işlevler saglayabilir.

Result filter: Bu filtre action metodun calismasiyla ortaya cikan sonucla, yani ActionResult objesi ile ilgilidir. Ortaya cikan HTTP response objesinin düzenlenmesi veya bu obje ile islemler yapilmasi gibi ek özellikler saglayabilir. Bu filtreye de en güzel örnek OutputCacheAttribute classidir. Cunku bu attribute action metoddan geri donen ActionResult nesnesini õnbelleğe alarak, benzer verilerin ramden cagrilmasini saglamaktadir.

Exception Filter: Eğer action metodumuzun herhangi bir yerinde işlenemeyen bir durum varsa yani bir hata meydana geldiyse bu action filter tetiklenir. Bu filtreyi hata mesajlarini loglamak veya hata sayfalarini göstermek icin kullanabiliriz. Yine bu filtreye de en güzel örnek HandleErrorAttribute sinifi gosterilebilir. Artik ActionFilter nesnelerinin ne ise yaradigini ve neden kullanildigini biliyoruz.

Simdi nasil kullanildigina bakalim: Action filter nesneleri tipik bir attribute classindan ibarettir. Ve FilterAttribute abstract classindan türetilerek oluşturulurlar. AuthorizeAttribute ve HandleErrorAttribute gibi action filter nesneleri direkt olarak FilterAttribute classindan türetilirler. Ve bu action filter nesneleri her zaman action metodlar calismadan önce cağirilirlar. Yani aslinda calismadan önce demekten kastimiz action metoda istek gider fakat ilk önce bu metoda atanmis olan attributelar calistirilir. Buna göre de action metoddan once yapilmasi gereken islemler varsa bunlar yapilir veya action metodun calistirilip calistirilmayacagina karar verilir.

OutputCacheAttribute gibi diğer action filtreler ise ActionFilterAttribute abstract classindan turetilmektedir. Ve bu tür filtreler action metodun calismasindan once de, calistirildiktan sonra da aktif hale gelirler. Bu aktiflikten kastim, her iki durumda da attributelar tetiklenir. Metod calismadan önce yapilacak birsey varsa bu islemler yapilir, calistiktan sonra da yine yapilacak islemler varsa yerine getirilir.
Action metodlari, hem action metod seviyesinde hem de controller seviyesinde kullanabilirsiniz. Action metoda uygulanirsa sadece o metodla ilgili islemlerde tetiklenir. Fakat controller seviyesinde uygulanirsa bu controllerdaki tüm metodlara uygulanir ve bu controller icerisindeki hangi metod cagrilirsa cagrilsin tanimlanmis olan actin filterlar uygunluk durumuna göre tetiklenir.

Action Filter

Action öncesi ve sonrasını yakalayan bir filtera ihtiyaç duyulduğunda kullanılır. Örneğin log almak istesek her metodta kod yazmamız gerekecek ve bu işlem sadece action öncesinde yapılabilir.
Bu yüzden Action Filter ile yönetimi kolaylaştırıp kodların sağlıklı olmasını sağlıyor.
Ufak bir Uygulama örneği yapalım senaryomuz siteye giren kullanıcının hangi sayfaya ne zaman girdiğinin kontrolu olsun.
Boş bir MVC projesi açıyorum ve Models  klasörü açarak kullanıcı bilgisini tutacağım  ve Log tutacağım tabloları (.cs) oluşturuyorum.  Ayrıca CodeFirst olduğu için DatabaseContext oluşturuyorum.

namespace Filters.Models
{
    [Table("Logs")]
    public class Log
    {
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        [Required, StringLength(20), DisplayName("İşlem Tarihi")]
        public string Tarih { get; set; }
        [Required, StringLength(20), DisplayName("Kullanıcı Adı")]
        public string KullaniciAdi { get; set; }
        [StringLength(100), DisplayName("Action")]
        public string ActionName { get; set; }
        [Required, StringLength(16), DisplayName("Controller"), DataType(DataType.Password)]
        public string ControllerName { get; set; }
        [StringLength(250), DisplayName("Action")]
        public string Bilgi { get; set; }

    }
}


namespace Filters.Models
{
    [Table("SiteUsers")]
    public class SiteUser
    {
        [Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        [Required,StringLength(20),DisplayName("Ad")]
        public string Ad { get; set; }
        [Required, StringLength(20), DisplayName("Soyad")]
        public string Soyad { get; set; }
        [Required, StringLength(20), DisplayName("Kullanıcı Adı")]
        public string KullaniciAdi { get; set; }
        [Required, StringLength(16), DisplayName("Şifre"),DataType(DataType.Password)]
        public string Sifre { get; set; }

    }
}


namespace Filters.Models
{
    public class DatabaseContext:DbContext
    {
        public DbSet<Log> Logs { get; set; }
        public DbSet<SiteUser> SiteUsers { get; set; }

    }
}

Filters diye bir klasör açıp ActionFilter kullanacağım attribute için cs oluşturuyorum.

namespace Filters.Filters
{
    public class ActFilter : FilterAttribute, IActionFilter
    {

        DatabaseContext db = new DatabaseContext();

        //Action çalıştıktan sonra
        public void OnActionExecuted(ActionExecutedContext filterContext)
        {

            db.Logs.Add(new Log() { KullaniciAdi = "system", ActionName = filterContext.ActionDescriptor.ActionName, ControllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, Tarih = DateTime.Now.ToShortDateString(), Bilgi = "OnActionExecuted" });
            db.SaveChanges();
        }

        //Action çalışmadan önce
        public void OnActionExecuting(ActionExecutingContext filterContext)
        {

            db.Logs.Add(new Log() { KullaniciAdi = "system", ActionName = filterContext.ActionDescriptor.ActionName, ControllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, Tarih = DateTime.Now.ToShortDateString(), Bilgi = "OnActionExecuting" });
            db.SaveChanges();
        }
    }
}

ve webConfingte  configuration altına aşağıdaki connectionString i yapıştırıyorum.
  <connectionStrings>
    <add name="DatabaseContext" providerName="System.Data.SqlClient" connectionString="Server=.;Database=ActionFilters;Integrated Security=True;"/>
  </connectionStrings>





Controller oluşturup viewları yarattıktan sonra projeyi çalıştırdığımızda hangi sayfalarda gezindiğimizi göreceksiniz.



Result Filter

View ların oluşmasından önceki ve sonrasındaki anları yakalamak için kullanılır.
Örnek olarak az önce ki senaryo üzerinden çalışacak olursak Result Filteriçin bir attribute oluşturmak bize yeterli olacaktır.
IResultFilter interface implemente edilir  OnResultExecuted  ve OnResultExecuting metotları gelir.

namespace Filters.Filters
{
    public class ResFilter : FilterAttribute, IResultFilter
    {
        DatabaseContext db = new DatabaseContext();

        public void OnResultExecuted(ResultExecutedContext filterContext)
        {
            db.Logs.Add(new Log() { KullaniciAdi = "system", ActionName = filterContext.RouteData.Values["action"].ToString(), ControllerName = filterContext.RouteData.Values["controller"].ToString(), Tarih = DateTime.Now.ToShortDateString(), Bilgi = "OnResultExecuted" });
            db.SaveChanges();
        }

        public void OnResultExecuting(ResultExecutingContext filterContext)
        {
            db.Logs.Add(new Log() { KullaniciAdi = "system", ActionName = filterContext.RouteData.Values["action"].ToString(), ControllerName = filterContext.RouteData.Values["controller"].ToString(), Tarih = DateTime.Now.ToShortDateString(), Bilgi = "OnResultExecuting" });
            db.SaveChanges();
        }
    }
}

Sadece Controller yada action da Result Filter attribute yazılır.
namespace Filters.Controllers
{
    public class HomeController : Controller
    {
        // GET: Home
        [ActFilter,ResFilter]
        public ActionResult Index()
        {
            return View();
        }
        [ActFilter, ResFilter]
        public ActionResult Index2()
        {
            return View();
        }
        [ActFilter, ResFilter]
        public ActionResult Index3()
        {
            return View();
        }

    }
}

Authorization Filter

Yetki işlemlerinde kullanılır. Şimdiki senaryomuz login yapmadan kullanıcının sayfalarda gezinmesini engellemek olsun.
IAuthorizationFilter interface implemente edilir  OnAuthorization metot gelir. (Yetki kontrolu yapacak metot)

namespace Filters.Filters
{
    public class AuthFilter : FilterAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext.HttpContext.Session["login"] == null)
            {
                // sign in sayfasına yönlendirme yap
                filterContext.Result = new RedirectResult("/Login/SignIn");
            }

        }
    }
}

Login Controller açarak sadece kullanıcı adı şifre soracak bir view ekleyerek gerekli kontrolleri sağlayalım.

public class LoginController : Controller
    {
        DatabaseContext db = new DatabaseContext();
        // GET: Login
        public ActionResult SignIn()
        {
            return View(new SiteUser());
        }
        [HttpPost]
        public ActionResult SignIn(SiteUser model)
        {
            SiteUser user = db.SiteUsers.FirstOrDefault(x=>x.KullaniciAdi==model.KullaniciAdi && x.Sifre==model.Sifre);
            if (user == null)
            {
                ModelState.AddModelError("","Hatalı Kullanıcı Adı veya Şifre");
                return View(model);
            }
            else
            {
                Session["login"] = user;

                return RedirectToAction("Index","Home");
            }

         
        }
    }


burada kullanıcı bilgilerini Sessionda tutarız.
bu arada ActionFilter ve ResultFilter için oluşturduğumuz attribute lerde kullanıcı adına default system yazmıştık buraları
(filterContext.HttpContext.Session["login"] as SiteUser).KullaniciAdi  şeklinde düzelte biliriz.







Exception Filter

Metodlarımızda, actionlarda hata olabilir hata olduğunda ilgili hata sayfasına kullanıcıyı yönlendirip hata nedenini burada belirtmek düzen açısından önemlidir. IExceptionFilter interface sinden  OnException metodunu çalıştırarak (düzenleyerek) işlem yapabiliriz.
Öncelikle ExceptionFilter için attribute oluşturalım.


namespace Filters.Filters
{
    public class ExcFilter : FilterAttribute, IExceptionFilter
    {
        public void OnException(ExceptionContext filterContext)
        {
            filterContext.ExceptionHandled = true;
            filterContext.Controller.TempData["error"] = filterContext.Exception;
            filterContext.Result = new RedirectResult("/Login/Error");
        }
    }
}
Login controllerinda
  public ActionResult Error()
        {
            if (TempData["error"] ==null)
            {
                return RedirectToAction("Index", "Home");

            }

            Exception model = TempData["error"] as Exception;

            return View(model);
        }

oluşturuyoruz  View da ise
@model Exception
@{
    ViewBag.Title = "Error";
}

<h2>Error</h2>

<div class="jumbotron">
    <h1>Bir hata oluştu</h1>
    <p>@Model.Message</p>
</div>

<hr />

<p>@Model.StackTrace</p>


oluşturup hata alacağımız sayfalarda ExcFilter yazıyoruz.

HomeController da   Index2 de hata alırsak metodumuzun çalıştığını göreceğiz.

public ActionResult Index2()
{
            int sayi = 0;
            int sayi1 = 1;
            int sayi2 = sayi1 / sayi;

            return View();
 }









Hiç yorum yok:

Yorum Gönder