ساخت یک Single page Application توسط ASP.NET MVC

Single page Application

خب بالاخره در پله آخر “MVC 5 را در ۷ روز یاد بگیرید” قرار گرفتیم.در این روز یک Single page Application میسازیم. من یقین دارم که از تمام روزهای پیش لذت بردید و مطالب خوبی یاد گرفتید.

فهرست Single page Application

  • آنچه در جلسه آخر یاد خواهیم گرفت
  • تمرین سی و یکم – ساماندهی پروژه
    • پرسش و پاسخ در تمرین سی و یکم
  • تمرین سی و دوم – ایجاد Single page Application بخش اول – setup
    • Area ها چی هستند؟
    • پرسش و پاسخ در تمرین سی و دوم
  • تمرین سی و سوم – ایجاد Single Page Application بخش دوم – نمایش کارمندان
  • تمرین سی و چهارم – ایجاد Single Page Application بخش سوم – ایجاد Employee
    • قدم بعدی چیست؟
    • برنامه ریزی
      • سفری برای پیدا کردن راه حل
        • بررسی مشکل
        • راه حل – یک نوع داده ای مشترک
        • مشکل – انواع داه ای پیچیده چطور؟
        • راه حل – یک استاندارد مشترک فرمت داده ها
        • مشکل – مشکلات فرمت XML
        • راه حل – JSON
      • برگشت به تمرین
      • پرسش و پاسخ در تمرین سی و چهارم
    • تمرین سی و پنجم – ایجاد Single Page Application بخش چهارم – آپلود چندگانه
    • جمع بندی

تمرین سی و یکم – ساماندهی پروژه

درواقع در این تمرین هیچ امکان جدیدی به پروژه اضافه نخواهیم کرد. این تمرین فقط پروژه را ساختاریافته تر و سیستماتیک می کند.

گام ا: ایجاد فولدرهای Solution

روی Solution راست کلیک کرده و گزینه Add>> New Solution Folder را انتخاب می کنیم.

 نینجای MVC

نام آن را “View And Controller” می گذاریم.

همین مرحله را سه بار دیگر نیز تکرار می کنیم و فولدرهایی شبیه به این با نام های “Model”، “ViewModel” و “Data Access Layer” ایجاد می کنیم.

 نینجای MVC

گام ۲: ایجاد Data Access Layer project

روی فولدر Data Access Layer راست کلیک کرده و یک class library جدید به نام “DataAccessLayer” ایجاد می کنیم.

 ساخت Single page Application

گام ۳: ایجاد Business Layer و Business Entities پروژه

دو class library جدید در فولدر Model ایجاد کرده و نام آن ها را به ترتیب “BusinessLayer” و “BusinessEntities” می گذاریم.

گام ۴: ایجاد ViewModel project

یک class library جدید نیز در فولدر ViewModel به نام ViewModel ایجاد می کنیم.

گام ۵: اضافه کردن رفرنس ها

روی هر یک از پروژه ها راست کلیک کرده، Add>> References را انتخاب کرده و به ترتیب رفرنس های زیر را اضافه می کنیم.

  1. برای DataAccessLayer، BusinessEntities را انتخاب می کنیم.
  2. برای BusinessLayer، DataAccessLayer و BusinessEntities را انتخاب می کنیم.
  3. برای MVC WebApplication نیز BusinessLayer، BusinessEntities و ViewModel را انتخاب می کنیم.
  4. برای BusinessEntities نیز ComponentModel.DataAnnotation را انتخاب خواهیم کرد.

گام ۶: تنظیم پروژه

  1. از فولدر DataAccessLayer، فایل cs را در Class library project ای که به تازگی با نام DataAccessLayer ایجاد کردیم، کپی می کنیم. ساخت Single page Application
  2. فولدر DataAccessLayer را از پروژه MVC(WebApplication1) حذف می کنیم.
  3. فایل های cs، UserDetails.cs و UserStatus.cs را از فولدر Model پروژه MVC به BusinessEntities class library کپی می کنیم.
  4. cs را از فولدر Model به BusinessLayer class library کپی می کنیم.
  5. فولدر Model را از پروژه MVC حذف می کنیم.
  6. تمام کلاس های ViewModels در پروژه MVC را به ViewModel Class library کپی می کنیم.
  7. فولدر ViewModels را از پروژه MVC حذف می کنیم.
  8. پروژه MVC(WebApplication1) را به فولدر “View And Controller” انتقال می دهیم.

گام ۷: Build کردن پروژه

گزینه Build را از منو و سپس Build Solution را انتخاب می کنیم.

پیغام خطاهای زیر رخ خواهد داد:

 ساخت Single page Application

گام ۸: از بین بردن خطاها

  1. رفرنس Web را به ViewModel اضافه می کنیم.
  2. با استفاده از Nuget manager، Entity framework را در DataAccessLayer و BusinessLayer نصب می کنیم.(اگر در استفاده از Nuget Manager دچار مشکل شدید، می توانید به روز سوم سری بزنید. )

نکته: Entity framework به این دلیل در BusinessLayer لازم است که BusinessLayer به طور مستقیم به DataAccessLayer متصل می شود. به عنوان یک معماری کارآمد BusinessLayer نباید به طور مستقیم به DataAccessLayer متصل شود. این مورد را می توانیم با Repository pattern انجام دهیم. Repository pattern کاملا از حوزه بحث این سری آموزشی جداست.

  1. Entity framework را از پروژه MVC حذف می کنیم.
  • روی پروژه MVC راست کلیک کرده و Mange Nuget packages را انتخاب می کنیم.
  • “Installed Packages” را از بخش سمت چپ “Manage Nuget Packages” انتخاب می کنیم.
  • در بخش سمت راست، همه پکیج های نصب شده نمایش داده می شوند، روی Entity framework کلیک کرده و روی Uninstall کلیک می کنیم.

