כאשר אנחנו רוצים להגדיר Actions המקבלים אובייקטים ועושים עליהם מניפולציה ומחזירים תשובה כלשהי (שזה פחות או יותר התפקיד של כמעט כל Action) נכתוב קוד בסגנון הזה

    public class HomeController : Controller
    {
        public ActionResult SendObject1(Employee person)
        {
            //……
            //……
            //……
            return Json(person, JsonRequestBehavior.AllowGet);
        }
    }
     
    public class Employee
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public float Salary { get; set; }
    }

     

    המתודה מקבלת אובייקט מסוג Employee ולצורך הבדיקה היא מחזירה אותו ב – JSON.,

    הפנייה למתודה בשביל הבדיקה יכולה להתבצע ישירות מתוך שורת הכתובת, ונקבל תשובה הגיונית

    image

     

    מה יקרה כאשר נרצה שהמתודה תוגדר שהיא מקבלת Person ובכל פעם היא תקבל יורש אחר,

    public class HomeController : Controller
    {
        public ActionResult SendObject1(Person person)
        {
            //……
            //……
            //……
            return Json(person, JsonRequestBehavior.AllowGet);
        }
    }
     
    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
     
    public class Employee : Person
    {
        public float Salary { get; set; }
    }

     

    הבעייה שכרגע כאשר נשים breakpoint ב – action נראה שבאמת קיבלנו Person אע”פ ששלחנו גם את ה – Salary, המנגנון של MVC לא ידע להבין שמדובר ב – Employee.

     

    image

     

    מי שאשם בזה הוא מנגנון ה – Model Binder או ליתר דיוק ה – DefaultModelBinder של MVC, המנגנון שלו אומר (ובצורה הגיונית) שיעבור בסוג של Reflection על המאפיינים של האובייקט שהוא אמור לבנות (במקרה שלנו Person) וימלא את הערכים שלו, לא מעניין אותו שבפועל נשלחו עוד ערכים.

    המטרה שלנו היא לעזור לו להבין שהפעם צריך לבנות אובייקט מסוג Employee.

    בשביל זה נוסיף את המחלקה הבאה:

    public class PersonModelBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controller, ModelBindingContext binding)
        {
            var salary = binding.ValueProvider.GetValue("Salary");
            if(salary != null)
            {
                binding.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(Employee));
            }
     
            return base.BindModel(controller, binding);
        }
    }

     

    בקוד שלהלן, אנחנו מקבלים החלטה לפי המידע האם קיים פרמטר בשם Salary, כמובן שבחיים האמיתיים ההחלטה יכולה להיות לפי הערך של פרמטר מסויים ועוד, (ValueProvider הוא חלק מהתשתית של MVC שעוזרת לקבל מידע שנשלח מצד הלקוח ממגוון מקורות).

    צריך גם להודיע ל – MVC שיגיע לכאן כאשר הוא צריך ליצור Person.

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        ModelBinders.Binders.Add(typeof(Person), new PersonModelBinder());
    }

    השורה האחרונה היא החשובה.

     

    כעת כאשר נדבג נראה את הדבר הבא

    image

     

    כמובן אם לא נשלח את הפרמטר Salary נקבל ישירות את Person.