Filtre yapısı bize action metodunun öncesi veya sonrasında yani request-response sürecine belirli noktalarda girerek istenilen kod bloklarını çalıştırmamızı sağlar. Ayrıca ASP.NET Core MVC yapısı içerisinde birçok dahili filtre de bulunmaktadır. Bunlarla birlikte kendi özel filtrelerimizi de oluşturabiliriz.
Filtre Tipleri :
- Yetkilendirme Filtreleri (Authorization Filters) : Yetkilendirme filtreleri ilk çalışan filtredir. Bu filtre bize kullanıcının istenilen request için yetkili olup olmadığının karar verilmesinde yardımcı olur. Eğer yetkisi yoksa bu pipeline atlanarak devam edilir. Ayrıca kendi istediğimiz özel yetkilendirme filtreleri de oluşturabiliriz.
- Kaynak Filtreleri (Resource Filters) : Bu filtre yetkilendirme filtrelerinden sonra çalışır. Geriye kalan filtreler çalışmadan önce ve sonra bu filtreler ile kod blokları çalıştırılabilir. Ayrıca bu filtreler short-circuit(kısa devre) sağlamak için de kullanılabilir. Caching işlemi için de bu filtreler kullanılabilir.
- Action Filtreleri : Bu filtreler controller action metot çağırılmadan önce ve sonrasında istenilen kod bloklarını çalıştırmak için kullanılır. Ayrıca bu action metoda gelen verileri istediğimiz şekilde değiştirebiliriz.
- Olağandışı durum filtreleri (Exception Filters) : Bu filtreler response body kısmına herhangi birşey yazılmadan önce oluşan özel durumlar için kullanılır.
- Sonuç Filtreleri (Result Filters) : Sonuç filtreleri action metotların çalıştırılmasından önce veya sonra istenilen kodların yazılması için kullanılır. Yalnız bu kod bloğu yalnızca action metot başarılı bir şekilde çalışırsa bununla beraber çalışacaktır.

Filtreler senkron ve asenkron uygulamayı destekler. Tabii bunun için ikisi için de farklı arayüzler kullanılır.
Senkron Filtre (Synchronous Filter)
Senkron filtreler pipeline stage (Yukarıda tanımladığımız filtre tipleri) durumuna göre OnStageExecuting ve OnStageExecuted olarak metotları kullanır. Action Filtre üzerinden devam edelim ve örneklendirelim.
public class CustomFilter1 : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
//Action metodu çalışmadan önce
}
public void OnActionExecuting(ActionExecutingContext context)
{
//Action metodu çalıştıktan sonra
}
}
Asenkron Filtre (Asynchronous Filter) :
Asenkron filtreler yalnızca OnStageExecutionAsync metodu ile tanımlanır. Bu metot parametre olarak FilterTypeExecutingContext ve FilterTypeExecutionDelegate alır.
ActionFilter üzerinden bir örnek ile devam edelim. Bu örnekte metodumuza gelen id parametresine karşılık olarak veritabanında böyle bir kategori var mı yok mu kontrolünü sağlayalım ve sonuca göre hata sayfasına yönlendirelim veya işlemlere devam edelim.

public class NotFoundFilter:ActionFilterAttribute
{
private readonly CategoryApiService _categoryApiService;
public NotFoundFilter(CategoryApiService categoryService)
{
_categoryApiService = categoryService;
}
public async override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
int id = (int)context.ActionArguments.Values.FirstOrDefault();
var category = await _categoryApiService.GetByIdAsync(id);
if (category != null)
{
await next();
}
else
{
ErrorDTO errorDTO = new ErrorDTO();
errorDTO.Errors.Add($"ID = {id} category cannot be found in the database");
context.Result = new RedirectToActionResult("Error", "Home",errorDTO);
}
}
}
Yukarıdaki metot çalıştığında aşağıdaki gibi bir görüntü elde edebiliriz. Burada ActionExecutingContext ile istek yolladığım metot ile ilgili bilgilere ve HttpContext ile birlikte de yolladığımız istekle ilgili bilgilere erişebiliriz. Ayrıca görüldüğü üzere farklı bilgilere de erişebiliriz.
ActionExecutionDelegate ile varsa bir sonraki filtreye veya aşamaya geçilir.


Şimdi ise filtreleri ekleme kısmına geçelim;
Filtreler 3 ayrı scope üzerinden eklenebilir.
- Action Method
- Controller Class
- Globally (Tüm Action ve Controller için)
Bunları karşılaştıracak olursak;
Mesela global alanda bir filtre tanımladık. Daha sonra ise Controller ve Action için ayrı ayrı farklı filtreler tanımladık. Burada sıralama şu şekilde olur.
İlk olarak Global filtre uygulanır, daha sonra Controller için olan filtre ve ondan sonra ise son olarak Action metot için olan filtre uygulanır. Aşağıda da bunu görebiliriz.