گام ۹: Build کردن Solution

پیغام خطاهای زیر را مشاهده خواهید کرد:

 آموزش MVC در هفت روز

گام ۱۰: از بین بردن خطاها

حالا نه رفرنس SalesERPDAL را در پروژه MVC داریم و نه رفرنس Entity framework. اضافه کردن این رفرنس ها راهکار خوبی نیست. به عنوان بهترین راهکار، نباید Controller به طور مستقیم به Data Access Layer متصل شود.

  1. کلاس جدیدی با نام DatabaseSettings با یک متد استاتیک به نام SetDatabase در DataAccessLayer ایجاد می کنیم.
using System.Data.Entity;

using WebApplication1.DataAccessLayer;

namespace DataAccessLayer

{

    public class DatabaseSettings

    {

        public static void SetDatabase()

        {

            Database.SetInitializer(new DropCreateDatabaseIfModelChanges<SalesERPDAL>());<saleserpdal>

        }

    }     

}

</saleserpdal>

کلاس جدیدی به نام BusinessSetting با یک متد استاتیک به نام SetBusiness در BusinessLayer ایجاد می کنیم.

using DataAccessLayer;

namespace BusinessLayer
{
    public class BusinessSettings
    {
        public static void SetBusiness()
        {
            DatabaseSettings.SetDatabase();
        }
    }
}

هر دو دستور نوشته شده در asax را که باعث خطا شده بودند حذف می کنیم، همچنین دستور Database.SetInitializer را نیز حذف می کنیم. تابع BusinessSettings.SetBusinee را به صورت زیر فراخوانی می کنیم:

using BusinessLayer;
.
.
.
BundleConfig.RegisterBundles(BundleTable.Bundles);
BusinessSettings.SetBusiness();

اگر دوباره برنامه را Build کنیم، این بار بدون خطا انجام خواهد شد.

پرسش و پاسخ در تمرین سی و یکم:

Solution Folder چیست؟

فولدرهای منطقی هستند که در واقع در هارد فیزیکی ما ایجاد نخواهند شد. تنها برای نظم بخشیدن به Solution به کار می روند.

تمرین سی و دوم – ایجاد Single Page Application بخش اول، setup

خب در این تمرین، قرار نیست تغییری در Controllerها و Viewهای موجود اعمال کنیم. Controllerها و Viewهای جدیدی برای این تمرین ایجاد خواهیم کرد. دلایل این کار:

  1. امکانات موجود را دست نخورده نگه می داریم تا درنهایت بتوانید نسخه اولیه را با نسخه single page مقایسه کرده و مطالب را بهتر درک کنید.
  2. پیاده سازی و بررسی یک مفهوم دیگر در Net MVC به نام Area

همان طور که گفتیم، برای این تمرین Controllerهای جدید، View و ViewModel های جدید را از ابتدا ایجاد می کنیم.

فقط موارد زیر قابلیت استفاده دوباره دارند:

  • Layer Business موجود
  • Data Access Layer موجود
  • Business entities موجود
  • Authentication و Exception filters
  • FooterViewModel
  • cshtml

گام ۱: ایجاد یک Area جدید

روی پروژه راست کلیک کرده و Add>>Area را انتخاب می کنیم. یک پنجره popup باز می شود. نام آن را SPA گذاشته و روی Add کلیک می کنیم.

 آموزش MVC در هفت روز

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

 آموزش MVC در هفت روز

واضح است که فولدر Model در اینجا نیاز نیست، پس آن را حذف می کنیم.

Area چیست؟

Area راهی برای پیاده سازی ماژول ها در ASP.Net MVC است. هر پروژه از چندین ماژول تشکیل شده است. به طور مثال – ماژول Account، ماژول Costumer Relationship، ماژول Payment getway و…

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

حال این فولدرها یک مشکل بزرگ در ASP.Net MVC هستند.

فرض کنید برای پیاده سازی ماژول در ASP.Net MVC از فولدرهای ساده استفاده کنیم.

  • حال DataAccessLayer، BusinessLayer و ViewModels هیچ مشکلی ایجاد نمی کنند. کلاس های ساده ای هستند که می توان آن ها را هر جایی نگه داشت.
  • Controllerها – آن ها را نمی توان هر جایی نگه داشت. این ها باید در فولدر Controller نگه داری شوند. اما این، مشکل چندان بزرگی ایجاد نمی کند چرا که از MVC 4 به بعد محدودیت روی محل Controllerها برداشته شد. بنابراین حالا می توانیم آن ها را هرجایی که بخواهیم نگه داری کنیم.
  • Viewها – متاسفانه برای View این امکان وجود ندارد.همه Viewها باید در فولدر “~/Views/ControllerName” یا “~/Views/Shared” قرار بگیرند.

این جاست که نقش Area مشخص می شود.

گام ۲: ایجاد ViewModelهای موردنیاز

کلاس جدیدی به نام SPA در ViewModel class library project ایجاد می کنیم و ViewModelای به نام MainViewModel به صورت زیر می سازیم:

using WebApplication1.ViewModels;
namespace WebApplication1.ViewModels.SPA
{
    public class MainViewModel
    {
        public string UserName { get; set; }
        public FooterViewModel FooterData { get; set; }//New Property
    }
}

گام ۳: ایجاد Index action method

فضاهای نام زیر را در MainController قرار می دهیم.

using WebApplication1.ViewModels.SPA;
using OldViewModel=WebApplication1.ViewModels;

حال یک action method به نام Index در MainController ایجاد می کنیم.

public ActionResult Index()
{
    MainViewModel v = new MainViewModel();
    v.UserName = User.Identity.Name;
    v.FooterData = new OldViewModel.FooterViewModel();
    v.FooterData.CompanyName = "StepByStepSchools";//Can be set to dynamic value
    v.FooterData.Year = DateTime.Now.Year.ToString();
    return View("Index", v);
}

همان طور که مشاهده می کنید، یک alias به نام OldViewModels برای فضای نام WebApplication1.ViewModels اضافه کردیم. حال می توانیم به جای نوشتن WebApplication1.ViewModels.ClassName به سادگی از OldViewModel.ClassName استفاده کنیم.

گام ۴: ایجاد Index View

View مربوط به متد بالا را به صورت زیر ایجاد می کنیم.

@using WebApplication1.ViewModels.SPA
@model MainViewModel
<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Employee Single Page Application</title>

گام ۵: تست و اجرای برنامه

کلید F5 را فشار داده و برنامه را اجرا می کنیم. فرایند ورود را کامل کرده و متد Index در MainController می رویم.

Single page Application

پرسش و پاسخ در تمرین سی و دوم:

چرا کلمه کلیدی SPA قبل از نام Controller نیاز است؟

زمانی که یک Area به ASP.Net MVC Application اضافه می کنیم، ویژوال استودیو یک فایل به نام [AreaName]AreaRegistration.cs ایجاد می کند، شامل یک کلاس که از AreaRegistration ارث بری می کند. این کلاس property به نام AreaName و متد RegisterArea را تعریف می کند، که اطلاعات route مربوط به Area جدید را ثبت می کند.

در مثال ما، این فایل را می توان با نام SpaAreaRegistration.cs پیدا کرد که در فولدر “~/Areas/Spa” قرار خواهد گرفت. متد RegisterArea در کلاس SpaAreaRegistration.cs شامل کد زیر می باشد:

context.MapRoute(
                "SPA_default",
                "SPA/{controller}/{action}/{id}",
                new { action = "Index", id = UrlParameter.Optional }
            );

به این دلیل است که وقتی Controller به Area می آید، کلمه کلیدی SPA قبل از آن قرار می گیرد.

متد RegisterArea در کلاس SPAAreaRegistration چگونه فراخوانی می شود؟

فایل global.asax را باز می کنیم، در خط های اولیه متد Application_Start چیزی شبیه به خط زیر خواهیم دید:

AreaRegistration.RegisterAllAreas();

متد RegisterAllAreas تمام typeهای موجود در دامنه برنامه را که از AreaRegistration ارث بری می کنند را یافته و متد RegisterArea هر یک را فراخوانی می کند.

آیا می توان متدهای MainController را بدون استفاده از SPA فراخوانی کرد؟

اجازه دهید این سوال را ساده تر کنیم.

سوال این است: آیا این URL “localhost:8870/Main/Index” کار می کند؟

پاسخ بله است.

کلاس AreaRegistration یک route جدید ایجاد می کند اما نمی تواند routeهای دیگر را حذف کند. Route تعریف شده در کلاس RouteConfig به درستی کار می کند. همان طور که پیش از این گفتیم، هیچ محدودیتی در محل قرارگیری Controller وجود ندارد. از این رو، کار خواهد کرد اما خروجی به درستی نمایش داده نخواهد شد چرا که نمی تواند View را بیابد. پیشنهاد می کنم برنامه خود را اجرا کرده و آن را امتحان کنید.

تمرین سی و سوم – ایجاد Single page application بخش دوم، نمایش کارمندان

گام ۱: ایجاد ViewModel برای نمایش کارمندان موجود

کلاس های ViewModel جدیدی به نام EmployeeViewModel و EmployeeListViewModel در فولدر SPA موجود در ViewModel class library ایجاد می کنیم.

namespace WebApplication1.ViewModels.SPA
{
    public class EmployeeViewModel
    {
        public string EmployeeName { get; set; }
        public string Salary { get; set; }
        public string SalaryColor { get; set; }
    }
}

namespace WebApplication1.ViewModels.SPA
{
    public class EmployeeListViewModel
    {
        public List<employeeviewmodel> Employees { get; set; }
    }
}
</employeeviewmodel>

نکته: هر دو ViewModel ایجاد شده دقیقا مانند ViewModelهایی است که برای برنامه غیر SPA ایجاد شده بودند. تنها تفاوت آن ها این است که این بار BaseViewModel نیاز نیست.

گام ۲: ایجاد EmployeeList Index

به صورت زیر، Action method جدیدی به نام EmployeeList در MainController ایجاد می کنیم.

public ActionResult EmployeeList()
{
    EmployeeListViewModel employeeListViewModel = new EmployeeListViewModel();
    EmployeeBusinessLayer empBal = new EmployeeBusinessLayer();
    List<employee> employees = empBal.GetEmployees();

    List<employeeviewmodel> empViewModels = new List<employeeviewmodel>();

    foreach (Employee emp in employees)
    {
        EmployeeViewModel empViewModel = new EmployeeViewModel();
        empViewModel.EmployeeName = emp.FirstName + " " + emp.LastName;
        empViewModel.Salary = emp.Salary.Value.ToString("C");
        if (emp.Salary > 15000)
        {
            empViewModel.SalaryColor = "yellow";
        }
        else
        {
            empViewModel.SalaryColor = "green";
        }
        empViewModels.Add(empViewModel);
    }
    employeeListViewModel.Employees = empViewModels;
    return View("EmployeeList", employeeListViewModel);
}
</employeeviewmodel>

نکته: HeaderFooterFilter لازم نیست.

گام ۳: ایجاد AddNewLink PartialView

حالا دیگر نمی توانیم از AddNewLink partial view که قبلا ایجاد کردیم استفاده کنیم زیرا تگ a که در آن داریم نیاز به refresh کامل صفحه دارد. در صورتی که هدف ما این است که یک “Single Page Application” ایجاد کنیم از این رو نباید refresh کامل داشته باشیم.

یک partial view به نام AddNewlink.cshtml در فولدر “~/Areas/Spa/Views/Main” ایجاد می کنیم.

<a href="#" onclick="OpenAddNew();">کارمند جدید</a>

گام ۴: ایجاد AddNewLink action method

یک action method جدید به نام GetAddNewLink در MainController ایجاد می کنیم.

public ActionResult GetAddNewLink()
{
if (Convert.ToBoolean(Session["IsAdmin"]))
{
return PartialView("AddNewLink");
}
else
{
return new EmptyResult();
}
}

گام ۵: ایجاد EmployeeList View

یک partial view جدید به نام EmployeeList در فولدر “~/Areas/Spa/Views/Main” ایجاد می کنیم.

@using WebApplication1.ViewModels.SPA
@model EmployeeListViewModel
<div>
    @{
        Html.RenderAction("GetAddNewLink");
    }

    <table border="1" id="EmployeeTable">
        <tr>
            <th>Employee Name</th>

گام ۶: تنظیم EmployeeList به عنوان صفحه اولیه

برای این کار Index.cshtml را که در فولدر “~/Areas/Spa/Views/Main” قرار گرفته است باز می کنیم و EmployeeList actionResult را در Div قرار می دهیم.



<pre class="lang:xhtml decode:true ">...  
</div>

گام ۷: تست و اجرا

کلید F5 را فشار داده و برنامه را اجرا می کنیم.

Single page Application

تمرین سی و چهارم – ایجاد single page application بخش سوم، ایجاد Employee

گام ۱: ایجاد AddNew ViewModels

یک ViewModel جدید به نام CreateEmployeeViewModel در فولدر SPA موجود در ViewModel class library project ایجاد می کنیم.

namespace WebApplication1.ViewModels.SPA	
{
    public class CreateEmployeeViewModel
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Salary { get; set; }
    }
}

گام ۲: ایجاد AddNew action method

فضای نام زیر را در MainController قرار می دهیم.

using WebApplication1.Filters;

حال به صورت زیر متد AddNew  را در MainController ایجاد می کنیم.

[AdminFilter]
public ActionResult AddNew()
{
    CreateEmployeeViewModel v = new CreateEmployeeViewModel();
    return PartialView("CreateEmployee", v);
}

گام ۳: ایجاد CreateEmployee Partial View

یک partial view جدید به نام CreateEmployee در فولدر “~/Areas/Views/Main” ایجاد می کنیم.

@using WebApplication1.ViewModels.SPA
@model CreateEmployeeViewModel
<div>
    <table>
        <tr>
            <td>
                نام کارمند:
            </td>

گام ۴: Include jQuery UI

روی نام پروژه راست کلیک کرده و “Manage Nuget Manager” را انتخاب می کنیم.

“jQuery UI” را جستجو می کنیم.

Single page Application

jQuery UI را نصب می کنیم. به این ترتیب، فایل های جاوا اسکریپت (.js) و Stylesheet(.css) به پروژه اضافه می کند.

Single page Application

گام ۵: Include jQuery UI

فایل “~/Areas/Spa/Views/Main/Index.cshtml” را باز کرده و فایل های jQuery.js، jQueryUI.js و همه فایل های css را به صورت زیر Include می کنیم. تمام این فایل ها توسط Nuget Manager به عنوان بخشی از jQuery UI packages اضافه می شوند.

<head>	
<meta name="viewport" content="width=device-width" />
<script src="~/Scripts/jquery-1.8.0.js"></script>
<script src="~/Scripts/jquery-ui-1.11.4.js"></script>
<title>Employee Single Page Application</title>
<link href="~/Content/themes/base/all.css" rel="stylesheet" />
...

گام ۶: پیاده سازی تابع OpenAddNew

یک تابع جدید جاوااسکریپت  به صورت زیر  به نام OpenAddNew در “~/Areas/Spa/Views/Main/Index.cshtml” ایجاد می کنیم.

<script>
    function OpenAddNew() {
        $.get("/SPA/Main/AddNew").then
            (
                function (r) {
                    $("<div id='DivCreateEmployee'></div>").html(r).
                        dialog({
                            width: 'auto', height: 'auto', modal: true, title: "Create New Employee",
                            close: function () {
                                $('#DivCreateEmployee').remove();
                            }
                        });
                }
            );
    }
</script>

گام ۷: تست و اجرا

کلید F5 را فشار داده و برنامه را اجرا می کنیم. فرایند ورود را کامل می کنیم و به متد Index در MainController می رویم. درنهایت روی لینک Add New کلیک می کنیم.

Single page Application

گام ۸: ایجاد تابع ResetForm

CreateEmployee.cshtml را باز می کنیم. در بالای این view، تابع ResetForm را به صورت زیر ایجاد می کنیم.

@model CreateEmployeeViewModel
<script>
    function ResetForm() {
        document.getElementById('TxtFName').value = "";
        document.getElementById('TxtLName').value = "";
        document.getElementById('TxtSalary').value = "";
    }

گام ۹: ایجاد تابع CancelSave

CreateEmployee.cshtml را باز می کنیم. در بالای این view، تابع CancelSave را به صورت زیر ایجاد می کنیم.

document.getElementById('TxtSalary').value = "";
    }
    function CancelSave() {
        $('#DivCreateEmployee').dialog('close');
    }

مرحله بعدی چیست؟

قبل از اینکه ادامه دهیم و گام ۱۰ را دنبال کنیم، اجازه دهید ببینیم مرحله بعد چه اتفاقی خواهد افتاد.

  • کاربر روی دکمه “Save” کلیک می کند.
  • مقادیر کنترل ها باید سمت کلاینت اعتبارسنجی شوند.
  • اگر همه مقادیر معتبر باشند، همه مقادیر به سمت سرور انتقال می یابند.
  • یک رکورد کارمند باید در دیتابیس ذخیره شود.
  • پنجره CreateEmployee باید بعد از آن بسته شود.
  • یک grid باید با مقادیر جدید به روزرسانی شود.

برنامه ریزی:

اعتبارسنجی:

برای اعتبارسنجی می توانیم از همان کد اعتبارسنجی جاوا اسکریپت که در نسخه غیر SPA اضافه کردیم، استفاده کنیم.

Save:

باید یک MVC action method برای ذخیره کارمندان ایجاد کنیم و آن را با استفاده از jQuery Ajax فراخوانی نماییم.

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

قبل از این، این کار به سادگی با کمک تگ Form و دکمه submit مدیریت می شد. اما در حال حاضر نمی توانیم از این روش استفاده کنیم، چرا که این روش به refresh کامل صفحه نیاز دارد. به جای آن، این بار با استفاده از jQuery Ajax متد MVC را بدون نیاز به refresh کامل صفحه، فراخوانی می کنیم.

حالا سوالی پیش می آید که اگر فراخوانی به طور دستی باشد، داده ها چگونه از جاوا اسکریپت به MVC action method انتقال پیدا می کنند.

سفری کوتاه برای پیدا کردن راه حل:

بررسی مشکل:

جاوا اسکریپت، .net یا هر تکنولوژی دیگری که باشد، وقتی کلمه داده را می شنوید اولین چیزی که به ذهن شما می آید، چیست؟

بله متغیرها هستند. ما از متغیرها برای نگه داری موقت داده ها استفاده می کنیم و پس از آن ممکن است آن را در یک حافظه پایدار و دائمی مانند دیتابیس ذخیره کنیم.

ما در این مثال، از دو تکنولوژی جاوا اسکریپت و ASP.Net MVC استفاده می کنیم. جاوا اسکریپت یک تکنولوژی است و ASP.Net MVC یک تکنولوژی متفاوت دیگر. این دو تکنولوژی نمی توانند به سادگی داده های خود را مبادله کنند یا به زبان ساده تر نمی توانند به طور مستقیم متغیرهای خود را مبادله نمایند.

ممکن است تعجب کنید، چرا نمی توانند؟

نوع داده int در .net لزوما شبیه به نوع داده int در یک تکنولوژی دیگر نیست. ممکن است در اندازه یا صفات دیگر متفاوت باشند. مفهوم متغیرها را در همه تکنولوژی ها داریم اما یکسان نیستند.

راه حل – یک نوع داده مشترک

با بروز این مشکل، همه به دنبال متغیری بودند که درواقع در همه تکنولوژی ها یکسان باشد. نوع داده ای که بتواند هر نوع داده ای را در خود نگه دارد، که این نوع داده ای “String” است. نوع داده String در همه تکنولوژی ها وجود دارد و می تواند هر چیزی را در خود نگه دارد.

  • می توانیم نوع داده int را به string تبدیل کرده و آن را به صورت رشته نگه داریم.
  • می توانیم نوع داده float را به string تبدیل کرده و آن را نیز به صورت رشته نگه داریم.
  • هر نوع داده ای می تواند به عنوان یک رشته ذخیره شود.

راه حل نهایی “هر گاه لازم باشد چیزی از یک تکنولوژی به تکنولوژی دیگر ارسال شود، تکنولوژی اول آن را به رشته تبدیل کرده و برای تکنولوژی دوم ارسال می کند چرا که یقین داریم تکنولوژی دوم، متغیر رشته را می فهمد.”

Single page Application

مشکل – نوع داده پیچیده چطور؟

حال اگر بخواهیم اطلاعات یک کارمند را از یک تکنولوژی به تکنولوژی دیگر ارسال کنیم، چطور؟

در .Net کلاس ها و اشیا نشان دهنده نوع داده پیچیده هستند.

به مثال زیر توجه کنید:

Employee e=new Employee();
e.EmpName= "باران";
e.Address= "تهران";

در جاوا اسکریپت “اشیای جاوا اسکریپت” برای نمایش داده های پیچیده استفاده می شوند.

مثال زیر را در نظر بگیرید:

var e={
EmpName= "باران",
Address= "تهران"
};

ارسال داده پیچیده از .Net به دیگر تکنولوژی ها به معنی ارسال اشیای کلاس از .Net به تکنولوژی دیگر است و ارسال داده از جاوا اسکریپت به تکنولوژی های دیگر به معنی ارسال اشیای جاوا اسکریپت به تکنولوژی های دیگر است. که به طور مستقیم امکان پذیر نیست. طبق هر استانداردی باید ابتدا داده ها (اشیای .Net یا اشیای جاوا اسکریپت) را به نوع string تبدیل کنیم و سپس آن ها را ارسال کنیم.

راه حل – یک استاندارد مشترک فرمت داده ها

دقیقا مانند مورد قبل، استاندارد دیگری هم اینجا تعریف شده است. این استاندارد می گوید هر تکنولوژی قبل از ارسال داده های خود باید آن را به یک نوع داده ای مشترک و قابل فهم برای همه تبدیل کند. اینجاست که XML معرفی می شود.

هر تکنولوژی داده های خود را به رشته فرمت بندی شده XML تبدیل کرده و سپس آن را به تکنولوژی های دیگر ارسال می کند. مانند string، نوع داده ای XML نیز قابل فهم برای همه تکنولوژی ها می باشد.

شی Employee ایجاد شده در کد C# بالا به صورت زیر در XML نشان داده خواهد شد:

<employee></employee><Employee>
      <EmpName>باران</EmpName>
      <Address>تهران</Address>
</Employee>

بنابراین راه حل این است: “تکنولوژی اول نوع داده پیچیده خود را به صورت XML در می آورد و سپس آن را برای تکنولوژی دیگر ارسال می کند.”

Single page Application

مشکل – مشکلات فرمت XML

مشکلات زیر را با فرمت XML داریم:

  1. XML سایز کلی رشته ای که می خواهیم ارسال کنیم را افزایش می دهد.

بیشتر شدن سایز رشته به معنی بیشتر شدن زمان ارسال آن است و این یعنی کاهش کارایی!

  1. مشکل دوم که مشکل مهم تری است، این است که ایجاد و سپس پارس کردن XML دشوار است.

اجازه دهید بیشتر در این مورد صحبت کنیم:

  • همان طور که قبلا گفتیم، هر تکنولوژی باید XML ای براساس داده های خود ایجاد کرده و آن را ارسال نماید. حالا ایجاد XML از اشیای .Net در C# با استفاده از XML Serializer بسیار آسان است.

اما درمورد جاوا اسکریپت چطور؟ در جاوا اسکریپت هیچ serializer و یا حتی کتابخانه آماده ای برای کار با XMl وجود ندارد. بنابراین باید به طور دستی از اشیای جاوا اسکریپت، رشته XML بسازیم که کار سختی است.

  • زمانی که یک تکنولوژی داده ای را از تکنولوژی دیگر دریافت می کند، همیشه این داده با فرمت XML خواهد بود. حال در C# پارس کردن رشته XML و ایجاد اشیای .Net از آن بسیار راحت با استفاه از XML Deserializer انجام می شود.

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

راه حل – JSON

برای حل مشکلات XML، فرمت جدیدی با نام JSON ارائه شد که کوتاه شده عبارت “JavaScript Object Notation” می باشد.

شی Employee ایجاد شده در C# در JSON به صورت زیر خواهد بود:

<{
  EmpName: "باران",
  Address: "تهران"
}

همان طور که مشاهده می کنید، این فرمت داده از نوع قبلی کم حجم تر می باشد.

همچنین توابع آماده ای در جاوا اسکریپت برای تبدیل اشیای جاوا اسکریپت به فرمت JSON و پارس رشته فرمت دار JSON به اشیای جاوا اسکریپت وجود دارد.

کد زیر ایجاد و پارس رشته JSON را نشان می دهد:

var e={
EmpName= “باران”,
Address= “تهران”
};
var EmployeeJsonString = JSON.stringify(e);//This EmployeeJsonString will be send to other technologies.
var EmployeeJsonString=GetFromOtherTechnology();
var e=JSON.parse(EmployeeJsonString);
alert(e.EmpName);
alert(e.Address);

بستن پنجره Create Employee:

برای بستن این پنجره می توان از jQuery Api استفاده کرد.

به روزرسانی Grid:

به روزرسانی Grid می تواند به یکی از دو روش زیر انجام شود:

  1. با استفاده از Partial View
  • یک Partial View درست شبیه کاری که برای پنجره CreateEmployee انجام دادیم، برای Ggrid ایجاد می کنیم.
  • یک Div با Id مشخص در EmployeeListView ایجاد کرده و Partial View را در آن نمایش می دهیم.
  • زمانی که دکمه Save کلیک می شود، Grid به روزرسانی شده به شکل یک partial view result دریافت شده و جایگزین تگ HTML داخلی div می شود.
  1. با استفاده از کد

