مطالب
کار با Areas در ASP.NET Core
کار با Areas را تا ASP.NET MVC 5.x می‌توانید در مطلب «ASP.NET MVC #14» مطالعه کنید. در ASP.NET Core، کلیات آن ثابت مانده‌است و تنظیمات ابتدایی آن اندکی تغییر کرده‌اند.


مفهوم Areas

Areas یکی از روش‌های ساماندهی برنامه‌های بزرگ، به نواحی کوچکتری مانند قسمت‌های مدیریتی، پشتیبانی از کاربران و غیره است. به این ترتیب می‌توان کنترلرها، Viewها و مدل‌های هر قسمت را از قسمتی دیگر، جدا کرد و مدیریت پروژه را ساده‌تر نمود. هر Area دارای ساختار پوشه‌های مرتبط به خود می‌باشد و به این نحو است که جداسازی این نواحی مختلف را میسر می‌کند؛ تا بهتر مشخص باشد که هر المانی متعلق است به چه ناحیه‌ای. به علاوه در این حالت می‌توان پروژه را بین چندین توسعه دهنده‌ی مختلف نیز تقسیم کرد؛ بدون اینکه در کار یکدیگر تداخلی ایجاد کنند.


ایجاد Areas

اگر با ASP.NET MVC 5.x کار کرده باشید، می‌دانید که ویژوال استودیو با کلیک راست بر روی پروژه‌ی جاری، گزینه افزودن یک Area جدید را به همراه دارد. یک چنین قابلیتی تا ASP.NET Core 1.1 به ابزارهای همراه آن افزوده نشده‌است. بنابراین تمام مراحل ذیل را باید دستی ایجاد کنید و هنوز قالب از پیش تعریف شده و ساده کننده‌‌ای برای اینکار وجود ندارد:


همانطور که در تصویر نیز ملاحظه می‌کنید، نیاز است در ریشه‌ی پروژه، پوشه‌ی جدیدی را به نام Areas ایجاد کرد. سپس در داخل این پوشه می‌توان نواحی مختلفی را با پوشه بندی‌های مجزایی ایجاد نمود. برای مثال در اینجا ناحیه‌ی Blog ایجاد شده‌است که در این ناحیه نیز پوشه‌های Controllers و Views آن باید به صورت دستی ایجاد شوند.


افزودن مسیریابی مرتبط با Areas

پس از اضافه کردن دستی پوشه‌های Areas و ناحیه‌ی جدید، به همراه ساختار پوشه‌های کنترلرها و Viewهای آن، اکنون نیاز است این ناحیه‌ی جدید را به سیستم مسیریابی معرفی نمود. برای این منظور به فایل آغازین برنامه مراجعه کرده و در متد Configure آن، تعریف جدید ذیل را اضافه می‌کنیم:
app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "areas",
        template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
 
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}"); 
});
مسیریابی پیش‌فرض را در مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 9 - بررسی تغییرات مسیریابی» پیشتر بررسی کرده‌ایم. در اینجا پیش از این مسیریابی، مسیریابی جدید areas تعریف شده‌است. قید exists در اینجا به معنای تنها استفاده‌ی از نواحی تعریف شده‌ی در برنامه‌ی جاری است و الگوی تعریف شده، تمام آن‌ها را شامل می‌شود و دیگر نیازی به تعریف مسیریابی جداگانه‌ای به ازای ایجاد هر Area جدید نیست (برخلاف ASP.NET MVC 5.x).


علامتگذاری کنترلرهای یک ناحیه

تمام اصول کار کردن با کنترلرهای یک ناحیه، مانند سایر کنترلرهای دیگر برنامه‌است؛ با یک تفاوت:
[Area("Blog")]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}
در ASP.NET Core حتما نیاز است توسط ویژگی جدید Area، نام ناحیه‌ی کنترلر را صریحا مشخص کرد؛ در غیراینصورت، صرفنظر از محل تعریف این کنترلر، اطلاعات آن متعلق به هیچ ناحیه‌ای نبوده و وارد سیستم مسیریابی Areas نمی‌شود.

یک نکته: اگر از Attribute routing استفاده می‌کنید، توکن مرتبط با نواحی، [area] نام دارد:
 [Route("[area]/app/[controller]/actions/[action]/{id:weekday?}")]


فعالسازی Layout و Tag Helpers در Areas

اگر در همین حال، برنامه را اجرا و به مسیر http://localhost/blog مراجعه کنید، هرچند اطلاعات View متناظر با کنترلر Home و اکشن متد Index آن نمایش داده می‌شوند، اما این View نه layout دارد و نه Tag helpers آن پردازش شده‌اند. برای فعالسازی این دو مورد، دو فایل ViewStart.cshtml_ و ViewImports.cshtml_ را از پوشه‌ی views اصلی پروژه، به پوشه‌ی views این Area جدید کپی کنید. فایل ViewStart، نام و مسیر فایل layout پیش فرض ناحیه را مشخص می‌کند و فایل ViewImports حاوی تعاریف فعالسازی Tag helpers است:
 @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
 هر Area می‌تواند layout خاص خودش را داشته باشد؛ اما اگر فایل ViewStart آن به نحو ذیل مقدار دهی شود، به فایل اصلی واقع در پوشه‌ی Views/Shared/_Layout.cshtml ریشه‌ی پروژه، اشاره می‌کند.
 @{
 Layout = "_Layout";
}
و برای تغییر و یا مقداردهی صریح آن می‌توان به صورت ذیل عمل کرد:
 @{
 Layout = "~/Areas/Blog/Views/Shared/_Layout.cshtml";
}


Areas و تاثیر آن‌ها در حین لینک دهی به قسمت‌های مختلف برنامه

اگر قرار است لینکی به قسمتی واقع در همان Area جاری مرتبط شود، نیازی نیست تا هیچ نکته‌ی خاصی را درنظر گرفت و تولید لینک‌ها به نحو صحیحی صورت می‌گیرند:
 <a asp-action="Index" asp-controller="Home">Link</a>
اما اگر می‌خواهیم به ناحیه‌ی جدیدی به نام Services و کنترلر و اکشن متد خاصی از آن، از یک ناحیه‌ی دیگر لینک دهیم، نیاز است asp-area را صریحا ذکر کرد:
 <a asp-area="Services" asp-controller="Home" asp-action="Index">Go to Services’ Home Page</a>
به علاوه  اگر قصد تعریف لینکی را به یک اکشن متد واقع در کنترلری که در هیچ ناحیه‌ای قرار ندارد، داشته باشیم، باید asp-area آن‌را خالی ذکر کنیم:
 <a asp-action="Index" asp-controller="Home" asp-area="">Link</a>


تاثیر Areas بر روی تنظیمات توزیع برنامه

فایل‌های View موجود در Areas نیز باید در حین توزیع نهایی برنامه ارائه شوند؛ مگر اینکه آن‌ها را از پیش کامپایل کرده باشیم. اگر از حالت از پیش کامپایل کردن Viewها استفاده نمی‌شود، نیاز است قسمت publishOptions فایل project.json را به نحو ذیل در جهت الحاق فایل‌های Viewهای نواحی مختلف، ویرایش و تکمیل کرد:
"publishOptions": {
     "include": [
       "Areas/**/*.cshtml",
       ....
       ....
     ]
مسیرراه‌ها
Entity framework code-first
شروع به کار با EF Code first

برای تکمیل بحث نیاز است تغییرات انجام شده از نگارش 4 به 6 را نیز مد نظر داشته باشید:


آشنایی با مباحث Migrations



آشنایی با تنظیمات نگاشت‌ها به دو روش استفاده از ویژگی‌ها و Fluent API



اعتبارسنجی و بررسی استثناءها



ردیابی تغییرات



استفاده از SQL خام و بانک‌های اطلاعاتی متفاوت

      نکات مهم کوئری نویسی در EF



      استفاده از EF در WPF


      لایه بندی پروژه‌های EF Code first



      پروژ‌ه‌های انجام شده با EF Code first

       
      بازخوردهای دوره
      تزریق خودکار وابستگی‌ها در برنامه‌های ASP.NET MVC
      من مطلب بالا را مطالعه کردم و با توجه به مطلب بالا کدهای خودم را به صورت زیر تغییر دادم

      لایه Service
      namespace ServiceLayer.EFServices
      {
          public class TABMPCREWService : ITABMPCREWService
          {
              private IUnitOfWork _uow;
              private IDbSet<TABMPCREWS> _tabmpcrews;
      
              public TABMPCREWService(IUnitOfWork uow)
              {
                  this._uow = uow;
                  _tabmpcrews = uow.Set<TABMPCREWS>();
              }
      
              public int Add(TABMPCREWS personnel)
              {
                  int rowEffect = 0;
      
                  _tabmpcrews.Add(personnel);
                  rowEffect = _uow.SaveChanges();
                  return rowEffect;
              }
      
          }
      }
      و اینترفیس
      namespace ServiceLayer.Interface
      {
          public interface ITABMPCREWService
          {
              int Add(TABMPCREWS personnel);
          }
      }
      و فایل Global
       protected void Application_Start()
              {
                  AreaRegistration.RegisterAllAreas();
      
                  RegisterGlobalFilters(GlobalFilters.Filters);
                  RegisterRoutes(RouteTable.Routes);
                  ObjectFactory.Initialize(x =>
                  {
                      x.For<ITABMPCREWService>().Use<TABMPCREWService>();
                     // x.For<IUsersService>().Use<UsersService>();
                  });
                  ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
                 // initStructureMap();
              }
      و
       public class StructureMapControllerFactory  : DefaultControllerFactory
          {
              protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
              {
                  if (controllerType == null)
                      throw new InvalidOperationException(string.Format("Page not found: {0}", requestContext.HttpContext.Request.Url.AbsoluteUri.ToString(CultureInfo.InvariantCulture)));
                  return ObjectFactory.GetInstance(controllerType) as Controller;
              }
          }
      و کد کنترلر
      public class HomeController  : Controller
          {
              public readonly ITABMPCREWService aa ;
              public HomeController(ITABMPCREWService tabmpcrewService)
              {
                  aa = tabmpcrewService;
              }
      
              public ActionResult Index()
              {
      
                  TABMPCREWS tt = new TABMPCREWS()
                  {
                      DTLASTUPDATEDDATE = DateTime.Now,
                      INTOTRATE = 122,
                      INTRATE = 215,
                      VCCODEDESCRIPTION = "fff858699",
                      VCCODEVALUE = "fff858699",
                      VCLASTUSERID = "fff858699",
                      INTCREWCODE = 105652
                  };
                  aa.Add(tt);
      
      
                  ViewBag.Message = "Welcome to ASP.NET MVC!";
      
                  return View();
              }
      
              public ActionResult About()
              {
                  ViewBag.Message = "Your app description page.";
      
                  return View();
              }
      
      public ActionResult Contact()
              {
                  ViewBag.Message = "Your contact page.";
      
                  return View();
              }
          }
      اما زمان اجرا این خطا رو بهم میده و از این خط خطا می‌گیره


      بازخوردهای دوره
      تزریق خودکار وابستگی‌ها در برنامه‌های ASP.NET MVC
      با سلام؛ من در استفاده از این روش در پروژه خودم به مشکل بر خوردم ممنون میشم راهنمایی بفرمایید.
      ساختار لایه بندی من به صورت زیر است.

      در پروژه وب یک کلاس ایجاد کردم و کد‌های زیر را در آن نوشتم

       public class StructureMapControllerFactory  : DefaultControllerFactory
          {
              protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
              {
                  if (controllerType == null)
                      throw new InvalidOperationException(string.Format("Page not found: {0}", requestContext.HttpContext.Request.Url.AbsoluteUri.ToString(CultureInfo.InvariantCulture)));
                  return ObjectFactory.GetInstance(controllerType) as Controller;
              }
          }
      و کدهای کنترلر من به صورت زیر است
       public class HomeController  : Controller
          {
              public ITABMPCREWService aa { get; set; }
      
              public ActionResult Index()
              {
      
                  TABMPCREWS tt = new TABMPCREWS()
                  {
                      DTLASTUPDATEDDATE = DateTime.Now,
                      INTOTRATE = 122,
                      INTRATE = 215,
                      VCCODEDESCRIPTION = "fff858699",
                      VCCODEVALUE = "fff858699",
                      VCLASTUSERID = "fff858699",
                      INTCREWCODE = 105652
                  };
                  aa.Add(tt);
      
      
                  ViewBag.Message = "Welcome to ASP.NET MVC!";
      
                  return View();
              }
      
              public ActionResult About()
              {
                  ViewBag.Message = "Your app description page.";
      
                  return View();
              }
      
      public ActionResult Contact()
              {
                  ViewBag.Message = "Your contact page.";
      
                  return View();
              }
          }
      و در فایل Global  در متد Application_Start() کد زیر را اضافه کردم
      ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
      و در لایه Service کلاس TABMPCREWServiceبه صورت زیر است
       public class TABMPCREWService : ITABMPCREWService
          {
              private IUnitOfWork _uow;
              private IDbSet<TABMPCREW> _tabmpcrews;
              public TABMPCREWService(IUnitOfWork uow)
              {
                  this._uow = uow;
                  _tabmpcrews = uow.Set<TABMPCREW>();
              }
      
              public int Add(TABMPCREW personnel)
              {
                  int rowEffect = 0;
      
                  _tabmpcrews.Add(personnel);
                  rowEffect = _uow.SaveChanges();
                  return rowEffect;
              }
      
          }
      و زمانیکه پروژه را اجرا می‌کنم به این خطا بر می‌خورم

      همه چیز رو چک کردم ولی دلیلی برای این خطا پیدا نکردم . ممنون میشم راهنمایی کنید.
      بازخوردهای دوره
      تهیه کوئری بر روی ایندکس‌های Full Text Search
      بنده در حال ساخت جستجویی برای وب سایتی هستم. این جستجو بر روی جداول کتاب، نویسنده، مترجم و انتشارات انجام میشه و در صورتی که کاربر قسمتی از نام کتاب و نام نویسنده را وارد کند جستجو بر روی این دو فیلد که از دو جدول متفاوت هستند انجام می‌شود.
      مشکل اینجاست که از آنجایی که دستوارت FTS بر روی یک جدول عمل می‌کنند و با توجه به پیچیدگی جستجو، شما چه راهی را برای کوئری گرفتن از چندین جدول (که ممکن است یک کتاب چند نویسنده هم داشته باشد) پیشنهاد می‌کنید.
      بنده در حال حاضر تمام این جداول را در یک View قرار داده و فیلدهای چندمقداری را با Concat بوسیله " ، " در یک فیلد جای داده‌ام.
      ممنون از راهنماییتون
      مطالب
      سفارشی سازی عناصر صفحات پویای افزودن و ویرایش رکوردهای jqGrid در ASP.NET MVC
      پیشنیاز این بحث مطالعه‌ی مطالب «صفحه بندی و مرتب سازی خودکار اطلاعات به کمک jqGrid در ASP.NET MVC» و «فعال سازی و پردازش صفحات پویای افزودن، ویرایش و حذف رکوردهای jqGrid در ASP.NET MVC» است و در اینجا جهت کوتاه شدن بحث، صرفا به تغییرات مورد نیاز جهت اعمال بر روی مثال‌ها اکتفاء خواهد شد.


      صورت مساله

          public class Product
          {
              public int Id { set; get; }
              public DateTime AddDate { set; get; }
              public string Name { set; get; }
              public decimal Price { set; get; }
          }
      در اینجا تعریف محصول، شامل خاصیت‌های تاریخ ثبت، نام و قیمت آن است.
      می‌خواهیم زمانیکه فرم‌های پویای ویرایش یا افزودن رکوردها ظاهر شدند، در حین تکمیل نام، یک auto complete ظاهر شود:


      در حین ورود تاریخ، یک date picker شمسی جهت سهولت ورود اطلاعات نمایش داده شود:


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



      پیشنیازها

      - برای نمایش auto complete از همان امکانات توکار jQuery UI که به همراه jqGrid عرضه می‌شوند، استفاده خواهیم کرد.
      - برای نمایش date picker شمسی از مطلب «PersianDatePicker یک DatePicker شمسی به زبان JavaScript که از تاریخ سرور استفاده می‌کند» کمک خواهیم گرفت.
      - جهت اعمال خودکار حرف سه رقم جدا کننده هزارها از افزونه‌ی Price Format جی‌کوئری استفاده می‌کنیم.

      تعریف و الحاق این پیشنیازها، فایل layout برنامه را به شکل زیر تغییر خواهد داد:
      <!DOCTYPE html>
      <html>
      <head>
          <meta charset="utf-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>@ViewBag.Title - My ASP.NET Application</title>
      
          <link href="~/Content/themes/base/jquery.ui.all.css" rel="stylesheet" />
          <link href="~/Content/jquery.jqGrid/ui.jqgrid.css" rel="stylesheet" />
          <link href="~/Content/PersianDatePicker.css" rel="stylesheet" />
          <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
      </head>
      <body>
          <div>
              @RenderBody()
          </div>
      
          <script src="~/Scripts/jquery-1.7.2.min.js"></script>
          <script src="~/Scripts/jquery-ui-1.8.11.min.js"></script>
          <script src="~/Scripts/i18n/grid.locale-fa.js"></script>
          <script src="~/Scripts/jquery.jqGrid.min.js"></script>
          <script src="~/Scripts/PersianDatePicker.js"></script>
          <script src="~/Scripts/jquery.price_format.2.0.js"></script>
      
          @RenderSection("Scripts", required: false)
      </body>
      </html>


      تغییرات مورد نیاز سمت کلاینت، جهت اعمال افزونه‌های جی‌کوئری و سفارشی سازی عناصر دریافت اطلاعات

      الف) نمایش auto complete در حین ورود نام محصولات
                      colModel: [
                          {
                              name: 'Name', index: 'Name', align: 'right', width: 100,
                              editable: true, edittype: 'text',
                              editoptions: {
                                  maxlength: 40,
                                  dataInit: function (elem) {
                                      // http://jqueryui.com/autocomplete/
                                      $(elem).autocomplete({
                                          source: '@Url.Action("GetProductNames","Home")',
                                          minLength: 2,
                                          select: function (event, ui) {
                                              $(elem).val(ui.item.value);
                                              $(elem).trigger('change');
                                          }
                                      });
                                  }
                              },
                              editrules: {
                                  required: true
                              }
                          }           
           ],
      برای اعمال هر نوع افزونه‌ی جی‌کوئری به عناصر فرم‌های خودکار ورود اطلاعات در jqGrid، تنها کافی است که رویداد dataInit یک ستون را بازنویسی کنیم. در اینجا توسط elem، المان جاری را در اختیار خواهیم داشت. سپس از این المان جهت اعمال افزونه‌ای دلخواه استفاده می‌کنیم. برای مثال در اینجا از متد autocomplete استفاده شده‌است که جزئی از jQuery UI استاندارد است.
      برای پردازش سمت سرور آن و مقدار دهی url آن، یک چنین اکشن متدی را می‌توان تدارک دید:
              public ActionResult GetProductNames(string term)
              {
                  var list = ProductDataSource.LatestProducts
                      .Where(x => x.Name.StartsWith(term))
                      .Select(x => x.Name)
                      .Take(10)
                      .ToArray();
                  return Json(list, JsonRequestBehavior.AllowGet);
              }
      مقدار term، عبارتی است که کاربر وارد کرده است. توسط متد StartsWith، کلیه نام‌هایی را که با این عبارت شروع می‌شوند (البته 10 مورد از آن‌ها را) بازگشت می‌دهیم.

      ب) نمایش date picker شمسی در حین ورود تاریخ
                      colModel: [
                          {
                              name: 'AddDate', index: 'AddDate', align: 'center', width: 100,
                              editable: true, edittype: 'text',
                              editoptions: {
                                  maxlength: 10,
                                  // https://www.dntips.ir/post/1382
                                  onclick: "PersianDatePicker.Show(this,'@today');"
                              },
                              editrules: {
                                  required: true
                              }
                          }
                      ],
      Date picker مورد استفاده، وابستگی خاصی به jQuery ندارد. مطابق مستندات آن باید در رویدادگردان onclick، این تقویم شمسی را فعال کرد. بنابراین در قسمت onclick دقیقا این مورد را اعمال می‌کنیم.

       @{
      ViewBag.Title = "Index";
      var today = DateTime.Now.ToPersianDate();
      }
      مقدار today آن در ابتدای View به نحو فوق تعریف شده‌است. کدهای کامل متد کمکی ToPersianDate در پروژه‌ی پیوست موجود است.

      ج) اعمال حروف سه رقم جدا کننده هزارها در حین ورود قیمت
                      colModel: [
                          {
                              name: 'Price', index: 'Price', align: 'center', width: 100,
                              formatter: 'currency',
                              formatoptions:
                              {
                                  decimalSeparator: '.',
                                  thousandsSeparator: ',',
                                  decimalPlaces: 2,
                                  prefix: '$'
                              },
                              editable: true, edittype: 'text',
                              editoptions: {
                                  dir: 'ltr',
                                  dataInit: function (elem) {
                                      // http://jquerypriceformat.com/
                                      $(elem).priceFormat({
                                          prefix: '',
                                          thousandsSeparator: ',',
                                          clearPrefix: true,
                                          centsSeparator: '',
                                          centsLimit: 0
                                      });
                                  }
                              },
                              editrules: {
                                  required: true,
                                  minValue: 0
                              }
                          }
                      ],
      افزونه‌ی price format نیز یک افزونه‌ی جی‌کوئری است. بنابراین دقیقا مانند حالت auto complete آن‌را در dataInit فعال سازی می‌کنیم و همچنین یک سری تنظیم ابتدایی مانند مشخص سازی  thousandsSeparator آن‌را مقدار دهی خواهیم کرد.


      یک نکته

      همین تعاریف را دقیقا به فرم‌های جستجو نیز می‌توان اعمال کرد. در اینجا برای حالات ویرایش و افزودن رکوردها، editoptions مقدار دهی شده‌است؛ در مورد فرم‌های جستجو باید searchoptions و برای مثال dataInit آن‌را مقدار دهی کرد.



      مشکل مهم!

      با تنظیمات فوق، قسمت UI بدون مشکل کار می‌کند. اما اگر در سمت سرور، مقادیر دریافتی را بررسی کنیم، نه تاریخ و نه قیمت، قابل دریافت نیستند. زیرا تاریخ ارسالی به سرور شمسی است و مدل برنامه DateTime میلادی می‌باشد. همچنین به دلیل وجود حروف سه رقم جدا کننده هزارها، عبارت دریافتی قابل تبدیل به عدد نیستند و مقدار دریافتی صفر خواهد بود.
      برای رفع این مشکلات، نیاز به تغییر model binder توکار ASP.NET MVC است. برای تاریخ‌ها از کلاس PersianDateModelBinder می‌توان استفاده کرد. برای اعداد decimal از کلاس ذیل:
      using System;
      using System.Globalization;
      using System.Threading;
      using System.Web.Mvc;
      
      namespace jqGrid05.CustomModelBinders
      {
          /// <summary>
          /// How to register it in the Application_Start method of Global.asax.cs
          /// ModelBinders.Binders.Add(typeof(decimal), new DecimalBinder());
          /// </summary>
          public class DecimalBinder : DefaultModelBinder
          {
              public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
              {
                  if (bindingContext.ModelType == typeof(decimal) || bindingContext.ModelType == typeof(decimal?))
                  {
                      return bindDecimal(bindingContext);
                  }
                  return base.BindModel(controllerContext, bindingContext);
              }
      
              private static object bindDecimal(ModelBindingContext bindingContext)
              {
                  var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
                  if (valueProviderResult == null)
                      return null;
                  
                  bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
                  decimal value;
                  var valueAsString = valueProviderResult.AttemptedValue == null ?
                                              null : valueProviderResult.AttemptedValue.Trim();
                  if (string.IsNullOrEmpty(valueAsString))
                      return null;
                  
                  if (!decimal.TryParse(valueAsString, NumberStyles.Any, Thread.CurrentThread.CurrentCulture, out value))
                  {
                      const string error ="عدد وارد شده معتبر نیست";
                      var ex = new InvalidOperationException(error, new Exception(error, new FormatException(error)));
                      bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex);
                      return null;
                  }
                  return value;
              }
          }
      }
      در اینجا عبارت ارسالی به سرور به صورت یک رشته دریافت شده و سپس تبدیل به یک عدد decaimal می‌شود. در آخر به سیستم model binding بازگشت داده خواهد شد. به این ترتیب دیگر مشکلی با پردازش حروف سه رقم جدا کننده هزارها نخواهد بود.

      برای ثبت و معرفی این کلاس‌ها باید به نحو ذیل در فایل global.asax.cs برنامه عمل کرد:
      using System;
      using System.Web.Mvc;
      using System.Web.Routing;
      using jqGrid05.CustomModelBinders;
      
      namespace jqGrid05
      {
          public class MvcApplication : System.Web.HttpApplication
          {
              protected void Application_Start()
              {
                  AreaRegistration.RegisterAllAreas();
                  RouteConfig.RegisterRoutes(RouteTable.Routes);
                  ModelBinders.Binders.Add(typeof(DateTime), new PersianDateModelBinder());
                  ModelBinders.Binders.Add(typeof(decimal), new DecimalBinder());
              }
          }
      }


      کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید
      jqGrid05.zip