کارکردن با فیلترها در ASP.NET Core MVC

در این مقاله قصد داریم تا با نحوه کار کردن فیلتر ها در ASP.NET Core MVC و مسائل مربوط به سفارشی کردن آن بپردازیم.با ما همراه باشید.

کارکردن با فیلترها در ASP.NET Core MVC

فیلترها به ما اجازه میدهند تا قبل و بعد از اجرای اکشن متدها ، یک کد سفارشی را اجرا کنیم.آنها راه هایی برای انجام وظایف تکراری و مشترک در اکشن متدها به ما ارائه میدهند.فیلترها در مراحل خاصی در پردازش درخواست pipeline فراخوانی می شوند.

فیلترهای ساخته شده بسیاری برای Asp.net Core  وجود دارد و همچنین میتوانیم فیلترهای سفارشی ایجاد کنیم.فیلتر ها به ما کمک میکنند تا کدهای تکراری را از برنامه حذف کنیم.

انواع فیلتر ها

هر کدام از فیلترها در یک مرحله (stage ) متفاوت از filter pipeline اجرا می شود. در زیر انواع فیلترها بیان شده است:

فیلتر احراز هویت(Authorization filters):

این فیلتر در ابتدای همه اجرا میشود.این فیلتر به ما کمک میکند تا تعیین کنیم که آیا این کاربر برای درخواست فعلی مجاز است یا خیر.اگر یک کاربر برای درخواست فعلی غیرمجاز باشد، این فیلتر می تواند جریان pipeline را کوتاه کند.ما همچنین میتوانیم فیلتر authorization  را سفارشی کنیم.

Resource filters:

این فیلتر درخواست را پس از احراز هویت کنترل میکند و می تواند قبل و بعد از اجرای بقیه فیلتر ها اجرا شود.این فیلتر پیش از model binding اجرا میشود.از این فیلتر میتوان برای پیاده سازی caching استفاده کرد.

Action filters:

فیلتر Action کدها را بلافاصله قبل و بعد از فراخوانی اکشن متد کنترلر ها اجرا میکند.از این فیلتر میتوان برای اجرا کردن هر اکشنی قبل و بعد از اجرا اکشن متد کنترلر ها استفاده کرد.همچنین میتوانیم ارگومان های ارسال به اکشن را نیز اداره کنیم.

Exception filters:

فیلتر های استثنا برای کنترل کردن استثناهایی است که پیش از هر چیزی که در بدنه پاسخ نوشته شده است رخ میدهد ، مورد استفاده قرار میگیرد.

Result filters:

این فیلتر برای اجرا کد قبل و بعد از اجرا شدن action results های کنترلر ها مورد استفاده قرار میگیرد.این ها تنها زمانیکه اکشن متد کنترلر با موفقیت اجرا میشود ، اجرا میشوند.

نمودار زیر نحوه عمل کردن این فیلتر ها در فیلتر pipeline در طی یک درخواست و پاسخ در چرخه حیات را نشان میدهد:

فیلتر دو نوع پیاده سازی را پشتیبانی میکند :

همزمان (synchronous )  و غیر همزمان(asynchronous)

هر دو با استفاده از تعاریف متفاوت اینترفیس پیاده سازی میشوند.

فیلتر همزمان کد ها را قبل و بعد از مرحله تعریف شده pipeline با تعریف OnStageExecuting  و OnStageExecuted اجرا میکند.

به عنوان مثال :ActionFilter

متد OnActionExecuting قبل از اکشن متد فراخوانی میشود و متد OnActionExecuted بعد از اکشن متد فراخوانی میشود.

ExampleFilter.cs

using System;  
using Microsoft.AspNetCore.Mvc.Filters;  
namespace Filters  
{  
    public class ExampleFilterAttribute : Attribute, IActionFilter, IOrderedFilter  
    {  
        public int Order { get; set; }  
          
        public void OnActionExecuting(ActionExecutingContext context)  
        {  
            //To do : before the action executes  
        }  
  
        public void OnActionExecuted(ActionExecutedContext context)  
        {  
            //To do : after the action executes  
        }  
    }  
}  

Controller.cs

using System;  
using Microsoft.AspNetCore.Mvc;  
using Filters;  
  
namespace Filters.Controllers  
{  
    [ExampleFilter(Order = 1)]  
    public class HomeController : Controller  
    {  
        public IActionResult Index()  
        {  
            return View();  
        }  
    }  
} 

زمانیکه فیلترها در pipeline اجرا میشوند ، فیلتر ها به ترتیب اولویت و سپس محدوده (scope) مرتب می شوند.

تمام فیلترهای ساخته شده اینترفیس IOrderFilter را پیاده سازی کرده اند  و مقدار اولویت پیش فرض فیلتر 0 تنظیم می شود.

لغو کردن با فیلترهای کوتاه مدت

ما می توانیم با تنظیم یک مشخصه "Result" که یکی از پارامترهای "Context"  است که به متدهای فیلتر متصل شده است، pipeline  فیلتر را در هر لحظه از زمان کوتاه کنیم.

Filter Example

using System;  
using Microsoft.AspNetCore.Mvc;  
using Microsoft.AspNetCore.Mvc.Filters;  
namespace Filters  
{  
    public class Example1FilterAttribute : Attribute, IActionFilter  
    {  
        public void OnActionExecuting(ActionExecutingContext context)  
        {  
            //To do : before the action executes  
            context.Result = new ContentResult()  
            {  
                Content = "Short circuit filter"  
            };  
        }  
        public void OnActionExecuted(ActionExecutedContext context)  
        {  
            //To do : after the action executes  
        }  
    }  
}  

فیلترها و DI (تزریق وابستگی)
همانطور که یاد گرفتیم، فیلتر را می توان با نوع یا توسط نمونه اضافه کرد. اگر ما فیلتر را به صورت نمونه اضافه کنیم، این نمونه برای هر درخواست استفاده می شود و اگر فیلتر را به عنوان یک نوع اضافه کنیم، نمونه برای هر درخواست ایجاد خواهد شد. فیلتر دارای وابستگی سازنده (constructor dependencies) است که توسط DI ارائه می شود.

فیلترهایی که به صورت صفات پیاده سازی می شوند و مستقیما به کنترلر ها یا اکشن متدها اضافه می شوند، نمی توانند وابستگی سازنده را توسط DI فراهم سازند. در این مورد، پارامتر پیمانکار (contractor ) را باید هنگام فراخوانی پاس داده بدهیم.

این محدودیت ویژگی ها است. راه های زیادی برای غلبه بر این محدودیت وجود دارد. ما می توانیم فیلتر ها را به کلاس کنترلر یا اکشن متد با استفاده از یکی از موارد زیر اعمال کنیم:

ServiceFilterAttribute

TypeFilterAttribute

IFilterFactory implemented on attribute

ServiceFilterAttribute

ServiceFilter یک نمونه از فیلتر را از تزریق وابستگی (DI) بازیابی می کند. ما باید این فیلتر را به یک ظرف (container ) در ConfigureService اضافه کنیم و آن را در ویژگی ServiceFilter در کلاس کنترلر یا اکشن متد رفرنس دهیم.

یکی از وابستگی هایی که ما ممکن است نیاز به دریافت آن از DI داشته باشیم ، یک logger است. در داخل فیلتر ، ممکن است ما نیاز به ثبت چیزی که اتفاق افتاده است داشته باشیم. مثلا یک اکشن فیلتر با وابستگی logger.

using Microsoft.AspNetCore.Mvc.Filters;  
using Microsoft.Extensions.Logging;  
namespace FiltersSample.Filters  
{  
    public class ExampleFilterWithDI : IActionFilter  
    {  
        private ILogger _logger;  
        public ExampleFilterWithDI(ILoggerFactory loggerFactory)  
        {  
            _logger = loggerFactory.CreateLogger<ExampleFilterWithDI>();  
        }  
        public void OnActionExecuting(ActionExecutingContext context)  
        {  
            //To do : before the action executes  
            _logger.LogInformation("OnActionExecuting");  
        }  
        public void OnActionExecuted(ActionExecutedContext context)  
        {  
            //To do : after the action executes  
            _logger.LogInformation("OnActionExecuted");  
        }  
    }  
} 

فیلتر را در متد ConfigureService ثبت کنید.

public void ConfigureServices(IServiceCollection services)  
{  
    services.AddScoped<ExampleFilterWithDI>();  
}  

از فیلتر در اکشن متد کلاس کنترلر استفاده کنید

[ServiceFilter(typeof(ExampleFilterWithDI))]  
public IActionResult Index()  
{  
    return View();  
} 

اگر ما نوع فیلتر را در متد ConfigureService ثبت نکنیم، سیستم یک استثناء صادر می کند - "InvalidOperationException".

ServiceFilterAttribute  در حقیقت IFilterFactory  را پیاده سازی میکند که یک متد برای ایجاد نمونه ای از IFilter را نمایش میدهد.متد CreateInstance برای بارگذاری نوع خاصی از DI  از services container استفاده میکند.

TypeFilterAttribute

این بسیار شبیه ServiceFilterAttribute  است و همچنین ایترفیس IFilterFactory را پیاده سازی کرده است.

در اینجا ، نوع به طور مستقیم از طریق DI container تامین نشده است، اما نوع ها با استفاده از کلاس "Microsoft.Extensions.DependencyInjection.ObjectFactory" نمونه سازی میشوند.

با توجه به این تفاوت ، انواعی که به TypeFilterAttribute  رفرنس داده شده اند نیاز دارند تا در ابتدا در متد ConfigureService  ثبت شوند.

TypeFilterAttribute میتواند به صورت اختیاری ارگومان های سازنده برای نوع را قبول کند.مثال زیر نشان می دهد که چگونه با استفاده از TypeFilterAttribute یک آرگومان را به یک نوع پاس دهید.

[TypeFilter(typeof(ExampleFilterAttribute), Arguments = new object[] {"Argument if any" })]  
public IActionResult About()  
{  
    return View();  
}

آموزش asp.net mvc