در این روش، MVC action method یک EmployeeViewModel برمی گرداند به جای EmployeeListViewModel که سمت جاوا اسکریپت دریافت می شود و با استفاده از سطر جدید، به طور دستی در Grid وارد می شود. (EmployeeViewModel به عنوان یک رشته JSON از MVC action  method به جاوا اسکریپت ارسال می شود.

بازگشت به تمرین:

گام ۱۰ – ایجاد SaveEmployee action

حال یک متد جدید در MainController با نام SaveEmloyee ایجاد می کنیم.

[AdminFilter]
public ActionResult SaveEmployee(Employee emp)
{
    EmployeeBusinessLayer empBal = new EmployeeBusinessLayer();
    empBal.SaveEmployee(emp);

EmployeeViewModel empViewModel = new EmployeeViewModel();
empViewModel.EmployeeName = emp.FirstName + " " + emp.LastName;
empViewModel.Salary = emp.Salary.Value.ToString("C");
if (emp.Salary > 15000)
{
empViewModel.SalaryColor = "yellow";
}
else
{
empViewModel.SalaryColor = "green";
    }
return Json(empViewModel);
}

گام ۱۱ –  Include کردن Validation.js

به صورت زیر فایل Validation.js ای که در مراحل قبل ایجاد کردیم،  Include می کنیم.



<pre class="lang:c# decode:true ">@using WebApplication1.ViewModels.SPA
@model CreateEmployeeViewModel
<script src="~/Scripts/Validations.js"></script>


گام ۱۲ – ایجاد تابع SaveEmployee

فایل CreateEmployee.cshtml را باز می کنیم. در بالای آن تابع SaveEmployee را به صورت زیر ایجاد می کنیم:

...
...
  function SaveEmployee() {
        if (IsValid()) {
            var e =
                {
                    FirstName: $('#TxtFName').val(),
                    LastName: $('#TxtLName').val(),
                    Salary: $('#TxtSalary').val()
                };
            $.post("/SPA/Main/SaveEmployee",e).then(
                function (r) {
                    var newTr = $('<tr></tr>');
                    var nameTD = $('<td></td>');
                    var salaryTD = $('<td></td>');

                    nameTD.text(r.EmployeeName);
                    salaryTD.text(r.Salary); 

                    salaryTD.css("background-color", r.SalaryColor);

                    newTr.append(nameTD);
                    newTr.append(salaryTD);

                    $('#EmployeeTable').append(newTr);
                    $('#DivCreateEmployee').dialog('close');
                }
                );
        }
    }
</script>

گام ۱۳ – تست و اجرا

کلید F5 را فشار داده و برنامه را اجرا می کنیم.

Single page Application

پرسش و پاسخ در تمرین سی و چهارم:

متد JSON چه کاری انجام می دهد؟

این متد JSONResult برمی گرداند. در روز ششم درباره چرخه درخواست در MVC صحبت کردیم. شکل زیر مرور دوباره ای بر آن می باشد:

Single page Application

ExecuteResult به صورت abstract در کلاس ActionResult تعریف شده است. تمام فرزندان کلاس ActionResult آن را درون خود به روش خود پیاده سازی می کنند. در روز اول درباره ViewResult صحبت کردیم. در کلاس ViewResult متد ExecuteResult کارهای زیر را انجام می دهد.

  • شی ای از کلاس ViewPageActivator می سازد.
  • ViewEngine درست را انتخاب کرده و شی ViewPageActivator را به عنوان آرگومان برای سازنده ViewEngine ارسال می کند. ViewEngin شی ای از کلاس View ایجاد می کند.
  • متد RenderView از کلاس View را فراخوانی می کند که خروجی نهایی HTML را که به عنوان پاسخ ارسال می شود، اجرا می کند.

زمانی که JsonResult داریم، متد ExecuteResult:

  • نوع محتوای پاسخ را “Application/Json” قرار می دهد.
  • با استفاده از JavaScript Serializer داده ارسالی را به رشته JSON تبدیل می کند.
  • JSON نهایی را در جریان پاسخ می نویسد.

تمرین سی و پنجم – ایجاد single page application بخش چهارم، آپلود چندگانه

گام ۱ – ایجاد SpaBulkUploadController

یک AsyncController جدید با نام SpaBulkUploadController ایجاد می کنیم.

namespace WebApplication1.Areas.SPA.Controllers
{
    public class SpaBulkUploadController : AsyncController
    {
    }
}

گام ۲ – ایجاد Index action

در Controller بالا یک متد جدید با نام Index به صورت زیر ایجاد می کنیم.

[AdminFilter]
public ActionResult Index()
{
    return PartialView("Index");
}

گام ۳ – ایجاد Index PartialView

یک PartialView  جدید به صورت زیر در “~/Areas/Spa/Views/SpaBulkUpload” ایجاد می کنیم.

div
    Select File : input type="file" name="fileUpload" id="MyFileUploader" value="" /
    input type="submit" name="name" value="آپلود" onclick="Upload();" /
/div

گام ۴ – ایجاد متد OpenBulkUpload

فایل Index.cshtml را در فولدر “~/Areas/Spa/Views/Main” باز کرده و یک متد جاوااسکریپت به نام OpenBulkUpload در آن ایجاد می کنیم.

function OpenBulkUpload() {
            $.get("/SPA/SpaBulkUpload/Index").then
                (
                    function (r) {
                        $("div id='DivBulkUpload'/div").html(r).dialog({ width: 'auto', height: 'auto', modal: true, title: "Create New Employee",
                            close: function () {
                                $('#DivBulkUpload').remove();
                            } });
                    }
                );
        }
    /script
/head
body
    div style="text-align:right"

گام ۵ – تست و اجرا

کلید F5 را فشار داده و برنامه را اجرا می کنیم. فرایند ورود را کامل کرده و به Index مربوط به MainController می رویم و روی لینک آپلود چندگانه کلیک می کنیم.

Single page Application

گام ۶ – ایجاد FileUploadViewModel

یک کلاس ViewModel جدید به نام FileUploadViewModel در فولدر SPA مربوط به ViewModel class library ایجاد می کنیم.

namespace WebApplication1.ViewModels.SPA
{
    public class FileUploadViewModel
    {
        public HttpPostedFileBase fileUpload { get; set; }
    }
}

گام ۷ – ایجاد Upload Action

یک Action method جدید به نام Upload در SpaBulkUploadController به صورت زیر ایجاد می کنیم.

[AdminFilter]
public async Taskactionresult Upload(FileUploadViewModel model)
{
    int t1 = Thread.CurrentThread.ManagedThreadId;
    Listemployee employees = await Task.Factory.StartNewlistemployee
        (() = GetEmployees(model));
    int t2 = Thread.CurrentThread.ManagedThreadId;
    EmployeeBusinessLayer bal = new EmployeeBusinessLayer();
    bal.UploadEmployees(employees);
    EmployeeListViewModel vm = new EmployeeListViewModel();
    vm.Employees = new Listemployeeviewmodel();
    foreach (Employee item in employees)
    {
        EmployeeViewModel evm = new EmployeeViewModel();
        evm.EmployeeName = item.FirstName + " " + item.LastName;
        evm.Salary = item.Salary.Value.ToString("C");
        if (item.Salary  15000)
        {
            evm.SalaryColor = "yellow";
        }
        else
        {
            evm.SalaryColor = "green";
        }
        vm.Employees.Add(evm);
    }
    return Json(vm);
}

private Listemployee GetEmployees(FileUploadViewModel model)
{
    Listemployee employees = new Listemployee();
    StreamReader csvreader = new StreamReader(model.fileUpload.InputStream);
    csvreader.ReadLine();// Assuming first line is header
    while (!csvreader.EndOfStream)
    {
        var line = csvreader.ReadLine();
        var values = line.Split(',');//Values are comma separated
        Employee e = new Employee();
        e.FirstName = values[0];
        e.LastName = values[1];
        e.Salary = int.Parse(values[2]);
        employees.Add(e);
    }
    return employees;
}
/employee

همان طور که مشاهده می کنید، این بار به جای Redirect، JsonResult برمی گردانیم.

گام ۸ – ایجاد تابع Upload

Index view موجود در فولدر “~/Areas/Spa/Views/SpaBulkUpload” را باز می کنیم و یک تابع جاوا اسکریپت به نام Upload ایجاد می کنیم.

script
    function Upload() {
        debugger;
        var fd = new FormData();
        var file = $('#MyFileUploader')[0];
        fd.append("fileUpload", file.files[0]);
        $.ajax({
            url: "/Spa/SpaBulkUpload/Upload",
            type: 'POST',
            contentType: false,
            processData: false,
            data: fd
        }).then(function (e) {
            debugger;
            for (i = 0; i  e.Employees.length; i++)
            {
                var newTr = $('tr/tr');
                var nameTD = $('td/td');
                var salaryTD = $('td/td');

                nameTD.text(e.Employees[i].EmployeeName);
                salaryTD.text(e.Employees[i].Salary);

                salaryTD.css("background-color", e.Employees[i].SalaryColor);

                newTr.append(nameTD);
                newTr.append(salaryTD);

                $('#EmployeeTable').append(newTr);
            }
            $('#DivBulkUpload').dialog('close');
        });
    }
/script

گام ۹ – تست و اجرا

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

Single page Application

کلید F5 را فشار داده و برنامه را اجرا می کنیم.

 برنامه نویسی سه لایه در MVC

جمع بندی:

خب در این جا سفر ۷ روزه ما در MVC به پایان رسید. پروژه ساده ای را با استفاده از بسیاری از امکانات ASP.Net MVC به همراه شما به پایان رساندیم. همچنین درباره بسیاری از مفاهیم تئوری با جزئیات بحث کردیم.

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

  • مقاله اول:

در این مقاله دوباره پروژه SPA را ایجاد خواهیم کرد، اما این بار به کمک Web API و Amgular

  • مقاله دوم:

در این مقاله نیز درباره مباحثی صحبت خواهیم کرد که در این سری بحث نشد.

  • Bunding و Minification
  • Application Error
  • Temp data
  • ایجاد کلاس های helper سفارشی
  • MVC Unit Testing
  • MVC dependency resolver

دانلود فایل PDF

  • پسورد: www.mspsoft.com
فاطمه زکایی

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

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

دیدگاه‌ها

*
*

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

    programmer پاسخ

    با سلام
    بسیار عالی بود ممنون از زحماتتان
    ممنون

    فرشته رمضانی پاسخ

    باران‌ خااانم ممنون و خسته نباشید
    ممنون از سایت ام اس پی سافت

      باران بزرگمهر پاسخ

      ممنونم لطف دارید موفق باشید.

        koushamanage پاسخ

        سلام ممنون از زحماتتون ولی من پی دی اف ها رو دانلود کردم با کمال شگفتی دیدم تو فایلهای زیپ پروژه ها و مثالها هستن. لطفا راهنمائی کنید پی دی اف های متن آموزشهاتونو از کجا دانلود کنم؟ ترجیح میدم متن آموزها رو بصورت پی دی اف و ترجیحا هر هفت روز رو تو یه فایل داشته باشم فکر کنم دوستان دیگه هم موافق باشن