Json در JQuery و MVC

در این مقاله با استفاده از مثال های ساده قصد پاسخ دادن به برخی از سوالات متداول در زمینه ی Json در jQuery  و MVC را داریم. پس برای درک بهتر Json در jQuery و MVC با من در این مقاله همراه باشید …

Json در JQuery و MVC

Json یا همان JavaScript Object Notation یک استاندارد مبتنی بر متن سبک وزن طراحی شده برای تبادل داده های قابل فهم برای انسان ها است.

زمانی که همزمان مشغول کار بر روی jQuery و ASP.NET MVC در ساخت برنامه های تحت وب هستید , به شما مکانیزمی معتبر برای تغییر داده ها بین مرورگر و سرور ارائه میدهد.

در سمت مرورگر داده به عنوان Java Script شئ Json ذخیره و دستکاری میشود. در سمت سرور اگر در حال استفاده از ASP.NET MVC باشید داده به عنوان شئ .NET ذخیره و دستکاری میشود.

Json در JQuery و MVC

زمانی که مرورگر داده ها را از سرور بارگذاری میکند , شئ .NET احتیاج به Serialized شدن به رشته های JSON دارد و سپس به مرورگر پاس داده شود.

مرورگر رشته های JSON را de-Serialized میکند . آنها را به اشیای JSON قابل استفاده تبدیل میکند.

زمانی که مرورگر داده ها را به سرور میفرستد اشیای JSON احتیاج به Serialized شدن به رشته های JSON را دارند و سپس عملیات de-Serialized شدن و تبدیل به اشیای .NET در سمت سرور صورت میگیرد.

این مقاله برای پاسخ به سوالات زیر در زمینه های jQuery و ASP.NET MVC با مثالی از پروژه ی ASP.NET MVC آورده شده است :

چگونه یک درخواست از مرورگر به سرور برای دریافت مقداری داده به عنوان JavaScript اشیای Json آغاز کنیم؟

چگونه سرور اشیای .NET را Serialized میکند و آن ها را به مرورگر میفرستد ؟

چگونه مرورگر JavaScript اشیای JSON را Serialized میکند و آنها را به سرور میفرستد ؟

چگونه سرور رشته های JSON را به اشیای .NET , de-Serialized میکند؟

در کنار پاسخ دادن به سوالات بالا این نمونه مثال نیز به شما نشان خواهد داد که چگونه میتوان از Session در ASP.NET MVC در خارج از کنترلر ها استفاده کرد. نمونه پروژه ی ما Solution اس مشابه زیر خواهد داشت :

Json در JQuery و MVC

بدنه های اصلی بلوک های برنامه ی ما شامل موارد زیر خواهد بود :

کلاس تعاریف اشیای .NET که همچنین میتوان از آن به عنوان قالبی برای اشیای JSON ای که در فایل Models\StudentModel.cs اجرا میشوند , استفاده کرد.

صفحه ی View در ASP.NET MVC نیز همان Index.aspx است.

این تنها صفحه ی View در رنامه های وب میباشد. تمام کذ های JavaScript سمت کاربر در این صفحه اجرا میشوند.

دو کلاس کنترلر در فولدر Controller وجود دارد. کلاس HomeController کنترلری است که Index.aspx را بارگذاری میکند. کلاس JsonOperationsController یک نقطه ی مرکزی در سمت سرور برای پردازش اشیای JSON ارسال شده از مرورگر ها و برای ارسال تمام اشیای JSON به مرورگر ها است.

کلاس StudentsRepository نیز همانند مخزن داده های برنامه با استفاده از Session state برنامه های وب عمل میکند.

این پروژه ی مثالی در ویژوال استودیوی ۲۰۱۰ و MVC 2 عرضه شده است.

ورژن jQuery آن نیز ۱.۴.۲ میباشد. برای ایجاد رابط کاربری برنامه در Index.aspx از jQuery treeview plug-in استفاده میشود.

این Plug-in برای نمایش داده های برنامه در یک ساختار درختی در مرورگر استفاده میشود.

این مقاله خواننده را مجاب میکند تا مقداری اطلاعات پایه در زمینه های MVC , jQuery و JSON داشته باشد.

اگر شما آشنایی با این مباحث ندارید میتوانید به راحتی مراجعی در این زمینه ها پیدا کنید.

ابتدا نگاهی به مدل کلاس ها در این برنامه می اندازیم و درمیابیم که داده ها بین سرور و مرورگر پاس داده میشوند.

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

کلاس های .NET model

برای پیچیده ساختن ساختار داده های متغیر بین مرورگر و سرور به میزان لازم سه کلاس .NET در فایل StudentModel.cs در حال اجراست.

using System
using System.Collections.Generic;
using System.Linq;
using System.Web;
 
namespace JsonMVC.Repositories
{
    public class Student
    {
        public string Name { get; set; }
        public IList<Class> ClassesTaken { get; set; }
    }
 
    public class Class
    {
        public string Name { get; set; }
        public IList<Exam> ExamesTaken { get; set; }
    }
 
    public class Exam
    {
        public DateTime ExamTime { get; set; }
        public string Description { get; set; }
        public int Score { get; set; }
    }
}

این سه کلاس , کلاس های Student , Class و Exam هستند. داده ی متغیر بین مرورگر و سرور لیستی از اشیای Student هستند.

هر شئ Student میتواند از چندین شئ Class با استفاده از Property عمومی ClassesTaken ارجاع گرفته باشد و همچنین هر شئ Class نیز میتواند از چندین شئ Examبا استفاده از Property عمومی ExamsTaken ارجاع گرفته باشد.

کلاس StudentRepository

برای نشان دادن آنکه Session میتواند خارج از کنترلر های MVC استفاده شود , داده های برنامه در سمت سرور در یک Session توسط کلاس StudentRepository نگهداری میشود :

using System
using System.Collections.Generic;
using System.Linq;
using System.Web;
using JsonMVC.Models;
 
namespace JsonMVC.Repositories
{
    public class StudentsRepository
    {
        public void Initialize(int NoOfStudents,
            int NoOfClasses, int NoOfExams)
        {
            List<Student> students = new List<Student>();
            Random rd = new Random();
            for (int iStudent = 0; iStudent < NoOfStudents; iStudent++)
            {
                Student aStudent = new Student();
                aStudent.Name = "Student Name No. " +
                    iStudent.ToString();
                aStudent.ClassesTaken = new List<Class>();
                for (int iClass = 0; iClass < NoOfClasses; iClass++)
                {
                    Class aClass = new Class();
                    aClass.Name = "Class No. " + iClass.ToString();
                    aClass.ExamesTaken = new List<Exam>();
                    for (int iExam = 0; iExam < NoOfExams; iExam++)
                    {
                        Exam aExam = new Exam();
                        aExam.ExamTime = System.DateTime.Now;
                        aExam.Description = "Exam No. " +
                            iExam.ToString();
                        aExam.Score
                            = Convert.ToInt16(60 + rd.NextDouble() * 40);
 
                        aClass.ExamesTaken.Add(aExam);
                    }
 
                    aStudent.ClassesTaken.Add(aClass);
                }
 
                students.Add(aStudent);
            }
 
            HttpContext.Current.Session["Students"] = students;
        }
 
        public IList<Student> GetStudents()
        {
            return (List<Student>)
                HttpContext.Current.Session["Students"];
        }
 
        public void SetStudents(IList<Student> students)
        {
            HttpContext.Current.Session["Students"] = students;
        }
    }
}

سه متد public در حال اجرا در کلاس StudentRepository هستند:

  • متد Initialize برای آغاز یک لیست از اشیای Student با مقداری داده های تولید شده ی تصادفی با توجه به پارامتر های ورودی است. لیست Student تولید شده ی تصادفی نیز پس از آن در Session State ذخیره میشود.
  • متد GetStudents لیست Student بازیابی شده از Session را باز میگرداند.
  • متد SetStudents لیستی از Student را به عنوان ورودی دریافت میکند و آن را در Session ذخیره میکند.

کنترلر Home

Home Controller همان کنترلر MVC میباشد که برای بارگذاری تک صفحه ی View برنامه (Index.aspx) به کار میرود.

using System
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Collections.Specialized;
using System.Configuration;
 
namespace JsonMVC.Controllers
{
    public class HomeController : Controller
    {
        [HttpGet]
        public ActionResult Index()
        {
            NameValueCollection appSettings
                = ConfigurationManager.AppSettings;
 
            ViewData["ApplicationTitle"] = 
                  appSettings["ApplicationTitle"];
            return View();
        }
    }
}

آن تیتر پیکربندی شده ی برنامه را به Web.config میبرد و آن را به Index.aspx از فرم ViewData پاس میدهد.

کنترلر JsonOperations

کنترلر JsonOperationsController یکی از نقاط کانونی در این مقاله است.

تمام عملیات های مرتبط با سرور برای ارتباط با مرورگر وب با استفاده از JSON در اینجا اجرا میشوند.

using System
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using JsonMVC.Models;
using JsonMVC.Repositories;
 
namespace JsonMVC.Controllers
{
    public class JsonOperationsController : Controller
    {
        // Utility function to add a exam to each class for a list of students
        private void AddAnExamToStudents(IList<Student> students, string updateSource)
        {
            Random rd = new Random();
            foreach (Student aStudent in students)
            {
                foreach (Class aClass in aStudent.ClassesTaken)
                {
                    IList<Exam> exames = aClass.ExamesTaken;
                    Exam aExam = new Exam();
                    aExam.ExamTime = System.DateTime.Now;
                    aExam.Description = "Exam No. " +
                        exames.Count.ToString()
                        + " by " + updateSource;
                    aExam.Score
                        = Convert.ToInt16(60 + rd.NextDouble() * 40);
 
                    exames.Add(aExam);
                }
            }
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult GetStudents(int NoOfStudents,
            int NoOfClasses, int NoOfExams)
        {
            StudentsRepository repository = new StudentsRepository();
            repository.Initialize(NoOfStudents, NoOfClasses, NoOfExams);
 
            return Json(repository.GetStudents());
        }
 
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult AddAnExamByJson(IList<Student> students)
        {
            StudentsRepository repository = new StudentsRepository();
            repository.SetStudents(students);
 
            AddAnExamToStudents(students, "json");
            return Json(students);
        }
 
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult AddAnExamBySession()
        {
            StudentsRepository repository = new StudentsRepository();
            IList<Student> students = repository.GetStudents();
 
            AddAnExamToStudents(students, "session");
            return Json(students);
        }
    }
}

سه متد عمومی ActionResult در زیر آورده شده اند :

  1. متد GetStudents یک ورودی عدد صحیح دریافت میکند و لیستی از اشیای Student را به مرورگر بازمیگرداند.
  2. متد AddAnExamByJson لیستی از اشیای Student را از مرورگر میگیرد و یک شئ Exam به هر شئ کلاس دریافت شده توسط Student اضافه میکند. لیست را درون Session ذخیره میکند و سپس آن لیست از اشیای Student را به مرورگر باز میگرداند.
  3. متد AddAnExamBySession هیچ پارامتری نمیگیرد. بلکه لیستی از اشیای Student را از Session با استفاده از کلاس StudentsRepository دریافت میکند. به هر کلاس دریافت شده توسط Student یک شئ Exam اضافه میکند و سپس لیست اشیای Student را به مرورگر باز میگرداند.

هر سه متد اشیای JSON را با استفاده از JsonResult به مرورگر میفرستند.

هر یک از آنها یکی از سه مورد را در هنگام دریافت داده از مرورگر نشان میدهد.

AddAnExanBySession هیچ داده ای از مرورگر دریافت نمیکند.

GetStudents یک داده ی ورودی اسکالر دریافت میکند.

AddAnExamByJson نیز لیستی از اشیای پیچیده را دریافت میکند.

MVC View Index.aspx

کدی که با متد ها در JsonOperationsController در سمت کاربر ارتباط دارد در Index.aspx اجرا میشود :

<%@ Page Language="C#
         Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Working on Json Arrays in MVC</title>
    <link rel="SHORTCUT ICON"
        href="<%= Url.Content("~/Content/Images/rubik.ico") %>" />
    <link rel="stylesheet"
        href="<%= Url.Content("~/Content/Styles/Site.css") %>"
        type="text/css" />
    <link rel="stylesheet"
        href="<%= Url.Content("~/Content/Styles/jquery.treeview.css") %>"
        type="text/css" />
     
