ويژگی Action Method Selector در ASP.NET MVC
شناسه پست: 1056
بازدید: 1481

چکیده: با استفاده از ویژگی Action method selector در ASP.NET MVC می توانید اکشن متد خاصی را با توجه به نیازهای بیزینستان اجرا و یا رد نمایید.

ما می توانیم به راحتی فیلترهای سفارشی برای authentication ، ثبت رویداد ها و خطاها و غیره پیاده سازی نماییم. در نتیجه می توانیم کنترلرها و Viewهای سفارشی برای توسعه آبجکت مدلها در application مان پیاده سازی نماییم.

پردازش request در MVC از Controller شروع می شود. این آبجکت مسئول نگه داری اکشن متدهای متفاوتی است که اکشنی که باید اجرا شود درون request توسط http مشخص می شود. فرایند request در MVC  با استفاده از IActionInvoker که درون خود دارد تعیین می کند که کدام اکشن متد باید فراخوانده شده و اجرا شود. نمودار زیر نشان می دهد که چطور کنترلر، اکشن متد مورد نظر را بر اساس attribute فرامی خواند.

پردازش اکشن متد

کنترلر در MVC میتواند چند متد با یک نام داشته باشد. این اکشن متدها در MVC با Attribute های HttpGet و HttpPost در بالای خود تعریف می شوند. این Attribute ها تعیین می کنند که request ارسال شده بر اساس GET و یا POST بودنش کدام یک از اکشن متدها باید اجرا گردد. نمودار زیر رفتار Action Invoker را برا یانتخاب اکشن متد در MVC Controller نشان می دهد.

action execution invocation

نمودار بالا نحوه انتخاب و اجرا شدن اکشن متد را نشان می دهد. از آنجایی که ما میدانیم Route در MVC شامل نام کنترلر و متد است، سپس اکشن مورد نظر بر اساس نام اکشن با استفاده از ویژگی Action Name Selector که درون خود Mvc وجود دارد فراخوانده می شود.

اما اگر کنترلر دارای اکشن متدها با یک نام یکسان است (در مثال ما متد create) که در اکثر موارد اتفاق می افتد سپس ویژگی توکار ActionMethod selector وارد فرایند می شود و اکشن مورد نظر را بر اساس نوع http request که در دو حالت Get و یا Post است فرا می خواند. این اطلاعات که request از چه نوعی است درون Http Request header قرا می گیرد. که در این حالت MVC از کلاس ActionMethodSelectorAttribute برای فراخوانی متد مورد نظر جهت اجرا استفاده می نماید.

حال ما میتوانیم یک Action Method Selector سفارشی ایجاد نماییم و کنترلر در MVC را مجبور نماییم که یک اکشن متد ویژه را بر اساس مقداری که در Http header درون request پاس داده می شود را فراخوانی نماید. به این منظور ما در این مقاله قصد داریم که طی یک مثال به شما نشان دهیم که چطور با استفاده از این ویژگی میخواهیم محصولاتی را در یک دسته بندی خاص که نام دسته درون http Header در request قرار گرفته می شود را برگردانیم. و این ویژگی را شما برای هرنوع موردی که در پروژه خود دارید می توانید به کار گیرید.

پیاده سازی Action Method Selector

مرحله 1: ویژوال استودیو را باز نمایید و یک پروژه جدید با نام MVC_CustomActionMethodSelector  از نوع ASP.NET Web Application را مانند شکل زیر ایجاد نمایید:

create aspnet mvc project

بر روی ok کلیک نمایید سپس در پنجره بعدی template را از نوع empty انتخاب نمایید:

mvc project

مرحله 2: در فولدر مدلها یک فایل کلاس به نام ModelClasses.cs ایجاد نمایید و کدهای زیر را درون آن قرار دهید:

using System.Collections.Generic;
 
namespace MVC_CustomActionMethodSelector.Models
{
    public class Product
    {
        public int ProductId { get; set; }
        public string ProductName { get; set; }
        public int Price { get; set; }
        public string Category { get; set; }
    }
 
    public class ElectronicsProductsDatabase : List<Product>
    {
        public ElectronicsProductsDatabase()
        {
            Add(new Product() { ProductId = 1, ProductName = "Desktop", Price = 34000, Category = "Electronics" });
            Add(new Product() { ProductId = 2, ProductName = "Laptop",  Price = 34000, Category = "Electronics" });
            Add(new Product() { ProductId = 3, ProductName = "Router",  Price = 34000, Category = "Electronics" });
            Add(new Product() { ProductId = 4, ProductName = "Mouse",   Price = 34000, Category = "Electronics" });
            Add(new Product() { ProductId = 5, ProductName = "USB HDD", Price = 34000, Category = "Electronics" });
            Add(new Product() { ProductId = 6, ProductName = "LCD",     Price = 34000, Category = "Electronics" });
        }
    }
 
    public class DataAccessElectronics
    {
        public List<Product> GetDataElectronics()
        {
            return new ElectronicsProductsDatabase();
        }
    }
 
    public class MechanicalProductsDatabase : List<Product>
    {
        public MechanicalProductsDatabase()
        {
            Add(new Product() { ProductId = 1, ProductName = "JCB", Price = 314000, Category = "Mechanical" });
            Add(new Product() { ProductId = 2, ProductName = "Tractor", Price = 134000, Category = "Mechanical" });
            Add(new Product() { ProductId = 3, ProductName = "Leath Machine", Price = 74000, Category = "Mechanical" });
            Add(new Product() { ProductId = 4, ProductName = "Crusher", Price = 104000, Category = "Mechanical" });
            Add(new Product() { ProductId = 5, ProductName = "Mixer", Price = 143000, Category = "Mechanical" });
        }
    }
 
    public class DataAccessMechanical
    {
        public List<Product> GetDataMechanical()
        {
            return new MechanicalProductsDatabase();
        }
    }
}

 

کد بالا شامل کلاسهای زیر می باشد:

  • Product  – این یک کلاس موجودیت شامل اطلاعات محصولات می باشد.
  • ElectronicsProductsDatabase  – این کلاس از کلاس List<Product> مشتق شده می باشد و شامل داده های پیش فرض برا ی محصولات الکترونیکی می باشد.
  • DataAccessElectronics  – این کلاس شامل متد برای برگرداندن تمام محصولات الکترونیکی می باشد.
  • MechanicalProductsDatabase  – این کلاس شامل داده های پیش فرض برا ی محصولات مکانیکی می باشد.
  • DataAccessMechanical  – این کلاس شامل متد برای برگرداندن تمام محصولات مکانیکی می باشد.

توجه: در یک پروژه واقعی، شما می توانید از Entity framework برای map کردن داده ها به دیتابیس استفاده نمایید.

مرحله 3: در پروژه یک فولدر به نام CustomActionMethodSelector ایجاد نمایید. در این فولدر یک فایل کلاس جدید به نام MyActionMethodSelector ایجاد نمایید و کدهای زیر را درون آن قرار دهید:

using System.Reflection;
using System.Web.Mvc;
 
namespace MVC_CustomActionMethodSelector.CustomActioMethodSelector
{
    public class ElectronicsActionMethodSelectorAttribute : ActionMethodSelectorAttribute
    {
        public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
        {
            return controllerContext.HttpContext.Request.Headers["P-Electronics"] != null;
        }
    }
 
    public class MechanicalActionMethodSelectorAttribute : ActionMethodSelectorAttribute
    {
        public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
        {
            return controllerContext.HttpContext.Request.Headers["P-Mechanical"] != null;
        }
    }
}


کد بالا شامل کلاسهای زیر می باشد:

ElectronicsActionMethodSelectorAttribute

  • این کلاس از کلاس ActionMethodSelectorAttribute  مشتق شده است.
  • این کلاس متد IsValidateForRequest را override می کند. این متد، آبجکت ControllerContext  و MethodInfo  را به عنوان ورودی می گیرد. ControllerContext  حاوی context کنترلر بارگزاری شده در request فرستاده شده برای اجرای اکشن مورد نظر می باشد.
  • این متد بررسی می کند که آیا request header ارسالی شامل عبارت P-Electronics: true می باشد یا خیر. اگر جواب مثبت باشد سپس اکشن متدی که حاوی ElectronicsActionMethodSelectorAttribute می باشد اجرا خواهد شد در غیر اینصورت خطای 404 برگردانده می شود.

MechanicalActionMethodSelectorAttribute

این کلاس نیز دقیقا مانند کلاس بالا می باشد با این تفاوت که request header ارسالی را برای عبارت P-Mechanical: true بررسی می نماید.

مرحله 4: در پوشه controllers، یک کنترلر با نام ProductController  ایجاد نمایید و متدهای زیر را درون آن کپی نمایید:

using System.Web.Mvc;
using MVC_CustomActionMethodSelector.Models;
using MVC_CustomActionMethodSelector.CustomActioMethodSelector;
 
namespace MVC_CustomActionMethodSelector.Controllers
{
    public class ProductController : Controller
    {
        // GET: Product
        public ActionResult Index()
        {
            return View();
        }
 
        [ElectronicsActionMethodSelector]
        public ActionResult GetElectronics()
        {
            var ds = new DataAccessElectronics();
            var products = ds.GetDataElectronics();
            return View("IndexElectronics", products);
        }
        [MechanicalActionMethodSelector]
        public ActionResult GetMechanical()
        {ttronutes
            var ds = new DataAccessMechanical();
            var products = ds.GetDataMechanical();
             return View("IndexMechanical", products);
        }
 
    }
}


کد بالا اکشن GetElectronics() و GetMechanical() با attribute های ElectronicsActionMethodSelector و MechanicalActionMethodSelector نشان می دهد که بر روی آنها اعمال شده اند. این به این معنیست زمانی که ما request را به هریک از این متدها با مقادیر P-Electronics and P-Mechanical ارسال می کنیم، این متدها فراخوانده و اجرا می شوند.

view های تولید شده برای اکشن متدهای بالا به فرض مثال IndexElectronics.cshtml و IndexMechanical.cshtml می باشند.

مرحله 5: حال یک breakpoint  داخل اکشن های GetElectronics و GetMechanical و متد IsValidForRequest در کلاس Action method selector سفارشی که در مرحله 3 ایجاد نمودیم قرار دهید. ما پرو‍ژه را با ابزار fiddler تست می نماییم.

application  را اجرا نمایید و در تب composer در ابزار fiddler آدرس زیر را وارد نمایید:

http://localhost:44083/Product/GetElectronics

روی دکمه Execute کلیک نمایید که در نتیجه با خطاس 404 مواجه خواهید شد:

خطای 404 mvc

حال request header را با مقدار P-Electronics: true به روزنمایید:

request header در mvc

روی دکمه Execute کلیک نمایید. در نتیجه کد وارد debug  می شود. مقدار header  را مانند شکل زیر بررسی نمایید:

header value

مقدار header  به عنوان P-Electronics دریافت شده است. زمانی که عملیات debug را ادامه دهید مشاهده خواهید نمود که اکشن GetElectronics مانند شکل زیر فراخوانی خواهد شد:

elec debug

F5 را بزنید. در نتیجه اجرا با نتیجه زیر در Web View ابزار Fiddler کامل خواهد شد:

نتیجه debug در fiddler

در نتیجه لیست تمام محصولات الکترونیکی به عنوان نتیجه برگشت داده میشود.

نتیجه گیری

ASP.NET MVC یک framework کامل برای توسعه application  می باشد. ویژگی Action method selector باعث می شود ما عملیت invoke  شدن اکشن متد مان را بر اساس نیاز بیزنسی مان به آسانی می سازد.

نویسنده

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