شرح مفهوم فیلتر ها و نحوه استفاده و پیاده سازی آنها در MVC

در این مقاله توضیح میدهیم که که فیلترها در MVC چگونه کار می کنند

شرح مفهوم فیلتر ها  و نحوه استفاده و پیاده سازی آنها در MVC

شرح مفهوم فیلتر ها  و نحوه استفاده و پیاده سازی آنها در MVC

در این مقاله توضیح میدهیم که که فیلترها در MVC چگونه کار می کنند.

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

این وضعیت توسط فیلتر هادر MVC انجام میشوداین یک مفهوم بسیار خوبی معرفی شده در MVC است.

پیاده سازی که در بالا گفته شد  cross-cutting concerns نامیده میشود.

بنابراین، به عبارت ساده تر، این  منطق اضافی برای پیاده سازی به درخواست در حال پردازش اضافه می کند.

به عنوان مثال برای  cross-cutting concerns میتوان به تایید مجوز(Authorization) و Output Caching اشاره کرد.

حال در مورد انواع مختلف فیلتر و نحوه ایجاد و استفاده از آنها را بررسی کنیم:

ابتدا نگاهی به نحوه استفاده از فیلتر ها می اندازیم:

namespace WebSecurityDemoTest.Filters  
{  
    public class WebSecurityAuthorize : AuthorizeAttribute  
    {  
        protected bool AuthorizeCore(HttpContextBase httpContext)  
        {  
            if (!httpContext.Request.IsAuthenticated)  
            {  
                return false;  
            }  
            if (HttpContext.Current.Session["SessionHelper"] == null)  
            {  
                return false;  
            }  
  
            return true;  
        }  
        protected void HandleUnauthorizedRequest(AuthorizationContext filterContext)  
        {  
            filterContext.Result = new RedirectResult("/");  
            base.HandleUnauthorizedRequest(filterContext);  
        }  
  
    }  
} 

کد بالا یک نمونه از یک صفت مجوز سفارشی (CustomAuthorize) می باشد.این صفت تنها یک نوع از فیلتر است.دلیل تعریف آن در اینجا این است که یک بار تعریف شده  و میتوان به عنوان یک صفت در MVC در هرجایی استفاده کرد. در هر سطح کنترلر در هر برنامه ای که نیاز به مجوز(اجازه) اجباری باشد این نیاز بررسی میشود.

حال ببینید اگر این قالب نباشد چگونه صراحت  ما در هر سطح متد بررسی میشود:

    namespace WebDemo.Controllers  
    {  
        public class DemoController : Controller  
        {  
            //..instances or constructor if any read onlyvariables used  
            public ActionResult Index()  
            {  
                if (!Request.IsAuthenticated)  
                {  
                    FormsAuthenticationn.RedirectToLoginPage();//MVC WebSecurity  
                }  
                //else rest implementation..  
            }  
        }  
    }  

در کد بالا میبینید که صحت درخواست  در هرسطح متد بررسی میشود. در این متد قبل از اجازه دسترسی به هر کاربر ناشناس نیاز به چک کردن اجازه آن می باشد.

بنابراین برای کنترل این افزونگی میتوانید از فیلترینگ استفاده کنید فقط با استفاده از صفت Authorize یا  CustomAuthorize در بالای هر متد یا کنترلر.بنابراین می توان گفت فیلترها صفت هایی هستند که  اضافه میشوند و برای بررسی بیشتر در سطح مسیریابی  کمک میکنند.تنها در طول پردازش درخواست ها این نیاز بررسی میشود.صفت ها کلاس های مخصوصی هستند که از فضای نام  System.Attribute مشتق میشوند.

در واقع چهارنوع فیلتر در پشتیبانی فریم ورک MVC وجود دارد:

قبل از فراخوانی از هر  action method، چارچوب(framework) ابتدا به برای هر تعریف از هر صفت های فیلتر نگاه میکند، سپس به سمت action method های اجرایی حرکت میکند  که به نوبه خود  سطح اضافی امنیتی به برنامه  بدون نوشتن کد میدهد .

فیلتر Authorization

همانطور که از نام آن پیداست برای ارائه سطح دسترسی در برنامه مورد نیاز است. صفت پیش فرض  [Authorize] است. سازنده آن نیز می تواند پارامترهای مانند نقش شرایط [اجازه (نقش = "مدیریت")] قبول کند

که این صفت بسیار مفید و بسیار رایج است فیلترهای authoization همانطور که در جدول بالا مشخص است اجرا میشود ابتدا قبل از هرفیلتر و action methos.

    namespace System.Web.MVC  
    {  
        public interface IAuthorizationFilter  
        {  
            void OnAuthorization(AuthorizationContext filterCOntext);  
        }  
    }  

بهترین کار این است که ما میتوانیم صفت Authorize را سفارشی کنیم توسط گسترش کلاس  authorize و منطق خودمان را پیاده سازی کنیم .

نکته خوبی که وجود دارد این است که میتوانیم صفت Authorize  سفارشی  را به آسانی نگهداری کنیم.

صفت Authorize به صورتی ساخته شده که  می پذیرد پارامتر کاربران (users )  مثل [Authorize(Users="Iman","Sajad","Ali")] که فیلترها عمل میکند براساس سطح دسترسی کاربران و استفاده از آن نیز خیلی آسان است و ما میتوانیم برای سطح action یا سطح کنترلر استفاده کنیم فقط باید [CustomAuthorize] قبل از کلاس کنترلر یا Action Method

فیلتر اکشن (Action)

فیلتر اکشن برای هر هدفی استفاده میشود.همانطور که در جدول ذکر شد ، این فیلتر ممکن است اجرا شود قبل از اجرای عملیات اما نه اولین بار نگاهی به رابط آن می اندازیم:


    namespace System.Web.MVC  
    {  
        public interface IActionFilter  
        {  
            void OnActionExecuting(ActionExecutingContext filterContext);  
            void OnActionExecuted(ActionExecutedContext filterContext);  
        }  
    }  

همانطور که در کد بالا مشاهده میکنید رابط دارا ی دو متد میباشد همانطور که از نام متد ها میشود حدس زد اولین متد OnActionExecuting به ما میگوید که قبل از action method احضار میشود ما میتوانیم از این متد استفاده کنیم.

متد دوم میگوید که یکبار متد اجراشده باشد میتواند احضار شود.:

 

متد OnActionExecuting :

همانطور که قبلا گفته شد این متد قبل از اینکه عملی اجرا شود احضار میشود.filterContext  از نوع ActionExecutingContext که شامل پارامتر های:

1-ActionDescriptor : جزئیات یک action method  را تهیه می کند.

2-Result :نتیجه را برای action method میدهد که فیلتر میتواند درخواست را برای لغو دستکاری کند.

پیاده سازی این متد در یک صفت action filter سفارشی:


    namespace Filters.WebDemoInfra  
    {  
        public CustomActionFilter : FilterAttribute , IActionFilter   
        {  
           public void OnActionExecuting(ActionExecutingContext filterContext)  
           if(filterContext.HttpContext.Request.IsLocal)   
           {  
              filterContext.Result = new HttpNotFoundResult();  
           }  
        }  
    }  

بنابراین زمانی که ما سعی دردرک  قطعه کد بالا داریم درمیابیم که قبل از عمل اجرا شده است این متد احضار شده است .

متد OnActionExecuting نتیجه تهی بر نمیگرداند.به عبارت دیگر HttpNotFoundResult  که  کاربر خطای پیدا نشدن صفحه (404) نمیدهد حتی اگر عمل (action ) دارای یک ویو تعریف شده باشد.این قدرت این فیلتر است.

OnActionExecuted :

این متد قبلا تعریف شده است میتواند احضار شود برای یک محدوده عملیات از action method در حال پردازش بر اساس درخواست.

به مثال زیر دقت کنید:

namespace Filters.WebDemoInfra  
{  
    public class CustomActionFilter : FilterAttribute, IActionFilter  
    {  
        private StopWatch watch; //System.Diagnostics  
        public void OnActionExecuting(ActionExecutingContext filterContext)  
        {  
            timer = Stopwatch.StartNew();  
        }  
  
        public void OnAcionExecuted(ActionExecutedContext filterContext)  
        {  
            timer.Stop();  
            if (filterContext.Exception == null)  
            {  
                filterContext.HttpContext.Response.Write(string.Format("Total Tme taken: {0}", timer.Elapsed.TotalSeconds));  
            }  
        }  
    }  
}

