ActionFilterAttribute در MVC

یکشنبه 19 مهر 1394

قصد داریم یک فیلتر بنویسیم که اطلاعات مشتری ای که در حال حاضر در وب سایت لاگین نموده است را به شکل خودکار به اکشن ها تزریق نماید!

هنگام برنامه نویسی در ASP.NET MVC گاهی اوقات نیاز پیدا می کنید که در یک فیلتر بتوانید به مقادیر پارامتر های یک اکشن دسترسی پیدا نموده و یا حتی این مقادیر را تغییر دهید. برای درک بهتر قضیه، مقاله را با ذکر یک مثال ادامه می دهیم.

فرض کنید نیاز باشد در اکشن هایی از یک یا چند کنترلر، به مشخصات یک مشتری که در حال حاضر در سیستم لاگین نموده است، دسترسی داشته باشیم. در قسمت زیر نمونه ای از این اکشن ها را ملاحظه می کنید.

public ActionResult Index()
{
    var currentCustomer = new Customer();
    // ...
    //  باز یابی اطلاعات مشتری
    // ...
    //
    return View(currentCustomer );
}

در قطعه کد بالا در قسمتی که با عنوان "بازیابی اطلاعات مشتری" مشخص شده است، قطعه کدهای برنامه جهت بازیابی اطلاعات مشتری جاری نوشته می شود. این اطلاعات می توانند در یک فایل کوکی یا پایگاه داده یا حافظه سرور و یا هر جای دیگری باشند که در این مقاله این موضوع مورد علاقه ما نمی باشد. پس از اینکه اطلاعات مشتری بازیابی شد، آن را به یک View جهت نمایش ارسال نموده ایم.

بدیهی است که در بسیاری از اکشن هایی که نیاز به بازیابی اطلاعات این مشتری داریم باید مشابه قطعه کد بالا را تکرار نماییم و این موضوع چندان جالب نمی باشد و بنابراین قصد داریم یک فیلتر بنویسیم که اطلاعات مشتری ای که در حال حاضر در وب سایت لاگین نموده است را به شکل خودکار به این اکشن ها تزریق نماید!

بدین منظور، اکشن بالا را به شکل زیر تغییر می دهیم:

public ActionResult Index(Customer currentCustomer)
{
   
    return View(currentCustomer);
}

تغییری که در این اکشن انجام شده است این است که در اینجا مشتری به شکل آماده از طریق یک پارامتر برای این اکشن ارسال شده است و دیگری نیازی به بازیابی اطلاعات در داخل این اکشن نمی باشد! این تزریق را قرار است از طریق یک ActionFilterAttribute انجام دهیم.

در شکل زیر پیاده سازی فیلتر CurrentCustomerAttribute را ملاحظه می کنید.

public class CurrentCustomerAttribute:ActionFilterAttribute
{

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.ActionParameters.ContainsKey("currentCustomer"))
        {
            // ...
            // باز یابی اطلاعات مشتری 
            // ...
            // 
            var customer = new Customer
                                {
                                    CustomerID = 1,
                                    FirstName = "Morteza",
                                    LastName = "Sahragard",
                                    Website = "www.30sharp.com"
                                };

            filterContext.ActionParameters["currentCustomer"] = customer;

        }
        base.OnActionExecuting(filterContext);
    }

}

 همانطور که در بالا ملاحظه می کنید، آبجکت filterContext دارای خصوصیتی به نام  ActionParameters می باشد که از طریق آن می توانیم به پارامتر های یک اکشن دسترسی پیدا کنیم. در اینجا بررسی نموده ایم که اگر این اکشن دارای پارامتری به نام currentCustomer بود، مشتری ای که در حال حاضر در سیستم لاگین نموده است را با روش دلخواه خود بازیابی نموده و پارامتر currentCustomer را مقدار دهی نموده ایم. توجه داشته باشید که ما برای درک بهتر مثال یک نمونه از کلاس Customer به نام customer ایجاد نموده و به شکل دلخواه مقدار دهی نموده ایم ولی بدیهی است که در پروژه های واقعی باید این عمل را با اطلاعات مشتری واقعی انجام دهیم.

اکنون زمان آن فرا رسیده است که این فیلتر را به اکشن مورد نظر خود اعمال کنیم

[CurrentCustomer]
public ActionResult Index(Customer currentCustomer)
{
   
    return View(currentCustomer);

}

خوب، کار تمام است و با اعمال نمودن فیلتر  CurrentCustomer اکنون ما در داخل این اکشن به شیء currentCustomer که قبلا در داخل CurrentCustomerAttribute مقدار دهی شده است، دسترسی داریم.

برای نمایش خروجی این اکشن یک View به شکل زیر ایجاد می کنیم.

@model ActionParametersSample.Models.Customer

<p>
   <b> Customer ID:  </b>@Model.CustomerID <br/>
   <b> First Name:   </b>@Model.FirstName <br/>
   <b> Last Name:    </b>@Model.LastName <br/>
   <b> Website:      </b>@Model.Website <br/>
</p>

تاکنون آموختیم که جهت دسترسی به مشتری ای که در حال حاضر در سیستم لاگین نموده است کافیست که یک پارامتر به نام currentCustomer به اکشن ها اضافه نموده و فیلتر CurrentCustomer را اعمال کنیم. اکنون قصد داریم که به نکته جالب دیگری نیز اشاره کنیم.

همانطور که احتمالا مستحضر هستید، کنترلر ها در ASP.NET MVC اینترفیس IActionFilterرا پیاده سازی نموده اند و در حقیقت کنتلر ها نیز نوعی اکشن هستند. پس به جای اینکه فیلتر CurrentCustomer را به تک تک اکشن های یک کنترلر اضافه کنیم، می توانیم مستقیما آن را فقط به همان کنترل اعمال کنیم. این موضوع را در قسمت زیر ملاحظه می کنید.

[CurrentCustomer]
public class HomeController : Controller
{

    public ActionResult Index(Customer currentCustomer)
    {

        return View(currentCustomer);

    }

    public ActionResult Index2(Customer currentCustomer)
    {

        return View(currentCustomer);

    }

    public ActionResult Index3(Customer currentCustomer)
    {

        return View(currentCustomer);

    }

}

در قطعه کد بالا ما فیلتر CurrentCustomer را فقط به کنترلر HomeController اعمال نموده ایم و اکنون تمامی اکشن ها به آبجکت currentCustomer که با اطلاعات مشتری پر شده است، دسترسی دارند.

نکته جالبتر این است که می توانیم این فیلتر را به جای کنترلر، در فایل Global.asax و در قسمت فیلتر های عمومی رجیستر کنیم و از این پس این فیلتر به تمامی کنترلر های وب سایت به شکل خودکار اعمال می شود و دیگر نیاز به هیچ کار اضافه دیگری نیست!

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
            
    filters.Add(new CurrentCustomerAttribute());

}

در پایان این مقاله نتیجه گیری می کنیم که دسترسی به پارامتر های یک اکشن از طریق فیلتر ها، یک ویژگی بسیار جالب می باشد که در مواقعی می تواند صرفه جویی فراوانی در وقت ایجاد نموده و همچنین باعث شفاف سازی بیشتر کدها نیز شود.

siavoshi

نویسنده 4 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید