یکدست کردن "ی" و "ک" در ASP.NET MVC با پیاده‌سازی یک Model Binder
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: یک دقیقه

قبلا در همین وب‌سایت در مورد یکسان‌سازی حروف "ی" و "ک" مطلبی بیان شده است. تمرکز آن مطلب بر روی اعمال تغییرات، قبل از ذخیره در دیتابیس با استفاده از EF است. به عبارتی، متن‌هایی که توسط مدیر سایت یا هر کاربر دیگری برای ذخیره شدن در دیتابیس وارد شده است. اما در صورتی که کاربری در جستجوی خود از حروف "ی" و "ک" عربی استفاده کند چه می‌شود؟ در اینجا می‌خواهیم روشی را پیاده‌سازی کنیم که عمومی بوده و بتواند هر دوی این حالات را پوشش دهد.

مسئله این است که بایستی تمام ورودی‌های کاربران سایت که از نوع رشته هستند چک و در صورت نیاز اصلاح شوند. بهترین روشی که به ذهن من می‌رسد این است که در فرایند Model Binding این عمل انجام بگیرد. با تعریف یک Model Binder برای نوع رشته می‌توانیم عمل یکدست‌سازی را به صورت عمومی در تمام وب‌سایت اعمال کنیم.

در MVC یک Model Binder پیش‌فرض داریم به نام DefaultModelBinder . ما هم از همین کلاس استفاده می‌کنیم تا تمام کارها را برای ما انجام دهد. تنها بایستی در متد BindModel آن کد موردنظر خود را اضافه کنیم و سپس اجازه دهیم بقیه فرایند به شکل عادی ادامه پیدا کند.

کلاسی به نام StringModelBinder اضافه کرده و کلاس DefaultModelBinder را به عنوان کلاس پایه آن تعریف می‌کنیم. سپس متد BindModel آنرا override کرده، کد مربوط به یکدست‌سازی را اضافه می‌کنیم :

    public class StringModelBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            object value = base.BindModel(controllerContext, bindingContext);

            if (value == null)
            {
                return value;
            }

            return value.ToString().Replace((char)1610, (char)1740).Replace((char)1603, (char)1705);
        }
    }

ابتدا مقدار به دست آمده توسط متد پیش‌فرض را می‌گیریم. سپس در صورت نیاز یکسان‌سازی را انجام می‌دهیم.

برای فعال کردن این Model Binder بایستی آنرا در رویداد Application_start برنامه، برای نوع رشته به ModelBinder‌های برنامه اضافه کنیم :

ModelBinders.Binders.Add(typeof(string), new StringModelBinder());

 
  • #
    ‫۹ سال و ۶ ماه قبل، جمعه ۷ فروردین ۱۳۹۴، ساعت ۰۲:۱۱
    در مطلب تکمیلی «یک دست سازی ی و ک در برنامه‌های Entity framework 6» روش دیگری برای اینکار معرفی شده‌است. در این حالت تمام کوئری‌هایی که توسط EF صادر می‌شوند و تمام پارامترهای آن‌ها پیش از ارسال به بانک اطلاعاتی، تحت کنترل قرار می‌گیرند (هر دو حالت کوئری‌های select و یا insert/update/delete توسط interceptorها در اختیار هستند و نه فقط حالت insert/update/delete مطلب قبلی).  
  • #
    ‫۹ سال و ۴ ماه قبل، دوشنبه ۱۸ خرداد ۱۳۹۴، ساعت ۰۱:۱۷
    موقعی که میخوام ازDefaultModelBinder ارث بری کنم دو تا از این کلاس‌ها میاد که یکی در فضای نام
    system.web.mvc

    است و دیگری در فضای نام
    system.web.modelbinding

    چه تفاوتی با همدیگه دارند؟
    • #
      ‫۹ سال و ۴ ماه قبل، دوشنبه ۱۸ خرداد ۱۳۹۴، ساعت ۰۵:۴۸
      ظاهرن System.Web.ModelBinding برای استفاده در Asp.net Webforms هست.

      The System.Web.ModelBinding namespace provides classes that enable you to bind data objects to ASP.NET Web Forms server controls.

      و برای پروژه‌های mvc از فضانام مربوط به خودش یعنی system.web.mvc استفاده می‌کنیم.

      فضانام سومی به نام System.Web.Http.ModelBinding  هم وجود داره که برای Asp.net Web API استفاده میشه.
  • #
    ‫۵ سال و ۱۰ ماه قبل، یکشنبه ۶ آبان ۱۳۹۷، ساعت ۱۹:۲۶
    یک نکته تکمیلی :
    در این روش تنها پارامترهای رشته ای که به طور مستقیم، متغیر در اکشن متد تعریف میشود بایند میگردند ولی خصوصیت‌های رشته ای در پارامترهایی که از نوع کلاس تعریف شده اند که بسیار پرکاربرد هم هستند تاثیری ندارد، برای این موارد بایندر جدیدی را به شکل زیر مینویسیم:
    public class StringModelBinder : DefaultModelBinder
        {
    
    protected override void SetProperty(ControllerContext controllerContext,
              ModelBindingContext bindingContext,
              System.ComponentModel.PropertyDescriptor propertyDescriptor, object value)
            {
                if (propertyDescriptor.PropertyType == typeof(string))
                {
                    var stringValue = (string)value;
                    if (!string.IsNullOrEmpty(stringValue))
                    {
                        value =value.ToString().Replace((char)1610, (char)1740).Replace((char)1603, (char)1705);
                    }
                    else
                    {
                        value = null;
                    }
                }
    
                base.SetProperty(controllerContext, bindingContext,
                                    propertyDescriptor, value);
            }
    
        }
    در اینجا متد دیگری را به نام SetProperty برای تغییر خصوصیت هر متدی که یافت میشود صدا زده میشود را رونویسی کردیم. شی propertyDescriptor  اطلاعات خصوصیت مورد نظر از قبیل نام و مقدار و ... را نگهداری میکندو در اینجا مقدار خصوصیت را دریافت کرده و تغییرات لازم را انجام میدهیم سپس مقدا تغییر یافته را توسط base به متد پدر منتقل میکنیم. سپس برای اعمال این بایندر کد زیر را اضافه میکنیم:
     ModelBinders.Binders.DefaultBinder = new StringModelBinder();
    بدین ترتیب بایندر پیش فرض به سیستم معرفی میگردد.
  • #
    ‫۲ سال و ۴ ماه قبل، چهارشنبه ۲۴ فروردین ۱۴۰۱، ساعت ۱۴:۳۰
    معادل این مطلب برای ASP.NET Core 6x
    - روش Model binder دیگر با نگارش‌های جدیدتر ASP.NET Core کار نمی‌کند و همچنین محدودیت‌های زیادی هم مانند عدم پشتیبانی از پارامترهای [FromBody] را دارد؛ چون بکارگیری [FromBody]، استفاده‌ی از تمام Model binders سفارشی را لغو می‌کند.
    - در حال حاضر، استفاده از روش Action filters توصیه می‌شود که به این نحو قابل ثبت است.