    <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22%3C%25%3D%20Url.Content(%22~%2FScripts%2Fjquery-1.4.2.min.js%22)%20%25%3E%22%0A%20%20%20%20%20%20%20%20type%3D%22text%2Fjavascript%22%3E%0A%20%20%20%20%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="script" title="script" />
    <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22%3C%25%3D%20Url.Content(%22~%2FScripts%2Fjquery.treeview.js%22)%20%25%3E%22%0A%20%20%20%20%20%20%20%20type%3D%22text%2Fjavascript%22%3E%0A%20%20%20%20%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="script" title="script" />
 
    <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20type%3D%22text%2Fjavascript%22%20language%3D%22javascript%22%3E%0A%20%20%20%20%20%20%20%20var%20GetStudentsURL%0A%20%20%20%20%20%20%20%20%20%20%20%20%3D%20'%3C%25%3A%20Url.Action(%22GetStudents%22%2C%20%22JsonOperations%22)%20%25%3E'%3B%0A%20%20%20%20%20%20%20%20var%20AddAnExamBySessionURL%0A%20%20%20%20%20%20%20%20%20%20%20%20%3D%20'%3C%25%3A%20Url.Action(%22AddAnExamBySession%22%2C%20%22JsonOperations%22)%20%25%3E'%3B%0A%20%20%20%20%20%20%20%20var%20AddAnExamByJsonURL%0A%20%20%20%20%20%20%20%20%20%20%20%20%3D%20'%3C%25%3A%20Url.Action(%22AddAnExamByJson%22%2C%20%22JsonOperations%22)%20%25%3E'%3B%0A%20%20%20%20%20%20%20%20var%20StudentJson%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20var%20NoOfStudents%20%3D%203%2C%20NoOfClasses%20%3D%201%2C%20NoOfExams%20%3D%200%3B%0A%20%0A%20%20%20%20%20%20%20%20var%20prependZero%20%3D%20function%20(v)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20v%20%3D%20v.toString()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20(v.length%20%3D%3D%201)%20%3F%20%220%22%20%2B%20v%20%3A%20v%3B%0A%20%20%20%20%20%20%20%20%7D%3B%0A%20%0A%20%20%20%20%20%20%20%20var%20dateDeserialize%20%3D%20function%20(dateStr)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20dt%20%3D%20new%20Date(parseInt(dateStr.substr(6)))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20prependZero((dt.getMonth()%20%2B%201))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%20%22%2F%22%20%2B%20prependZero(dt.getDate())%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%20%22%2F%22%20%2B%20dt.getFullYear()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%20%22%20%22%20%2B%20prependZero(dt.getHours())%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%20%22%3A%22%20%2B%20prependZero(dt.getMinutes())%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%20%22%3A%22%20%2B%20prependZero(dt.getSeconds())%3B%0A%20%20%20%20%20%20%20%20%7D%3B%0A%20%0A%20%20%20%20%20%20%20%20var%20FixDateinJson%20%3D%20function%20(JsonStudents)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24.each(JsonStudents%2C%20function%20(i%2C%20JsonStudent)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24.each(JsonStudent.ClassesTaken%2C%20function%20(i%2C%20JsonClass)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24.each(JsonClass.ExamesTaken%2C%20function%20(i%2C%20JsonExam)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20JsonExam.ExamTime%20%3D%20dateDeserialize(JsonExam.ExamTime)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20JsonStudents%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%0A%20%20%20%20%20%20%20%20var%20buildStudentTree%20%3D%20function%20(students)%20%7B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20createTextNode%20%3D%20function%20(text)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20span%20%3D%20document.createElement(%22span%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.setAttribute(%22style%22%2C%20%22margin-left%3A%202px%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20tx%20%3D%20document.createTextNode(text)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.appendChild(tx)%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20span%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20root%20%3D%20document.createElement(%22ul%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20root.id%20%3D%20%22StudentTreeRoot%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20root.setAttribute(%22style%22%2C%20%22margin%3A%2015px%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20root.className%20%3D%20%22filetree%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24.each(students%2C%20function%20(i%2C%20student)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20studentNode%20%3D%20document.createElement(%22li%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FstudentNode.className%20%3D%20%22closed%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20span%20%3D%20document.createElement(%22span%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.className%20%3D%20%22folder%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.appendChild(createTextNode(student.Name))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20studentNode.appendChild(span)%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20classesNode%20%3D%20document.createElement(%22ul%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24.each(student.ClassesTaken%2C%20function%20(i%2C%20aClass)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20classNode%20%3D%20document.createElement(%22li%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FclassNode.className%20%3D%20%22closed%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span%20%3D%20document.createElement(%22span%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.className%20%3D%20%22folder%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.appendChild(createTextNode(aClass.Name))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20classNode.appendChild(span)%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20examesNode%20%3D%20document.createElement(%22ul%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20examesNode.className%20%3D%20%22folder%22%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24.each(aClass.ExamesTaken%2C%20function%20(i%2C%20aExam)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20examNode%20%3D%20document.createElement(%22li%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FexamNode.className%20%3D%20%22closed%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span%20%3D%20document.createElement(%22span%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.className%20%3D%20%22folder%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.appendChild(createTextNode(aExam.Description))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20examNode.appendChild(span)%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20detailNode%20%3D%20document.createElement(%22ul%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20examTime%20%3D%20document.createElement(%22li%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span%20%3D%20document.createElement(%22span%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.className%20%3D%20%22file%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.appendChild(createTextNode(aExam.ExamTime))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20examTime.appendChild(span)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20detailNode.appendChild(examTime)%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20score%20%3D%20document.createElement(%22li%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span%20%3D%20document.createElement(%22span%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.className%20%3D%20%22file%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20span.appendChild(createTextNode(aExam.Score))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20score.appendChild(span)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20detailNode.appendChild(score)%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20examNode.appendChild(detailNode)%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20examesNode.appendChild(examNode)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%20%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20classNode.appendChild(examesNode)%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20classesNode.appendChild(classNode)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20studentNode.appendChild(classesNode)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20root.appendChild(studentNode)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%24(%22%23StudentTree%22).html(%22%22).append(root)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24(%22%23StudentTreeRoot%22).treeview()%3B%0A%20%20%20%20%20%20%20%20%7D%3B%0A%20%0A%20%20%20%20%20%20%20%20%24(document).ready(function%20()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24(%22%23StudentTree%22).html(%22%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24.ajax(%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cache%3A%20false%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20type%3A%20%22POST%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20async%3A%20false%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20url%3A%20GetStudentsURL%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%20%22%2F%3FNoOfStudents%3D%22%20%2B%20NoOfStudents%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%20%22%26NoOfClasses%3D%22%20%2B%20NoOfClasses%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%20%22%26NoOfExams%3D%22%20%2B%20NoOfExams%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dataType%3A%20%22json%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20success%3A%20function%20(students)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20StudentJson%20%3D%20FixDateinJson(students)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20buildStudentTree(StudentJson)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%24(%22%23btnAddAnExamJson%22).click(function%20()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24(%22%23StudentTree%22).html(%22Loading%20...%22)%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24.ajax(%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cache%3A%20false%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20type%3A%20%22POST%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20url%3A%20AddAnExamByJsonURL%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20contentType%3A%20'application%2Fjson'%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dataType%3A%20%22json%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20data%3A%20JSON.stringify(StudentJson)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20success%3A%20function%20(students)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20StudentJson%20%3D%20FixDateinJson(students)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20buildStudentTree(StudentJson)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%24(%22%23btnAddAnExamSession%22).click(function%20()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24(%22%23StudentTree%22).html(%22Loading%20...%22)%3B%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24.ajax(%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cache%3A%20false%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20type%3A%20%22POST%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20url%3A%20AddAnExamBySessionURL%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dataType%3A%20%22json%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20success%3A%20function%20(students)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20StudentJson%20%3D%20FixDateinJson(students)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20buildStudentTree(StudentJson)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="script" title="script" />
</head>
 
<body>
    
<div id="TitleContainer"><%= ViewData["ApplicationTitle"]%></div>

    
<div id="MainContainer">
        
<div id="StudentTree"></div>

        
<div id="ButtonContainer">
            <button id="btnAddAnExamSession" class="ButtonStyle">
                Add an exam to students using session</button>
            <button id="btnAddAnExamJson" class="ButtonStyle">
                Add an exam to students by posting Json</button>
        </div>

    </div>

</body>
</html>

بخش HTML از Index.aspx بسیار ساده است. اما باید به اجزای زیر توجه داشته باشید :

دکمه ی کنترلی btnAddAnExamSession . این دکمه فراخوانی یک jQuery Ajax را به متد AddAnExamBySession در JsonOperationsController فعال میکند.

دکمه ی کنترلی btnAddAnExamJson. این دکمه فراخوانی یک jQuery Ajax را به متد AddAnExamJson در JsonOperationsController فعال میکند.

Div مربوط به StudentTree مکانی است که ما لیست اشیای Student دریافت شده از سرور را با استفاده از JQuery treeview plug-in نمایش میدهیم.

اکثریت منطق Index.aspx در JavaScript با jQuery اجرا میشود :

در رویداد $(document),ready() یک فراخوانی Ajax همگام بر متد GetStudent در JsonOperationsController با استفاده از jQuery اتفاق می افتد.

لیست بازگشتی از اشیای Student نیز در حال حاضر de-Serialized به آرایه ای از اشیای JSON توسط jQuery شده است.

این آرایه ی JSON سپس در متغیر های جهانی JavaScript , StudnetJson ذخیره میشود تا بعدا مورد پردازش قرار داده شوند.

همچنین توسط تابع buildStudentTree برای ساخت یک TreeView استفاده میشود.

Treeview در بالای Student Tree div با استفاده از jQuery treeview plug-in ساخته میشود.

در رویداد کلیک دکمه ی btnAddAnExamSession یک رویداد فراخوانی Ajax همگام بر متد AddAnExamBySession در JsonOperationsController ایجاد میشود.

سپس treeview توسط لیست دانش آموزان دریافت شده ی اخیر به روز میشود.

در رویداد کلیک دکمه ی btxAddAnExam یک رویداد فراخوانی Ajax همگام بر متد AddAnExamByJson در JsonOperationsController ایجاد میشود. سپس treeview توسط لیست دانش آموران دریافت شده ی اخیر به روز میشود.

کد نشان داده شده JavaScript در Index.aspx مانند زیر است :

فراخوانی های jQuery AJAX میتوانند همگام یا غیرهمگام باشند.

پیش فرض آن فراخوانی ناهمگام است. اما شما میتوانید با مشخص کردن مقدار async:false آن را همگام نمایید.

ایجاد یک فراخوانی jQuery AJAX همگام در هدف این مقاله نیست اما ممکن است در شرایط خاصی مفید واقع شود.

هر یک از سه فراخوانی jQuery AJAX یکی از سه مورد را نشان میدهد که شامل پاس ندادن داده ای به سرور , پاس دادن داده ی اسکالر به سرور و پاس دادن آرایه ای از اشیای JSON به سرور میباشد.

افزودنی ها به پیش فرض MVC Model Binder

حال ما کد های هر دو سمت کاربر و سرور را تمام کرده ایم تا چگونگی کار بر روی اشیای JSON با jQuery و MVC را نشان دهیم.

برای اکثر بخش ها ممکن است درست کار کند اما پیش فرض MVC ModelBinder آرایه ی اشیای JSON را de-Serialized نمیکند.

این به آن معناست که ما موفق به ارسال آرایه ای Student اشیای JSON به متد AddAnExamByJson نخواهیم شد و برای حل این مشکل باید تغییراتی در فایل Global.aspx.cs ایجاد کنیم:

using System
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
 
namespace JsonMVC
{
    public class JsonModelBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext,
            ModelBindingContext bindingContext)
        {
            // If the request is not of content type "application/json"
            // then use the default model binder.
            if (!IsJSONRequest(controllerContext))
            {
                return base.BindModel(controllerContext, bindingContext);
            }
 
            // Get the JSON data posted
            var request = controllerContext.HttpContext.Request;
            var jsonStringData =
                new System.IO.StreamReader(request.InputStream).ReadToEnd();
 
            return new System.Web.Script.Serialization.JavaScriptSerializer()
                .Deserialize(jsonStringData, bindingContext.ModelMetadata.ModelType);
        }
 
        private bool IsJSONRequest(ControllerContext controllerContext)
        {
            var contentType = controllerContext.HttpContext.Request.ContentType;
            return contentType.Contains("application/json");
        }
    }
 
    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
            routes.MapRoute("Default", "{controller}/{action}/{id}",
                new
                {
                    controller = "Home",
                    action = "Index",
                    id = UrlParameter.Optional
                });
        }
 
        protected void Application_Start()
        {
            // Set the model binder
            ModelBinders.Binders.DefaultBinder = new JsonModelBinder();
            AreaRegistration.RegisterAllAreas();
            RegisterRoutes(RouteTable.Routes);
        }
 
        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            // It is OK to cache the jQuery library, images, etc.
            string FilePath = HttpContext.Current.Request.FilePath;
            if (FilePath.Contains("jquery-1.4.2.min.js") ||
                FilePath.Contains("rubik.ico") ||
                FilePath.Contains(".jpg") ||
                FilePath.Contains(".css"))
                return;
 
            HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            HttpContext.Current.Response.Cache.SetNoStore();
        }
    }
}

در Global.aspx.cs یک کلاس JsonModelBinder در حال اجراست.

متد BindModel در این کلاس ابتدا Contenct type را در درخواست HTTP چک میکند.

اگر این application/json باشد , JavaScriptSerializer برای de-Serialize کردن محتوای ارسالی استفاده میشود.

در غیر اینصورت پیش فرض Serializer استفاده میشود تا رفتار طبیعی MVC را تغییر ندهد.

اگر مایل بودید میتوانید آن را بررسی بیشتری کنید.

اجرای برنامه

حال ما آماده ی تست اجرای برنامه هستیم.

در حالی که Index.aspx در حال بارگذاری شدن است , یک فراخوانی jQuery AJAX همگام برای دریافت لیستی از دانش آموران اشیای JSON برای سرور با فراخوانی متد GetStudents در JsonOperationsController انجام میشود.

سپس لیست دانش آموزان در یک treeview توسط jQuery treeview plug-in نمایش داده میشود:

 استفاده از Jsonسپس میتوانیم بر روی دکمه های Add an exam to students by posting JSON و Add an exam to students using session کلیک کنیم.

هر کلیک دکمه یک شمارنده فراخوانی jQuery AJAX ناهمگام متناسب با متد خود یعنی AddAnExamByJson یا AddAnExamBySession در JsonOperationsController خواهد داشت.

Treeview با محتوای جدید به روز میشود :

 چگونه از JSON استفاده کنیم؟از تصویر بالا میتوانیم ببینیم که اشیای JSON با موفقیت به JsonOperationsController ارسال شده اند و مدیریت Session State توسط کلاس StudentRepository به خوبی انجام میشود.

جمع بندی

برای جمع بندی من به سوالاتی که در ابتدای مقاله پرسیده شده بود پاسخ خواهم داد :

  •  چگونه یک درخواست از مرورگر به سرور برای دریافت مقداری داده به عنوان JavaScript اشیای Json آغاز کنیم؟

پاسخ : متد jQuery AJAX میتواند فراخوانی به یک کنترلر MVC را برای درخواست داده به عنوان اشیای JavaScript JSON آغاز کند.

فراخوانی های jQuery AJAX میتواند هم همگام و هم غیرهمگام باشد.

  •  چگونه سرور اشیای .NET را Serialized میکند و آن ها را به مرورگر میفرستد ؟

پاسخ : در متد MVC Controller میتوان به راحتی یک JsonResult به عنوان یک ActionResult برگرداند. چارچوب MVC امور Serialization را بر عهده دارد.

سینتکس نیز به سادگی return Json در جایی که شئ از نوع .NET است که نیاز به Serialized و ارسال به مرورگر را دارد.

  •  چگونه مرورگر JavaScript اشیای JSON را Serialized میکند و آنها را به سرور میفرستد ؟

پاسخ : متد jQuery AJAX به مرورگر اجازه ی ارسال اشیای JSON به یک MVC Controller در سرور را میدهد.

  • چگونه سرور رشته های JSON را به اشیای .NET , de-Serialized میکند؟

پاسخ : MVC ModelBinder پیش فرض آرایه های اشیای JSON را de-Serialized نمیکند. اگر شما میخواهید متد MVC Controller همواره اشیای JSON را به درستی دریافت کند میتوانید با مقداری جستجو در این باره متد مناسبی پیدا کنید.

زمانی که از یک MVC ModelBinder تغییر داده شده استفاده میکنید نیاز دارید تا نوع محتوا را به عنوان “application/json” مشخص کنید و از JSON.stringfy برای Serialize مردن اشیای JSON زمانی که در حال فراخوانی jQuery AJAX هستید , استفاده کنید.

نکات قابل توجه

این مقاله از یک مثال ساده برای پاسخ دادن به برخی از سوالات ساده و متداول که ممکن است در حال کار با JSON در jQuery و MVC برایتان پیش بیاید , میباشد.

در کنار پاسخ دادن به این سوالات , این مقاله همچنین نشان میدهد که چگونه میتوان از Session State در خارج از MVC Controller استفاده کرد و با ارائه ی مثالی استفاده از jQuery treeview plug-in برای تولید داینامیکی treeview از داده ها در اشیای JSON را توضیح میدهد.

راه های زیادی برای تغییر داده ها با JSON بین مرورگر و سرور وجود دارد.

متدی که در این مقاله توضیح داده شد تنها یکی از این راه حل ها را نشان میدهد. در زمان کار با jQuery و MVC به عقیده ی من متد معرفی شده در این مقاله آسان ترین متد بود.

امیدوارم از این مطلب استفاده مفید داشته باشید. لطفا نظرات و پیشنهادات خودتان را با من در میان بگذارید.
با تشکر

داریوش فرخی

داریوش فرخی هستم از سال 92 شروع به یادگیری برنامه نویسی و از سال 93 در بخش برنامه نویسی و تولید محتوای سایت mspsoft.com مشغول هستم. فعالیتم نیز بیشتر در زمینه های برنامه نویسی با سی شارپ و asp.net بوده است. اوقات فراغتم را هم غالبا با تماشای فیلم یا بازی های کامپیوتری پر میکنم .

نوشته‌های مرتبط

دیدگاه‌ها

*
*

این سایت از اکیسمت برای کاهش هرزنامه استفاده می کند. بیاموزید که چگونه اطلاعات دیدگاه های شما پردازش می‌شوند.

    مسعود پاسخ

    اینجا از لیست استفاده شده باید Generic رو حذف کنید

    zahra_no پاسخ

    لینک دانلود چرا نیست؟

      مسعود شریفی پاسخ

      به صورت مقاله ارائه شده.