İlk olarak projemize bir filtreyi eklemeyi görelim.
public void ConfigureServices(IServiceCollection services)
{
// Framework Service ekleme
services.AddMvc(options=> {
//Örnek ile ekleme
options.Filters.Add(new CustomActionFilter());
//Tipi ile ekleme
options.Filters.Add(typeof(CustomActionFilter));
});
}
veya direkt olarak IoC container üzerinden de ekleme yapabiliriz.
services.AddScoped<NotFoundFilter>();
Filtrelemede Order Kullanımı :
IOrderedFilter arayüzü ile filtre uygulama gidiş sırasını değiştirebiliriz. Order parametresi ile uygulama düzenini belirtebiliriz. Düşük değerli Order, yüksek değerliden daha önce çalıştırılır.
public class OrnekFilterAttribute : Attribute, IActionFilter, IOrderedFilter
{
public int Order { get; set; }
public void OnActionExecuting(ActionExecutingContext context)
{
//Action çalışmadan önce
}
public void OnActionExecuted(ActionExecutedContext context)
{
//Action çalıştıktan sonra
}
}
[OrnekFilter(Order = 1)]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
Pipeline içerisinde filtreler çalıştığında, filtreler ilk olarak Order’a göre sıralanır daha sonra Scope’a göre sıralanır. Tüm built-in filtreler IOrderFilter ile implemente edilir ve default Order değeri 0 olarak alınır.
Filtreleri İptal Etme veya Atlama
Filtre Pipeline için istenilen bir noktada atlama yapılabilir. Bunu Context’in Result özelliğini kullanarak yapabiliriz.
public class OrnekFilterAttribute : Attribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
//Action çalışmadan önce
context.Result = new ContentResult()
{
Content = "Atlama filtresi"
};
}
public void OnActionExecuted(ActionExecutedContext context)
{
//Action çalıştıktan sonra
}
}
Dependency Injection ve Filtreler
Yukarıda da gördüğümüz gibi filtreler tipi ile veya oluşturulan bir örneği ile eklenebiliyordu. Eğer bir örneği ile filtreyi eklersek bu örnek tüm istekler için kullanılacaktır. Eğer ki tipi ile eklersek bu tipin örneği her istekte oluşturulacaktır.
Attribute olarak eklenen ve direkt olarak controller veya action metotlara eklenen filtreler Dependency Injection tarafından sağlanan Constructor(Yapıcı metot) bağımlılıklarına sahip olamaz. Bu durumda, parametreye ihtiyaç duyulacaktır. Bu bizim için büyük bir problemdir.
Bunun önüne geçmek için aşağıdaki Attribute yapıları kullanılabilir.
- ServiceFilterAttribute
- TypeFilterAttribute
- IFilterFactory (attribute tarafından implement edilir)
ServiceFilterAttribute
ServiceFilter Dependency Injection’dan filtrenin bir örneğini alır. Bu filtreyi ConfigureService içerisinde bulunan container yapısına eklenir. Daha sonra controller veya action metot içerisinde bulunan ServiceFilter attribute içerisinde bu değer kullanılır.
Dependency Injection’dan almaya ihtiyaç duyduğumuz bağımlılıklardan biri de Logger yapısıdır. Filtre içerisinde, gerçekleşen bazı şeyleri loglayabiliriz.
public class OrnekFilterWithDI : IActionFilter
{
private ILogger _logger;
public OrnekFilterWithDI(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<OrnekFilterWithDI>();
}
public void OnActionExecuting(ActionExecutingContext context)
{
//Action çalışmadan önce
_logger.LogInformation("OnActionExecuting");
}
public void OnActionExecuted(ActionExecutedContext context)
{
//Action çalıştıktan sonra
_logger.LogInformation("OnActionExecuted");
}
}
ConfigureService içerisinde container içerisine filtreyi ekliyoruz.
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<OrnekFilterWithDI>();
}
Action metot içerisinde filtreyi kullanalım,
[ServiceFilter(typeof(OrnekFilterWithDI))]
public IActionResult Index()
{
return View();
}
ServiceFilter, IFilterFactory arayüzünü implemente eder. Bu arayüz ile de CreateInstance metodu gelir. Bu metot services container içerisinden gerekli olan tipi yükler.
TypeFilterAttribute
Bu kullanım türü de ServiceFilterAttribute ile çok benzerdir. TypeFilter yapısı da IFilterFactory arayüzünden implemente edilir. Bu kullanım şeklinde farklı olarak Dependency Injection Container içerisinden örneği almaz ve bunun yerine “Microsoft.Extensions.DependencyInjection.ObjectFactory” sınıfını kullanarak gereken tipin örneğini oluşturur.
Farklılıktan dolayı, TypeFilterAttribute içerisinde belirtilecek olan filtre ilk olarak ConfigureService içerisinde container içerisine eklenmelidir. TypeFilterAttribute yapıcı metot(constructor) için değişkenleri kabul edebilir.
[TypeFilter(typeof(OrnekFilterAttribute), Arguments = new object[] {"Herhangi bir değişken"})]
public IActionResult Index()
{
return View();
}