Model Binder سفارشی در MVC

سه شنبه 4 خرداد 1395

در این مقاله قصد داریم نحوه استفاده از مدل اتصال یا Model Binder سفارشی را برای نگاشت داده ها از درخواست بر روی مدل بررسی کرده و یک نمونه Model Binder پیاده سازی کنیم.

 Model Binder  سفارشی در MVC

در  ASP.NET MVC مدل های خود را می توانیم با استفاده از  Entity Framework ، کدهای ADO.net  یا هر تکنیک دسترسی به داده دیگر ایجاد کنیم. در هنگام توسعه لایه مدل،  POCO یا Plain Old CLR Objects را تعریف میکنیم. اگر از  Entity Framework  استفاده کنیم ، برنامه عناصر  POCO را فراهم میکند که می توان از آنها به عنوان موجودیت ها استفاده کرد. کنترلر  MVC متدهایی را فراهم میکند که به اشیاء  POCO به عنوان پارامتر ورودی دسترسی دارند و متد  action از این اشیاء  CLR برای ذخیره در دیتابیس استفاده میکند. MVC با کمک  POCO ،  چهارچوب بندی  View ها را انجام می دهد. در میان فرایند  Scaffolding ، مدل اتصال یا  Model binder  وارد صحنه می شود.  Model Binder  مسئول نگاشت عناصر  View  به ویژگیهای مدل  POCO است.  Model Binder  به عنوان پلی بین  View  و مدل های  MVC عمل میکند.

 MVC از انواع زیر برای مدل های اتصال استفاده میکند.

اینترفیس IModelBinder : متدهایی که برای یک مدل اتصال نیاز است تعریف میکند، مانند متد  BindModel . این متد با استفاده از ControllerContext  و  BindingContext مسئول اتصال یک مدل به بعضی مقادیر است.

اینترفیس  IModelBinderProvider : این اینترفیس شامل متدهایی است که پیاده سازی داینامیک مدل اتصال را برای کلاس هایی که اینترفیس  IModelBinder  را پیاده سازی میکنند فعال میکند. برای مدیریت اتصالات سفارشی برای نوع داده های ارسال شده توسط کاربر نهایی در  View ها استفاده می شود.

کلاس DefaultModelBinder  :

     - این کلاس برای نگاشت درخواست های مرورگر برای یک داده موجودیت استفاده می شود. این کلاس یک درخواست بهم پیوسته برای  IModelBinder است.

    - این کلاس به صورت پیش فرض توسط  MVC برای نگاشت داده های ارسال شده توسط عناصر  View  به ویژگیهای  POCO استفاده می شود بنابراین کنترلر می تواند از آن برای پردازش های بیشتر استفاده کند.

 Model Binder را می توان توسط دیاگرام زیر ارائه داد.

یک پروژه جدید در ویژوال استودیو ایجاد میکنیم . قالب آن را به صورت  Empty قرار داده و گزینه  MVC را انتخاب میکنیم .

یک دیتابیس با نام  ApplicationDB.mdf اضافه کرده و آن را به صورت خالی رها میکنیم. در پوشه  Models یک  ADO.NET Entity Data Model  جدید با نام  ApplicationEntities اضافه میکنیم. در پنجره باز شده گزینه  Code-First from database را انتخاب  میکنیم.

در پنجره بعدی  ApplicationDB.mdf  را انتخاب میکنیم که فایل کلاس  ApplicationEntities.cs را اضافه خواهد کرد. این کلاس از کلاس DbContext مشتق شده است. از این کلاس برای انجام عملیات پایگاه داده استفاده خواهیم کرد.

در پوشه  Models  کلاس جدیدی با نام  Employee.cs  به صورت زیر اضافه میکنیم.

using System.ComponentModel.DataAnnotations;

namespace ModelBinder.Models
{
    public class Employee
    {
        [Key]
        public int EmpNo { get; set; }
        [Display(Name = "نام ")]
        public string EmpName { get; set; }
        [Display(Name = "حقوق")]
        public decimal Salary { get; set; }
    }
}

 Employee  بالا یک کلاس  Entity  است که  EmpNo  به عنوان کلید اصلی تعریف شده است.

از آنجایی که به تولید جدول از این کلاس نیاز داریم ، خط زیر را در کلاس  ApplicationEntities  اضافه میکنیم.

public DbSet<Employee> Employees { get; set; }

یک کنترلر با نام  Employee ایجاد کرده و در آن متد زیر را اضافه میکنیم. 

using System.Linq;
using System.Web.Mvc;
using MVC_CustomModelBinder.Models;
using System.Xml.Serialization;
 
namespace MVC_CustomModelBinder.Controllers
{
    public class EmployeeController : Controller
    {
        ApplicationEntities ctx;
        public EmployeeController()
        {
            ctx = new ApplicationEntities();
        }
 
        // GET: Employee
        public ActionResult Index()
        {
            var Emps = ctx.Employees.ToList();
            return View(Emps);
        }
        public ActionResult Create()
        {
            var empPostedData = new XmlSerializer(typeof(Employee));
            var Emp = (Employee)empPostedData.Deserialize(HttpContext.Request.InputStream);
            ctx.Employees.Add(Emp);
              
            return View("Index") ;
        } 
    }
}

کد بالا شیء  ApplicationEntities را برای ارتباط با دیتابیس استفاده میکند.در اینجا متد  Create بسیار اهمیت دارد. از یک کلاس  XmlSerializer برای تعریف نوع داده  XML که از طریق درخواست  Post  دریافت می شود استفاده شده است. از متد  Deserialize() هنگامی استفاده می شود که درخواست خوانده شده و در شیء  Employee ذخیره شده است که در عملیات های دیتابیس استفاده خواهد شد. با قرار دادن  breakpoint بر روی این متد می توانیم آن را تست کنیم . برای تست داده ها از  fiddler می توان استفاده کرد. در اینجا از  Postman  استفاده شده است.

ابزار  fiddler  را باز کرده و آدرس زیر را استفاده میکنیم.

برنامه  MVC را ایجاد کنید. با فشردن دکمه  Execute  نتیجه  اشکال زدایی یا  debug به صورت زیر در شیء  Emp که در کد تعریف شده است نمایش داده خواهد شد.

کد داده  Employee  پست شده را نمایش می دهد. متد  Deserializer درخواست ها را می خواند و داده ها بر روی شیء Employee نگاشت میکند. از این می توان برای فرایندهای سمت سرور استفاده کرد. اما برای هر متد action در کنترلر باید مکانیزمی داشته باشیم که با استفاده از آن داده ها به صورت خودکار با استفاده از شیء  CLR نگاشت شوند. اینجا همان جایی است که  Model Binder  وارد می شود. در اینجا ما به پیاده سازی زیر ساختی با استفاده از داده های  XML پست شده که بر روی شیء  EMployee  نگاشت می شوند احتیاج داریم. می توان آن را با استفاده از یک  Model Binder  سفارشی انجام داد. 

پوشه جدیدی با نام  CustomModelBinders درون پروژه ایجاد میکنیم. در این پوشه یک کلاس با کدهای زیر اضافه میکنیم.

using System;
using System.Web;
 
using System.Web.Mvc;
using System.Xml.Serialization;
 
namespace MVC_CustomModelBinder.CustomModelBinders
{
    public class XMLToObjectModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            try
            {
                //1.
                var model = bindingContext.ModelType;
                //2.
                var data = new XmlSerializer(model);
                //3.
                var receivedStream = controllerContext.HttpContext.Request.InputStream;
                //4.
                return data.Deserialize(receivedStream);
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.AddModelError("Error", "Received Model cannot be serialized");
                return null;
            }
 
        }
    }
    public class XMLToObjectModelBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(Type modelType)
        {
            //5.
            var receivedContentType = HttpContext.Current.Request.ContentType.ToLower();
            if (receivedContentType != "text/xml")
            {
                return null;
            }
 
            return new XMLToObjectModelBinder();
        }
    }
 
}

کلاس XMLToObjectModelBinder ویژگیهای زیر را دارد.

1. این دستورات نوع  Model  را تحت Model Context  جاری می خواند.

2. نمونه ای از  XmlSerializer برای کار با داده های پست شده تعریف شده است.

3. داده دریافت شده از درخواست پست شده خوانده می شود.

4. داده های دریافت شده  Deserialize می شوند.

کلاس  XMLToObjectModelBindingProvider ،  اینترفیس  IModelBinderProvider  و متد  GetBinder() آن را پیاده سازی میکند. این متد نوع محتوا را از درخواست ورودی می خواند. اگر نوع محتوای دریافت شده text/xml نباشد آنگاه  Null بازگردانده خواهد شد در غیر اینصورت یک نمونه از XMLToObjectModelBindiner باز گردانده خواهد شد.

کلاس فراهم کننده  Model  سفارشی را در برنامه اضافه خواهیم کرد بنابراین برنامه آن را در فرایند  Model Binder  بارگذاری خواهد کرد.  Global.asax را باز کرده و خطی که با  highlighte  مشخص شده است را در آن اضافه میکنیم.

protected void Application_Start()
{
    ModelBinderProviders.BinderProviders.Insert(0, new XMLToObjectModelBinderProvider());
    AreaRegistration.RegisterAllAreas();
    RouteConfig.RegisterRoutes(RouteTable.Routes);
}

 ModelBinderProviders  فراهم کننده اتصال را که در مرحله قبل ایجاد کردیم در برنامه اضافه خواهد کرد.

کد متد  Create را به صورت زیر تغییر می دهیم.

public ActionResult Create(Employee Emp)
{
    ctx.Employees.Add(Emp);
    ctx.SaveChanges(); 
    return View("Index") ;
}

یک  breakpoint بر روی متد Create قرار داده و برنامه را با استفاده از  Fiddler  اجرا میکنیم. داده های  Employee ارسال شده به صورت زیر نمایش داده خواهند شد.

کد نشان می دهد که داخل شیء  Employee CLR داده ها  deserialized شده اند.

آموزش asp.net mvc

فایل های ضمیمه

برنامه نویسان

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

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

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