کد قبلی یک مثال برای درک ساده تر بود. متغیر خصوصی (private) ازنوع StopWatch می باشد که یک کلاس ساخته شده در فضای نام System.Diagnostics می باشد.

در متد executing ما در حال مقداردهی اولیه زمان هستیم و بعد از اجرای action method متد executed احضار شده است.

httpContext که شامل هم درخواست و هم پاسخ می باشد ما زمان سپری شده به پاسخ (به ثانیه) اختصاص دادیم.

خواص ارائه شده توسط روش OnActionExecuted :

1- ActionDescriptor : جزئیات یک اکشن متد را تهیه میکند.

2- Cancelled : اگر  عمل توسط هر فیلتر دیگر لغو شو مقدار این خاصیت true میشود

3-Exception :اگر هر فیلتر یا عملی یک استثنا تولید کند توسط این خصوصیت برگردانده میشود

4-ExceptionHandled :اگر هر فیلتر یا عملی یک استثنا تولید کند و این اسنثنا کنترل شود مقدار این خاصیت true میشود

5-Result : نتیجه را برای action method میدهد که فیلتر میتواند درخواست را برای لغو دستکاری کند.

 

فیلتر Result :

این فیلتر کاملا شبیه به فیلتر اکشن می باشد. فیلترهایی هستند که احضار میشوند یا به کارگرفته میشوند روی نتایجی که توسط متد های ActionResult تولید میشوند.

این پیاده سازی از واسط IResultFiler ارث بری میکند که کاملا شبیه واسط IActionFilter است:


    namespace System.Web.MVC  
    {  
        public interface IResultFilter  
        {  
            void OnResultExecuting(ResultExecutingContext filterContext);  
            void OnResultExecuted(ResultExecutedContext filterContext);  
        }  
    }  

OnResultExecuting :

متد OnResultExecuting احضار میشود زمانی که یک نتیجه توسط یک Action method قبل از این که عمل به صورت کامل انجام شده باشد بازگشت داده میشود.که دارای خواص مشابه با OnActionExecuting می باشد.

OnResultExecuted :

متد OnResultExecuted احضار میشود بعد از نتیجه عمل (action) اجرا شده است .

در اینجا نیز پارامتر filterContext شامل خواص همان روش OnActionExecuted است که شرح داده شد.

demostration  مشابه زمان شرح داده شده در بخش فیلتر اکشن است.

public Abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IResultFilter  
{  
    public virtual void OnActionExecuting(ActionExecutingContext filterContext)  
    {  
    }  
    public virtual void OnActionExecuted(ActionExecutedContext filterContext)  
    {  
    }  
    public virtual void OnResultExecuting(ResultExecutingContext filterContext)  
    {  
    }  
    public virtual void OnResultExecuted(ActionExecutedContext filterContext)  
    {  
    }  
}

Using Global Filters :

ویژگی خیلی خوبی است که در برنامه های MVC پیاده سازی میشود.همانطور که میدانید Global.asax قلب برنامه های وب از نوع MVC  است.

متد Application_Start فراخوانی شده از این قسمت هر زمان که برنامه اجرا شود .

درون پوشه App_Start مان یک فایل به نام FilterConfig.cs داریم که ما میتوانیم یک متد ثابت (static) به نام

RegisterGlobalFilters پیدا کنیم در این متد ما فیلتر سفارشی مان را ثبت میکنیم که برنامه برای همه کنترلر ها و متد ها در برنامه به کار گیرد:


    namespace Filters  
    {  
        public class FilterConfig  
        {  
            public static void RegisterGlobalFilters(GLobalFilterCollection filters)  
            {  
                filters.Add(new HandleErrorAttribute());  
                filters.Add(new CustomAllAttribute());  
            }  
        }  
    }  

بنابراین فیلتر دوم برای ثبت و اضافه کردن به عنوان فیلتر عمومی  که صفت سفارشی مان است.

مثلا:


    [ProfileA(Message = "First")]  
    [ProfileB(Message = "Second")]  
    public ActionResult Index()  
    {  
        //Implementation  
    }  

ما دو فیلتر سفارشی به نام ProfileA و ProfileB که که یک پارامتر ورودی به نام Message دارد.