Skip to content

2. مقدمه‌ای کوتاه بر ASP.NET

در اینجا، هدف ما این است که با استفاده از چند مثال، مفاهیم ASP.NET را که بعداً در این سند به کار ما خواهند آمد، معرفی کنیم. این مقدمه پیچیدگی‌های ارتباطات کلاینت/سرور در یک برنامه وب را پوشش نمی‌دهد. برای این منظور، ممکن است بخواهید بخوانید:

این مقدمه برای کسانی در نظر گرفته شده است که می‌خواهند سریعاً شروع کنند، در حالی که در ابتدا می‌پذیرند که برخی نکات - که ممکن است مهم باشند - به تفصیل پوشش داده نشده‌اند. بقیه این سند این نکات را با جزئیات بیشتری بررسی می‌کند. کسانی که با ASP.NET آشنا هستند می‌توانند مستقیماً به پاراگراف ۳ بروند.

2.1. یک پروژهٔ نمونه

2.1.1. ایجاد پروژه

  • در [1]، یک پروژه جدید با استفاده از Visual Web Developer ایجاد کنید
  • در [2]، یک پروژه وب را در Visual C# انتخاب کنید
  • در [3]، مشخص کنید که می‌خواهید یک برنامه وب ایجاد کنید. در ASP.NET
  • در [4]، برای برنامه یک نام انتخاب کنید. یک پوشه با این نام برای پروژه ایجاد خواهد شد.
  • در [5]، پوشهٔ والد پوشهٔ [4] پروژه را مشخص کنید.
  • در [6]، پروژه ایجاد می‌شود
  • [Default.aspx] یک صفحه وب است که به‌طور پیش‌فرض ایجاد می‌شود. این صفحه شامل تگ‌های HTML و تگ‌های ASP.NET است
  • [Default.aspx.cs] حاوی کدی برای مدیریت رویدادهای تحریک‌شده توسط کاربر در صفحه [Defaul.aspx] است که در مرورگر کاربر نمایش داده می‌شود
  • [Default.aspx.designer.cs] شامل فهرست اجزای ASP.NET در صفحه [Default.aspx] است. هر مؤلفه ASP.NET که در صفحه [Default.aspx] قرار می‌گیرد، یک اعلان برای آن مؤلفه در [Default.aspx.designer.cs] تولید می‌کند.
  • [Web.config] فایل پیکربندی پروژه ASP.NET است.
  • [References] فهرستی از فایل‌های DLL است که توسط پروژه وب استفاده می‌شوند. این فایل‌های DLL کتابخانه‌های کلاسی هستند که پروژه از آن‌ها استفاده خواهد کرد. در [7] فهرست فایل‌های DLL قرار دارد که به‌صورت پیش‌فرض در ارجاعات پروژه تنظیم شده‌اند. اکثر آن‌ها غیرضروری هستند. اگر پروژه نیاز به استفاده از DLL داشته باشد که در [7] فهرست نشده است، می‌توان آن را از طریق [8] اضافه کرد.

2.1.2. صفحه [Default.aspx]

اگر پروژه با استفاده از [Ctrl-F5] اجرا شود، صفحه [Default.aspx] در یک مرورگر نمایش داده می‌شود:

  • در [1]، صفحه URL از پروژه وب. Visual Web Developer یک سرور وب داخلی دارد که هنگام اجرای پروژه راه‌اندازی می‌شود. این سرور روی یک پورت تصادفی گوش می‌دهد، در این مورد پورت 1490. پورت گوش‌دادن معمولاً پورت ۸۰ است. در [1]، هیچ صفحه‌ای درخواست نشده است. در این حالت، صفحه [Default.aspx] نمایش داده می‌شود، از این رو به آن صفحه پیش‌فرض گفته می‌شود.
  • در [2]، صفحه [Default.aspx] خالی است.
  • در ویژوال وب دیواپر، صفحه [Default.aspx] [3] را می‌توان به صورت بصری (تَب [Design]) یا با استفاده از تگ‌ها (تَب [Source]) ساخت.
  • در [4]، صفحه [Defaul.aspx] در حالت [Design] قرار دارد. این صفحه با کشیدن و رها کردن کامپوننت‌ها از جعبه ابزار [5] روی آن ساخته می‌شود.

حالت [Source] [6] دسترسی به کد منبع صفحه را فراهم می‌کند:


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Intro._Default" %>

<!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 runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
  </div>
  </form>
</body>
</html>
  • خط ۱ یک دستور ASP.NET است که برخی از ویژگی‌های صفحه را فهرست می‌کند
    • دستور Page برای یک صفحه وب اعمال می‌شود. دستورهای دیگری مانند Application، WebService، … وجود دارند که برای اشیاء دیگر ASP.NET اعمال می‌شوند
    • ویژگی CodeBehind فایلی را مشخص می‌کند که رویدادهای صفحه را مدیریت می‌کند
    • ویژگی Language زبان .NET را که توسط فایل CodeBehind استفاده می‌شود، مشخص می‌کند
    • ویژگی Inherits نام کلاسی را که در فایل CodeBehind تعریف شده است مشخص می‌کند
    • ویژگی AutoEventWireUp="true" نشان می‌دهد که ارتباط بین یک رویداد در [Default.aspx] و دست‌پردازشگر آن در [Defaul.aspx.cs] از طریق نام رویداد برقرار می‌شود. بنابراین،رویداد Load در صفحه [Default.aspx] توسط متد Page_Load از کلاس Intro._Default که با ویژگی Inherits تعریف شده است، پردازش خواهد شد.
  • خطوط ۴–۱۴ صفحه [Defaul.aspx] را با استفاده از تگ‌ها توصیف می‌کنند:
    • برچسب‌های استاندارد HTML مانند <body> یا <div>
    • ASP.NET. این‌ها تگ‌هایی هستند که دارای ویژگی runat="server" می‌باشند. تگ‌های ASP.NET قبل از ارسال صفحه به کلاینت توسط وب سرور پردازش می‌شوند. آنها به برچسب‌های HTML تبدیل می‌شوند. بنابراین مرورگر کلاینت یک صفحه استاندارد HTML دریافت می‌کند که در آن دیگر هیچ برچسب ASP.NET وجود ندارد.

صفحه [Default.aspx] را می‌توان مستقیماً از کد منبع آن ویرایش کرد. این کار گاهی ساده‌تر از استفاده از حالت [Design] است. ما کد منبع را به شرح زیر تغییر می‌دهیم:


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Intro._Default" %>

<!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 runat="server">
  <title>Introduction ASP.NET</title>
</head>
<body>
  <h3>Introduction à ASP.NET</h3>
  <form id="form1" runat="server">
  <div>
  </div>
  </form>
</body>
</html>

در خط ۶، با استفاده از تگ <title> از HTML به صفحه یک عنوان می‌دهیم. در خط ۹، مقداری متن را در بدنه (<body>) صفحه وارد می‌کنیم. اگر پروژه را اجرا کنیم (Ctrl-F5)، نتیجه زیر را در مرورگر مشاهده می‌کنیم:

 

2.1.3. فایل‌های [Default.aspx.designer.cs] و [Default.aspx.cs]

فایل [Default.aspx.designer.cs] اجزای صفحه [Defaul.aspx] را اعلام می‌کند:


//------------------------------------------------------------------------------
// <auto-generated>
//      این کد توسط یک ابزار تولید شده است.
//      نسخهٔ زمان اجرا: 2.0.50727.3603
//
//      تغییراتی که در این فایل انجام شده ممکن است باعث رفتار نادرست شود و در صورت
//      کد مجدداً تولید شود.
// </auto-generated>
//------------------------------------------------------------------------------

namespace Intro {
    
    
    public partial class _Default {
        
        /// <summary>
        /// کنترل Form1.
        /// </summary>
        /// <remarks>
        /// فیلد تولیدشده به‌طور خودکار.
        /// برای ویرایش، اعلان فیلد را از فایل دیزاینر به فایل کد-بیهایند منتقل کنید.
        /// </remarks>
        protected global::System.Web.UI.HtmlControls.HtmlForm form1;
    }
}

این فایل شامل فهرست اجزای ASP.NET از صفحه [Default.aspx] است که دارای شناسه هستند. این موارد با تگ‌های موجود در [Default.aspx] که دارای ویژگی runat="server" و ویژگی id هستند، مطابقت دارند. بنابراین، مؤلفه در خط ۲۳ بالا با تگ


  <form id="form1" runat="server">

در [Default.aspx].

توسعه‌دهنده تعامل کمی با فایل [Default.aspx.designer.cs] دارد. با این حال، این فایل برای تعیین کلاس یک مؤلفه خاص مفید است. بنابراین، در زیر می‌بینیم که مؤلفه form1 از نوع HtmlForm است. توسعه‌دهنده سپس می‌تواند این کلاس را بررسی کند تا با ویژگی‌ها و متدهای آن آشنا شود. کامپوننت‌های موجود در صفحه [Default.aspx] توسط کلاس موجود در فایل [Default.aspx.cs] استفاده می‌شوند:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Intro
{
  public partial class _Default : System.Web.UI.Page
  {
    protected void Page_Load(object sender, EventArgs e)
    {

    }
  }
}

شایان ذکر است که کلاسی که در فایل‌های [Default.aspx.cs] و [Default.aspx.designer.cs] تعریف شده یکسان است (خط ۱۰): Intro._Default. کلیدواژه partial است که امکان گسترش اعلان کلاس را در چندین فایل، در این مورد دو فایل، فراهم می‌کند.

در خط ۱۰، در بالا، می‌بینیم که کلاس [_Default] از کلاس [Page] ارث می‌برد و رویدادهای آن را به ارث می‌برد. یکی از این‌ها رویداد Load است که هنگام بارگذاری صفحه توسط وب‌سرور رخ می‌دهد. خط ۱۲: متد Page_Load که رویداد Load صفحه را مدیریت می‌کند. این معمولاً جایی است که صفحه قبل از نمایش در مرورگر کلاینت، اولیه می‌شود. در اینجا، متد Page_Load هیچ کاری انجام نمی‌دهد.

کلاسی که با یک صفحه وب مرتبط است – در این مورد، کلاس Intro._Default – در ابتدای درخواست مشتری ایجاد می‌شود و پس از ارسال پاسخ به مشتری، نابود می‌گردد. بنابراین نمی‌توان از آن برای ذخیره اطلاعات بین درخواست‌ها استفاده کرد. برای این کار باید از مفهوم جلسه کاربری (user session) استفاده شود.

2.2. رویدادها در یک صفحه وب ASP.NET

ما در حال ساخت صفحه زیر، [Default.aspx] هستیم:


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Intro._Default" %>

<!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 runat="server">
  <title>Introduction ASP.NET</title>
</head>
<body>
  <h3>Introduction à ASP.NET</h3>
  <form id="form1" runat="server">
  <div>
    <table>
      <tr>
        <td>
          Nom</td>
        <td>
          <asp:TextBox ID="TextBoxNom" runat="server"></asp:TextBox>
        </td>
        <td>
          &nbsp;</td>
      </tr>
      <tr>
        <td>
          Age</td>
        <td>
          <asp:TextBox ID="TextBoxAge" runat="server"></asp:TextBox>
        </td>
        <td>
          &nbsp;</td>
      </tr>
    </table>
  </div>
  <asp:Button ID="ButtonValider" runat="server" Text="Valider" />
  <hr />
  <p>
    Evénements traités par le serveur</p>
  <p>
    <asp:ListBox ID="ListBoxEvts" runat="server"></asp:ListBox>
  </p>
  </form>
</body>
</html>

حالت [Design] برای صفحه به شرح زیر است:

 

فایل [Default.aspx.designer.cs] به شرح زیر است:


namespace Intro {
    public partial class _Default {
        protected global::System.Web.UI.HtmlControls.HtmlForm form1;
        protected global::System.Web.UI.WebControls.TextBox TextBoxNom;
        protected global::System.Web.UI.WebControls.TextBox TextBoxAge;
        protected global::System.Web.UI.WebControls.Button ButtonValider;
        protected global::System.Web.UI.WebControls.ListBox ListBoxEvts;
    }
}

این شامل تمام اجزای ASP.NET از صفحه [Default.aspx] است که دارای شناسه هستند.

ما فایل [Default.aspx.cs] را به شرح زیر به‌روزرسانی می‌کنیم:


using System;

namespace Intro
{
  public partial class _Default : System.Web.UI.Page
  {
    protected void Page_Init(object sender, EventArgs e)
    {
      // رویداد
      ListBoxEvts.Items.Insert(0, string.Format("{0}: Page_Init", DateTime.Now.ToString("hh:mm:ss")));
    }

    protected void Page_Load(object sender, EventArgs e)
    {
      //رویداد ثبت می‌شود
      ListBoxEvts.Items.Insert(0, string.Format("{0}: Page_Load", DateTime.Now.ToString("hh:mm:ss")));
    }

    protected void ButtonValider_Click(object sender, EventArgs e)
    {
      //رویداد ثبت می‌شود
      ListBoxEvts.Items.Insert(0, string.Format("{0}: ButtonValider_Click", DateTime.Now.ToString("hh:mm:ss")));
    }
  }
}

کلاس [_Default] (خط ۵) سه رویداد را مدیریت می‌کند:

  • رویداد Init (خط ۷)، که هنگام اولیه شدن صفحه رخ می‌دهد
  • رویداد Load (خط ۱۳)، که زمانی رخ می‌دهد که صفحه توسط سرور وب بارگذاری شده باشد. رویداد Init قبل از رویداد Load رخ می‌دهد.
  • رویداد کلیک روی دکمه ButtonValider (خط ۱۹)، که زمانی رخ می‌دهد که کاربر دکمه [Valider] را کلیک می‌کند

پردازش هر یک از این سه رویداد شامل افزودن یک پیام به کامپوننت Listbox با نام ListBoxEvts است. این پیام زمان و نام رویداد را نمایش می‌دهد. هر پیام در بالای لیست قرار می‌گیرد. بنابراین، پیام‌های بالای لیست جدیدترین‌ها هستند.

هنگامی که پروژه اجرا می‌شود، صفحه زیر نمایش داده می‌شود:

از [1] می‌توان دید که رویدادهای Page_Init و Page_Load به ترتیب رخ داده‌اند. شایان ذکر است که جدیدترین رویداد در بالای فهرست ظاهر می‌شود. هنگامی که مرورگر صفحه [Default.aspx] را مستقیماً از طریق نشانی [2] درخواست می‌کند، این کار را با استفاده از فرمان HTTP انجام می‌دهد. (پروتکل انتقال HyperText) که با نام GET شناخته می‌شود. پس از بارگذاری صفحه در مرورگر، کاربر رویدادها را در صفحه فعال می‌کند. برای مثال، آن‌ها روی دکمه [Valider] [3] کلیک خواهند کرد. رویدادهایی که کاربر پس از بارگذاری صفحه در مرورگر ایجاد می‌کند، درخواستی به صفحه [Default.aspx] ارسال می‌کند، اما این بار با دستوری HTTP به نام POST. برای خلاصه کردن:

  • بارگذاری اولیه یک صفحه P در مرورگر توسط عملیاتی به نام HTTP GET انجام می‌شود
  • رویدادهایی که متعاقباً در صفحه رخ می‌دهند، هر کدام یک درخواست جدید به همان صفحه P ایجاد می‌کنند، اما این بار با فرمان HTTP POST. یک صفحه P می‌تواند تشخیص دهد که آیا با استفاده از فرمان GET یا فرمان POST درخواست شده است، که این امکان را به آن می‌دهد تا در صورت لزوم رفتار متفاوتی از خود نشان دهد – که معمولاً چنین است.

درخواست اولیه برای یک صفحه ASPX: GET

  • به [1]، مرورگر صفحه ASPX را از طریق یک فرمان HTTP GET بدون پارامتر درخواست می‌کند.
  • در [2]، سرور وب در پاسخ جریان HTML را ارسال می‌کند که ترجمه صفحه درخواست‌شده ASPX است.

پردازش رویدادی که در صفحه‌ای که توسط مرورگر نمایش داده می‌شود رخ می‌دهد: POST

  • به عنوان [1]، پس از یک رویداد در صفحه HTML، مرورگر صفحه ASPX را درخواست می‌کند، که قبلاً از طریق عملیاتی GET بازیابی شده است، این بار با استفاده از دستوری HTTP POST همراه با پارامترها. این پارامترها، مقادیر اجزایی هستند که در تگ <form> صفحه HTML نمایش‌داده‌شده توسط مرورگر قرار دارند. به این مقادیر، مقادیر ارسال‌شده توسط کلاینت گفته می‌شود. این مقادیر توسط صفحه ASPX برای پردازش درخواست کلاینت استفاده خواهند شد.
  • در [2]، سرور وب پاسخ را به صورت فید HTML بازمی‌گرداند – که ترجمه‌ای از صفحه ASPX است که در ابتدا توسط POST درخواست شده، یا در صورتی که انتقال یا هدایت صفحه صورت گرفته باشد، ترجمه‌ای از صفحه دیگری است.

بیایید به صفحهٔ مثال خود بازگردیم:

  • در [2]، صفحه از طریق یک GET به دست آمد.
  • در [1]، می‌توانیم دو رویدادی را که در طول این GET رخ داده‌اند، مشاهده کنیم

اگر، همانطور که در بالا نشان داده شده است، کاربر روی دکمه [Valider] [3] کلیک کند، صفحه [Default.aspx] از طریق یک POST درخواست خواهد شد. این POST همراه با پارامترهایی خواهد بود که نمایانگر مقادیر تمام مؤلفه‌های گنجانده‌شده در تگ <form> در صفحه [Default.aspx] هستند: دو TextBox و [TextBoxNom, TextBoxAge]، دکمه [ButtonValider] و لیست [ListBoxEvts]. مقادیر ارسال‌شده برای اجزا به شرح زیر است:

  • TextBox: مقدار واردشده
  • Button: متن دکمه، در این مورد «ارسال»
  • Listbox: متن پیامی که در ListBox انتخاب شده است

در پاسخ به POST، صفحه [4] بازگردانده می‌شود. این بار دیگر صفحه [Default.aspx] است. این رفتار طبیعی است، مگر اینکه توسط پردازشگرهای رویداد صفحه، انتقال صفحه یا هدایت مجدد (redirection) انجام شود. می‌توانیم ببینیم که دو رویداد جدید رخ داده‌اند:

  • رویداد Page_Load، که هنگام بارگذاری صفحه رخ داده است
  • رویداد ButtonValider_Click، که در نتیجه کلیک روی دکمه [Valider] رخ داده است

می‌توان مشاهده کرد که:

  • رویداد Page_Init در طول عملیات HTTP POST رخ نداده است، در حالی کهاین رویداد در طول رویدادهای HTTP و GET رخ داده بود
  • رویداد Page_Load هر بار، چه روی GET و چه روی POST، رخ می‌دهد. در این روش است که معمولاً باید بدانیم آیا با GET سروکار داریم یا با POST.
  • پس از پردازش POST، صفحه [Default.aspx] با تغییراتی که توسط رویدادپردازها ایجاد شده بود، به کلاینت بازگردانده شد. این همیشه صادق است. به محض اینکه رویدادهای یک صفحه P پردازش شدند، همان صفحه P به کلاینت بازگردانده می‌شود. دو راه برای دور زدن این قاعده وجود دارد. آخرین پردازشگر رویدادی که اجرا شده ممکن است
    • جریان اجرای برنامه را به صفحهٔ دیگری منتقل کند، P2.
    • مرورگر مشتری را به صفحهٔ دیگری، P2، هدایت کند.

در هر دو حالت، صفحه P2 به مرورگر بازگردانده می‌شود. این دو روش تفاوت‌هایی دارند که بعداً به آن‌ها خواهیم پرداخت.

  • رویداد ButtonValider_Click پس از رویداد Page_Load رخ داد. بنابراین این هندلر است که می‌تواند تصمیم بگیرد که آیا به صفحه P2 منتقل شود یا هدایت گردد.
  • فهرست رویدادهای [4] دو رویدادی را که در هنگام بارگذاری اولیه (GET) صفحه [Default.aspx] نمایش داده شدند، حفظ کرد. این موضوع با توجه به اینکه صفحه [Default.aspx] در طول POST بازسازی شده است، شگفت‌آور است. ما باید صفحه [Default.aspx] را با مقادیر طراحی آن و در نتیجه یک ListBox خالی ببینیم. اجرای هندلرهای Page_Load و ButtonValider_Click باید دو پیام را در آنجا قرار دهد. با این حال، چهار پیام وجود دارد. این موضوع با مکانیزم VIEWSTATE توضیح داده می‌شود. در طول فرآیند اولیه GET، وب‌سرور صفحه [Default.aspx] را با تگ HTML <input type="hidden" ...> که به عنوان فیلد مخفی شناخته می‌شود، ارسال می‌کند (خط ۱۰ در زیر).
<!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><title>
        Introduction ASP.NET
</title></head>
<body>
  <h3>Introduction à ASP.NET</h3>
  <form name="form1" method="post" action="default.aspx" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKLTMzMTEyNDMxMg9kFgICAw9kFgICBw8QZBAVAhMwNjoxNjozNjogUGFnZV9Mb2FkEzA2OjE2OjM2OiBQYWdlX0luaXQVAhMwNjoxNjozNjogUGFnZV9Mb2FkEzA2OjE2OjM2OiBQYWdlX0luaXQUKwMCZ2dkZGRW1AnTL8f/q7h2MXBLxctKD1UKfg==" />
</div>
..............................

در فیلد «id» با مقدار «__VIEWSTATE»، سرور وب مقادیر تمام اجزای صفحه را رمزگذاری می‌کند. این کار را هم برای ورودی اولیه «GET» و هم برای ورودی بعدی «POST» انجام می‌دهد. وقتی POST در صفحه P رخ می‌دهد:

  • مرورگر با درج مقادیر تمام کامپوننت‌های موجود در تگ <form> در درخواست خود، صفحه P را درخواست می‌کند. در بالا می‌بینیم که کامپوننت «__VIEWSTATE» داخل تگ <form> قرار دارد. بنابراین، مقدار آن در طول یک POST به سرور ارسال می‌شود.
  • صفحه P با مقادیر ساخت خود نمونه سازی و اولیه می‌شود
  • کامپوننت «__VIEWSTATE» برای بازگرداندن کامپوننت‌ها به مقادیری که هنگام ارسال قبلی صفحه P داشتند، استفاده می‌شود. به این ترتیب، برای مثال، لیست رویدادهای [4] دو پیام اولی را که هنگام ارسال در پاسخ به درخواست اولیه GET مرورگر در خود داشت، بازیابی می‌کند.
  • سپس اجزای صفحه P مقادیر ارسال‌شده توسط مرورگر را به خود اختصاص می‌دهند. در این نقطه، فرم صفحه P در همان حالتی قرار دارد که کاربر آن را ارسال کرده بود.
  • رویداد Page_Load پردازش می‌شود. در اینجا، آن یک پیام به فهرست رویدادها [4] اضافه می‌کند.
  • رویدادی که POST را فعال کرده است، پردازش می‌شود. در اینجا، ButtonValider_Click پیامی را به لیست رویدادها [4] اضافه می‌کند.
  • صفحه P بازگردانده می‌شود. کامپوننت‌ها مقادیر زیر را دارند:
    • یا مقداری که ارسال شده است، c.a.d، یا مقداری که کامپوننت هنگام ارسال به سرور در فرم داشت
    • یا مقداری که توسط یکی از رسیدگی‌کننده‌های رویداد ارائه شده است.

در مثال ما،

  • دو کامپوننت TextBox مقادیر ارسال‌شده خود را حفظ می‌کنند زیرا رسیدگی‌کننده‌های رویداد آنها را تغییر نمی‌دهند
  • فهرست رویدادها [4] مقدار ارسال‌شده خود، c.a.d را حفظ می‌کند. تمام رویدادهای موجود در لیست، به‌علاوه دو رویداد جدید ایجادشده توسط متدهای Page_Load و ButtonValider_Click.

می‌توان مکانیزم VIEWSTATE را در سطح هر مؤلفه فعال یا غیرفعال کرد. بیایید آن را برای مؤلفه [ListBoxEvts] غیرفعال کنیم:

  • در [1]، مکانیزم VIEWSTATE برای مؤلفه [ListBoxEvts] غیرفعال است. مکانیزم‌های مربوط به TextBox و [2] به‌طور پیش‌فرض فعال هستند.
  • در [3]، دو رویداد پس از GET اولیه بازگردانده می‌شوند
  • در [4]، فرم تکمیل شده و دکمه [Valider] کلیک شده است. یک POST به صفحه [Default.aspx] فراخوانی خواهد شد.
  • در [6]، نتیجه‌ای که پس از کلیک روی دکمه [Valider] بازگردانده می‌شود
  • مکانیزم فعال‌شده VIEWSTATE توضیح می‌دهد که چرا TextBox و [7] مقادیر ارسال‌شده در [4] را حفظ کرده‌اند
  • مکانیزم غیرفعال VIEWSTATE توضیح می‌دهد که چرا مؤلفه [ListBoxEvts] [8] محتوای خود [5] را حفظ نکرد.

2.3. پردازش مقادیر ارسال‌شده

در اینجا، ما مقادیری را که دو عنصر TextBox هنگام کلیک کاربر روی دکمه [Valider] ارسال می‌کنند، بررسی خواهیم کرد. صفحه [Default.aspx] در حالت [Design] به شرح زیر تغییر می‌کند:

کد منبع عنصر اضافه شده در [1] به شرح زیر است:


  <p>
    Eléments postés au serveur :
    <asp:Label ID="LabelPost" runat="server"></asp:Label>
</p>

ما از کامپوننت [LabelPost] برای نمایش مقادیر وارد شده در هر دو TextBox و [2] استفاده خواهیم کرد. کد برای رویدادپرداز [Default.aspx.cs] به شرح زیر تغییر می‌کند:


using System;

namespace Intro
{
  public partial class _Default : System.Web.UI.Page
  {
    protected void Page_Init(object sender, EventArgs e)
    {
      //رویداد ثبت می‌شود
      ListBoxEvts.Items.Insert(0, string.Format("{0}: Page_Init", DateTime.Now.ToString("hh:mm:ss")));
    }

    protected void Page_Load(object sender, EventArgs e)
    {
      //رویداد ثبت می‌شود
      ListBoxEvts.Items.Insert(0, string.Format("{0}: Page_Load", DateTime.Now.ToString("hh:mm:ss")));
    }

    protected void ButtonValider_Click(object sender, EventArgs e)
    {
      // رویداد ثبت می‌شود
      ListBoxEvts.Items.Insert(0, string.Format("{0}: ButtonValider_Click", DateTime.Now.ToString("hh:mm:ss")));
      //نام نمایشی و سن
      LabelPost.Text = string.Format("nom={0}, age={1}", TextBoxNom.Text.Trim(), TextBoxAge.Text.Trim());
    }
  }
}

در خط ۲۴، کامپوننت LabelPost به‌روزرسانی می‌شود:

  • LabelPost از نوع [System.Web.UI.WebControls.Label] است (به Default.aspx.designer.cs مراجعه کنید). خاصیت Text آن، متنی را که توسط کامپوننت نمایش داده می‌شود، نشان می‌دهد.
  • TextBoxNom و TextBoxAge از نوع [System.Web.UI.WebControls.TextBox] هستند. ویژگی Text یک کامپوننت TextBox، متنی است که در فیلد ورودی نمایش داده می‌شود.
  • متد Trim() هرگونه فضای خالی را که ممکن است قبل یا بعد از یک رشته قرار داشته باشد، حذف می‌کند.

همان‌طور که قبلاً توضیح داده شد، وقتی متد ButtonValider_Click اجرا می‌شود، اجزای صفحه همان ارزشی را دارند که هنگام ارسال صفحه توسط کاربر داشتند. بنابراین، ویژگی‌های Text هر دو متد TextBox مقادیر متنی را که کاربر در مرورگر وارد کرده است، به خود اختصاص می‌دهند.

در اینجا یک مثال آورده شده است:

  • در [1]، مقادیر ارسال‌شده
  • در [2]، پاسخ سرور.
  • در [3]، فیلدهای TextBox از طریق مکانیزم VIEWSTATE فعال‌شده به مقادیر ارسال‌شده خود بازگردانده شده‌اند
  • در [4]، پیام‌های مؤلفه ListBoxEvts از متدهای Page_Init نشأت می‌گیرند، Page_Load، ButtonValider_Click و یک VIEWSTATE غیرفعال
  • در [5]، مؤلفه LabelPost مقدار خود را با استفاده از روش ButtonValider_Click به‌دست آورد. ما با موفقیت دو مقداری را که کاربر در دو کامپوننت TextBox و [1] وارد کرده است، بازیابی کردیم.

همان‌طور که در بالا مشاهده می‌شود، مقداری که برای سن ارسال شده، رشته «yy» است که یک مقدار نامعتبر است. ما قصد داریم کامپوننت‌هایی به نام اعتبارسنج (validator) به صفحه اضافه کنیم. این‌ها برای بررسی اعتبار داده‌های ارسال‌شده استفاده می‌شوند. این اعتبار را می‌توان در دو مکان بررسی کرد:

  • در سمت کلاینت. یک گزینه پیکربندی اعتبارسنج به شما امکان می‌دهد انتخاب کنید که آیا بررسی‌ها باید در مرورگر انجام شوند یا خیر. در صورت مثبت بودن پاسخ، این بررسی‌ها توسط کد JavaScript که در صفحه HTML جاسازی شده است، انجام می‌شوند. هنگامی که کاربر مقادیر وارد شده در فرم را ارسال می‌کند، این مقادیر ابتدا توسط کد جاوااسکریپت بررسی می‌شوند. اگر هر یک از بررسی‌ها با شکست مواجه شود، ارسال انجام نخواهد شد. این کار از رفت و برگشت به سرور جلوگیری می‌کند و در نتیجه صفحه را پاسخگوتر می‌سازد.
  • در سمت سرور. در حالی که اعتبارسنجی سمت کلاینت ممکن است اختیاری باشد، اعتبارسنجی سمت سرور صرف‌نظر از اینکه اعتبارسنجی سمت کلاینت انجام شده باشد یا نه، اجباری است. این به آن دلیل است که وقتی یک صفحه مقادیر ارسال‌شده را دریافت می‌کند، هیچ راهی برای دانستن اینکه آیا این مقادیر قبل از ارسال توسط کلاینت اعتبارسنجی شده‌اند یا خیر، ندارد. بنابراین، در سمت سرور، توسعه‌دهنده باید همیشه اعتبار داده‌های ارسال‌شده را بررسی کند.

صفحه [Default.aspx] به شرح زیر تغییر می‌کند:


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Intro._Default" %>

<!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 runat="server">
  <title>Introduction ASP.NET</title>
</head>
<body>
  <h3>Introduction à ASP.NET</h3>
  <form id="form1" runat="server">
  <div>
    <table>
      <tr>
        <td>
          Nom</td>
        <td>
          <asp:TextBox ID="TextBoxNom" runat="server"></asp:TextBox>
        </td>
        <td>
          <asp:RequiredFieldValidator ID="RequiredFieldValidatorNom" runat="server" 
            ControlToValidate="TextBoxNom" Display="Dynamic" 
            ErrorMessage="Donnée obligatoire !"></asp:RequiredFieldValidator>
        </td>
      </tr>
      <tr>
        <td>
          Age</td>
        <td>
          <asp:TextBox ID="TextBoxAge" runat="server"></asp:TextBox>
        </td>
        <td>
          <asp:RequiredFieldValidator ID="RequiredFieldValidatorAge" runat="server" 
            ControlToValidate="TextBoxAge" Display="Dynamic" 
            ErrorMessage="Donnée obligatoire !"></asp:RequiredFieldValidator>
          <asp:RangeValidator ID="RangeValidatorAge" runat="server" 
            ControlToValidate="TextBoxAge" Display="Dynamic" 
            ErrorMessage="Tapez un nombre entre 1 et 150 !" MaximumValue="150" 
            MinimumValue="1" Type="Integer"></asp:RangeValidator>
        </td>
      </tr>
    </table>
  </div>
  <asp:Button ID="ButtonValider" runat="server" onclick="ButtonValider_Click" 
    Text="Valider" CausesValidation="False"/>
  <hr />
  <p>
    Evénements traités par le serveur</p>
  <p>
    <asp:ListBox ID="ListBoxEvts" runat="server" EnableViewState="False">
    </asp:ListBox>
  </p>
  <p>
    Eléments postés au serveur :
    <asp:Label ID="LabelPost" runat="server"></asp:Label>
  </p>
  <p>
    Eléments validés par le serveur :
    <asp:Label ID="LabelValidation" runat="server"></asp:Label>
  </p>
  <asp:Label ID="LabelErreursSaisie" runat="server" ForeColor="Red"></asp:Label>
  </form>
</body>
</html>

اعتبارسنج‌ها به خطوط ۲۰، ۳۲ و ۳۵ اضافه شده‌اند. در خط ۵۸، یک کامپوننت Label برای نمایش مقادیر ارسال‌شده معتبر استفاده می‌شود. در خط ۶۰، یک کامپوننت Label برای نمایش پیام خطا در صورت وجود هرگونه خطای ورودی استفاده می‌شود.

صفحه [Default.aspx] در حالت [Design] به شرح زیر است:

  • کامپوننت‌های [1] و [2] از نوع RequiredFieldValidator هستند. این اعتبارسنج بررسی می‌کند که یک فیلد ورودی خالی نباشد.
  • کامپوننت [3] از نوع RangeValidator است. این اعتبارسنج بررسی می‌کند که یک فیلد ورودی حاوی مقداری در محدوده مشخص‌شده باشد.
  • در [4]، ویژگی‌های اعتبارسنج [1].

ما دو نوع اعتبارسنج را از طریق تگ‌هایشان در کد صفحه [Default.aspx] ارائه خواهیم داد:


          <asp:RequiredFieldValidator ID="RequiredFieldValidatorNom" runat="server" 
            ControlToValidate="TextBoxNom" Display="Dynamic" 
ErrorMessage="Donnée obligatoire !"></asp:RequiredFieldValidator>
  • ID: شناسه‌ی کامپوننت
  • ControlToValidate: نام جزئیه‌ای که مقدار آن در حال بررسی است. در اینجا، می‌خواهیم اطمینان حاصل کنیم که جزء TextBoxNom مقدار خالی (یک رشته خالی یا دنباله‌ای از فضاها) ندارد.
  • ErrorMessage: پیام خطایی که در صورت داده‌های نامعتبر در اعتبارسنج نمایش داده می‌شود.
  • EnableClientScript: یک مقدار بولی که مشخص می‌کند آیا اعتبارسنج باید در سمت کلاینت نیز اجرا شود یا خیر. این ویژگی در صورتی که به صورت واضح مانند بالا تنظیم نشده باشد، دارای مقدار پیش‌فرض True است.
  • نمایش: حالت نمایش اعتبارسنج. دو حالت وجود دارد:
    • static (پیش‌فرض): اعتبارسنج در صفحه فضا اشغال می‌کند حتی اگر پیام خطا نمایش ندهد
    • dynamic: اعتبارسنج جای خود را در صفحه اشغال نمی‌کند اگر هیچ پیام خطایی نمایش ندهد.

          <asp:RangeValidator ID="RangeValidatorAge" runat="server" 
            ControlToValidate="TextBoxAge" Display="Dynamic" 
            ErrorMessage="Tapez un nombre entre 1 et 150 !" MaximumValue="150" 
            MinimumValue="1" Type="Integer"></asp:RangeValidator>
  • نوع: نوع داده‌ای که اعتبارسنجی می‌شود. در اینجا، سن یک عدد صحیح است.
  • MinimumValue، MaximumValue: محدودیت‌هایی که مقدار اعتبارسنجی‌شده باید در آن‌ها قرار گیرد

پیکربندی جزئی که POST را فعال می‌کند، بر روش اعتبارسنجی تأثیر می‌گذارد. در اینجا، این جزء دکمه‌ی [Valider] است:


  <asp:Button ID="ButtonValider" runat="server" onclick="ButtonValider_Click"  Text="Valider" CausesValidation="True" />
  • CausesValidation: حالت خودکار یا نام اعتبارسنجی‌های سمت سرور را تعیین می‌کند. این ویژگی در صورت عدم مشخص شدن صریح، مقدار پیش‌فرض «True» را دارد. در این مورد،
    • در سمت کلاینت، اعتبارسنج‌هایی با شناسه‌های بین EnableClientScript تا True اجرا می‌شوند. POST تنها در صورتی فعال می‌شود که همه اعتبارسنج‌های سمت کلاینت با موفقیت اجرا شوند.
    • در سمت سرور، تمام اعتبارسنج‌هایی که در صفحه وجود دارند، به‌طور خودکار قبل از پردازش رویدادی که POST را تحریک کرده است، اجرا می‌شوند. در اینجا، آن‌ها قبل از فراخوانی متد ButtonValider_Click اجرا خواهند شد. درون این متد، می‌توان تشخیص داد که آیا تمام اعتبارسنجی‌ها با موفقیت انجام شده‌اند یا خیر. مقدار Page.IsValid در صورتی که همه با موفقیت انجام شده باشند «True» و در غیر این صورت «False» است. در حالت دوم، پردازش رویدادی که POST را فعال کرده است، می‌تواند متوقف شود. صفحه ارسال‌شده دقیقاً همان‌طور که وارد شده بود بازگردانده می‌شود. اعتبارسنج‌هایی که ناموفق بوده‌اند سپس پیام‌های خطای خود را نمایش می‌دهند (ویژگی ErrorMessage).

اگر CausesValidation مقدار False را داشته باشد، آنگاه

  • در سمت کلاینت، هیچ اعتبارسنجی اجرا نمی‌شود
  • در سمت سرور، این وظیفه توسعه‌دهنده است که خود فراخوانی اعتبارسنج‌های صفحه را انجام دهد. آنها این کار را با استفاده از متد Page.Validate() انجام می‌دهند. بسته به نتیجه اعتبارسنجی‌ها، این متد خاصیت Page.IsValid را روی «True» یا «False» تنظیم می‌کند.

در [Default.aspx.cs]، کد پردازش برای ButtonValider_Click به شرح زیر تغییر می‌کند:


protected void ButtonValider_Click(object sender, EventArgs e)
    {
      // رویداد را ثبت کنید
      ListBoxEvts.Items.Insert(0, string.Format("{0}: ButtonValider_Click", DateTime.Now.ToString("hh:mm:ss")));
      // نمایش نام و سن
      LabelPost.Text = string.Format("nom={0}, age={1}", TextBoxNom.Text.Trim(), TextBoxAge.Text.Trim());
      // آیا صفحه معتبر است؟
      Page.Validate();
      if (!Page.IsValid)
      {
        // پیام خطای عمومی
        LabelErreursSaisie.Text = "Veuillez corriger les erreurs de saisie...";
        LabelErreursSaisie.Visible = true;
        return;
      }
      // پنهان کردن پیام خطا
      LabelErreursSaisie.Visible = false;
      // نمایش نام و سن تأییدشده
      LabelValidation.Text = string.Format("nom={0}, age={1}", TextBoxNom.Text.Trim(), TextBoxAge.Text.Trim());
}

اگر دکمه [Valider] دارای ویژگی CausesValidation تنظیم‌شده روی True و اعتبارسنج‌ها دارای ویژگی EnableClientScript تنظیم‌شده روی True باشند، متد ButtonValider_Click تنها زمانی اجرا می‌شود که مقادیر ارسال‌شده معتبر باشند. در این صورت ممکن است به هدف کد موجود از خط ۸ به بعد فکر کرد. مهم است به یاد داشته باشید که همیشه می‌توان یک برنامه کلاینت نوشت که مقادیر تأییدنشده را به صفحه [Default.aspx] ارسال کند. بنابراین، این صفحه باید همیشه دوباره بررسی‌های اعتبارسنجی را اجرا کند.

  • خط ۸: اجرای تمام اعتبارسنج‌ها در صفحه را تحریک می‌کند. اگر دکمه [Valider] ویژگی CausesValidation خود را روی True تنظیم کرده باشد، این کار به طور خودکار انجام می‌شود و نیازی به تکرار آن نیست. در اینجا تکرار وجود دارد.
  • خطوط ۹–۱۵: حالتی که یکی از اعتبارسنج‌ها شکست خورده است
  • خطوط 16–19: حالتی که همه اعتبارسنج‌ها با موفقیت عبور کرده‌اند

در اینجا دو مثال از خروجی آورده شده است:

  • در [1]، مثالی از اجرا که:
    • دکمه [Valider] ویژگی خود را از CausesValidation به True تنظیم می‌کند
    • ویژگی validators به مقدار True تنظیم شده است

پیام‌های خطا [2] توسط اعتبارسنج‌هایی که در سمت کلاینت با کد جاوااسکریپت صفحه اجرا می‌شوند، نمایش داده شدند. هیچ POST به سرور ارسال نشد، همانطور که توسط برچسب عناصر ارسال‌شده [3] نشان داده شده است.

  • در [4]، مثالی از اجرا که در آن:
    • دکمه [Valider] دارای مقداردهی شده برای ویژگی CausesValidation به False است
    • ویژگی EnableClientScript اعتبارسنج‌ها روی False تنظیم شده است

پیام‌های خطا [5] توسط اعتبارسنج‌های سمت سرور نمایش داده شدند. همانطور که توسط [6] نشان داده شده است، یک POST در واقع به سرور ارسال شد. در [7]، پیام خطایی که توسط متد [ButtonValider_Click] در صورت بروز خطاهای ورودی نمایش داده می‌شود.

  • در [8]، مثالی که با داده‌های معتبر به‌دست آمده است. [9,10] نشان می‌دهد که آیتم‌های ارسال‌شده اعتبارسنجی شده‌اند. هنگام اجرای آزمون‌های مکرر، ویژگی EnableViewState از برچسب [LabelValidation] باید روی False تنظیم شود تا پیام اعتبارسنجی در تمام دوره‌های اجرا نمایش داده نشود.

2.4. مدیریت داده‌های دامنه – برنامه

بیایید معماری اجرای یک صفحه ASPX را مجدداً بررسی کنیم:

کلاس صفحه ASPX در ابتدای درخواست مشتری ایجاد و در پایان آن نابود می‌شود. در نتیجه، نمی‌توان از آن برای ذخیره داده‌ها بین درخواست‌ها استفاده کرد. دو نوع داده وجود دارد که ممکن است نیاز به ذخیره داشته باشند:

  • داده‌های مشترک بین همه کاربران وب‌اپلیکیشن. این داده‌ها معمولاً فقط قابل خواندن هستند. سه فایل برای پیاده‌سازی این اشتراک‌گذاری داده استفاده می‌شوند:
    • [Web.Config]: فایل پیکربندی برنامه
    • [Global.asax, Global.asax.cs]: برای تعریف کلاسی به نام کلاس برنامه جهانی (global application class) استفاده می‌شود که چرخه عمر آن با چرخه عمر برنامه مطابقت دارد، و همچنین برای تعریف هندلرهای رویدادهای خاص در آن برنامه.

کلاس جهانی برنامه به شما امکان می‌دهد داده‌هایی را تعریف کنید که برای تمام درخواست‌های همه کاربران در دسترس خواهد بود.

  • داده‌هایی که در میان درخواست‌های یک کلاینت مشترک می‌شوند. این داده‌ها در ابجکتی به نام Session ذخیره می‌شوند. اصطلاح «جلسه کلاینت» برای اشاره به حافظه کلاینت به کار می‌رود. تمام درخواست‌های یک کلاینت به این جلسه دسترسی دارند. آنها می‌توانند اطلاعات را در آن ذخیره و بخوانند.

در بالا، انواع حافظه‌ای را که یک صفحه به آن دسترسی دارد، نشان می‌دهیم:

  • حافظهٔ برنامه، که عمدتاً حاوی داده‌های فقط-خواندنی است و برای همهٔ کاربران قابل دسترسی است.
  • حافظه یک کاربر خاص، یا جلسه، که حاوی داده‌های خواندنی/نوشتنی است و برای درخواست‌های متوالی از همان کاربر قابل دسترسی است.
  • در بالا، حافظه درخواست، یا زمینه درخواست، نشان داده نشده است. درخواست یک کاربر ممکن است توسط چندین صفحه متوالی ASPX پردازش شود. زمینه درخواست به صفحه ۱ امکان می‌دهد اطلاعات را به صفحه ۲ منتقل کند.

در اینجا، ما به داده‌های دامنه Application، یعنی داده‌هایی که بین همه کاربران مشترک است، علاقه‌مند هستیم. کلاس جهانی برنامه را می‌توان به صورت زیر ایجاد کرد:

  • در [1]، یک عنصر جدید به پروژه اضافه می‌شود
  • در [2]، کلاس جهانی برنامه را اضافه می‌کنیم
  • در [3]، نام پیش‌فرض [Global.asax] برای عنصر جدید حفظ می‌شود
  • در [4]، دو فایل جدید به پروژه اضافه شده‌اند
  • در [5]، نشانه‌گذاری برای [Global.asax] نمایش داده می‌شود

<%@ Application Codebehind="Global.asax.cs" Inherits="Intro.Global" Language="C#" %>
  • برچسب Application جایگزین برچسب Page است که برای [Default.aspx] داشتیم. این برچسب کلاس جهانی برنامه را شناسایی می‌کند
  • کدبیهایند: فایلی را مشخص می‌کند که در آن کلاس جهانی برنامه تعریف شده است
  • میراث‌بردار از: نام این کلاس را مشخص می‌کند

کلاس تولیدشده Intro.Global به شرح زیر است:


using System;

namespace Intro
{
  public class Global : System.Web.HttpApplication
  {

    protected void Application_Start(object sender, EventArgs e)
    {

    }

    protected void Session_Start(object sender, EventArgs e)
    {

    }

    protected void Application_BeginRequest(object sender, EventArgs e)
    {

    }

    protected void Application_AuthenticateRequest(object sender, EventArgs e)
    {

    }

    protected void Application_Error(object sender, EventArgs e)
    {

    }

    protected void Session_End(object sender, EventArgs e)
    {

    }

    protected void Application_End(object sender, EventArgs e)
    {

    }
  }
}
  • خط ۵: کلاس جهانی برنامه از کلاس HttpApplication ارث می‌برد

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

  • خطوط ۸ و ۳۸: رویدادهای Application_Start (شروع برنامه) و Application_End (پایان برنامه هنگام خاموش شدن وب‌سرور یا هنگام خارج کردن برنامه توسط مدیر) را مدیریت می‌کنند
  • خطوط ۱۳، ۳۳: رویدادهای Session_Start (شروع یک جلسه جدید کلاینت هنگامی که یک کلاینت جدید می‌رسد یا زمانی که یک جلسه موجود منقضی می‌شود) و Session_End (پایان یک جلسه کلاینت، یا به طور صریح از طریق برنامه‌نویسی یا به طور ضمنی به دلیل فراتر رفتن جلسه از مدت زمان مجاز خود) را مدیریت می‌کند.
  • خط ۲۸: رویداد Application_Error را مدیریت می‌کند (رخداد یک استثنا که توسط کد برنامه مدیریت نشده و به سرور ارجاع داده می‌شود)
  • خط ۱۸: رویداد Application_BeginRequest (ورود یک درخواست جدید) را مدیریت می‌کند.
  • خط ۲۳: رویداد Application_AuhenticateRequest را مدیریت می‌کند (هنگامی که کاربر احراز هویت شده است رخ می‌دهد).

متد [Application_Start] اغلب برای راه‌اندازی برنامه با استفاده از اطلاعاتی که در [Web.Config] وجود دارد، استفاده می‌شود. متدی که هنگام ایجاد اولیه پروژه تولید می‌شود، به این شکل است:


<?xml version="1.0" encoding="utf-8"?>

<configuration>
    <configSections>
...
    </configSections>  
  
    <appSettings/>
    <connectionStrings/>
  
    <system.web>
...
    </system.web>

    <system.codedom>
....
    </system.codedom>
    
    <!-- 
        La section system.webServer est requise pour exécuter ASP.NET AJAX sur Internet
        Information Services 7.0.  Elle n'est pas nécessaire pour les versions précédentes d'IIS.
    -->
    <system.webServer>
...
    </system.webServer>

    <runtime>
....
    </runtime>

</configuration>

برای برنامه فعلی ما، این فایل غیرضروری است. اگر آن را حذف یا نامش را تغییر دهیم، برنامه به طور معمول به کار خود ادامه خواهد داد. اکنون به تگ‌های روی خطوط ۸ و ۹ نگاه می‌کنیم:

  • <appsettings> به شما امکان می‌دهد یک فرهنگ لغت از اطلاعات را تعریف کنید
  • <connectionStrings> برای تعریف رشته‌های اتصال پایگاه داده استفاده می‌شود

بیایید فایل زیر را در نظر بگیریم: [Web.config]


<?xml version="1.0" encoding="utf-8"?>

<configuration>
    <configSections>
...
    </configSections>  
  
  <appSettings>
    <add key="cle1" value="valeur1"/>
    <add key="cle2" value="valeur2"/>
  </appSettings>
  <connectionStrings>
    <add connectionString="connectionString1" name="conn1"/>
  </connectionStrings>
  
    <system.web>
...

این فایل می‌تواند توسط کلاس جهانی زیر استفاده شود:


using System;
using System.Configuration;

namespace Intro
{
  public class Global : System.Web.HttpApplication
  {
    public static string Param1 { get; set; }
    public static string Param2 { get; set; }
    public static string ConnString1 { get; set; }
    public static string Erreur { get; set; }

    protected void Application_Start(object sender, EventArgs e)
    {
      try
      {
        Param1 = ConfigurationManager.AppSettings["cle1"];
        Param2 = ConfigurationManager.AppSettings["cle2"];
        ConnString1 = ConfigurationManager.ConnectionStrings["conn1"].ConnectionString;
      }
      catch (Exception ex)
      {
        Erreur = string.Format("Erreur de configuration : {0}", ex.Message);
      }
    }

    protected void Session_Start(object sender, EventArgs e)
    {

    }

  }
}
  • خطوط ۸–۱۱: چهار خاصیت ایستا P. از آنجایی که عمر کلاس Global برابر با عمر برنامه است، هر پرس‌وجوی انجام‌شده در برنامه از طریق سینتکس Global.P به این خاصیت‌های P دسترسی خواهد داشت.
  • خطوط 17–19: فایل [Web.config] از طریق کلاس [System.Configuration.ConfigurationManager] قابل دسترسی است
  • خطوط ۱۷–۱۸: عناصر تگ <appSettings> را از فایل [Web.config] از طریق ویژگی key بازیابی می‌کند.
  • خط ۱۹: عناصر تگ <connectionStrings> را از فایل [Web.config] از طریق ویژگی name بازیابی می‌کند.

ویژگی‌های ثابت در خطوط ۸–۱۱ از هر دستگیرکننده رویداد روی صفحات بارگذاری‌شده ASPX قابل دسترسی هستند. ما از آن‌ها در دستگیرکننده [Page_Load] روی صفحه [Default.aspx] استفاده می‌کنیم:


    protected void Page_Load(object sender, EventArgs e)
    {
      // رویداد را ثبت کنید
      ListBoxEvts.Items.Insert(0, string.Format("{0}: Page_Load", DateTime.Now.ToString("hh:mm:ss")));
      // بازیابی اطلاعات از کلاس جهانی برنامه
      LabelGlobal.Text = string.Format("Param1={0},Param2={1},ConnString1={2},Erreur={3}", Global.Param1, Global.Param2, Global.ConnString1, Global.Erreur);
}
  • خط ۶: چهار ویژگی ایستا از کلاس جهانی برنامه برای پر کردن یک برچسب جدید در صفحه [Default.aspx] استفاده می‌شوند

پس از اجرا، نتیجه زیر را دریافت می‌کنیم:

در بالا می‌بینیم که پارامترهای [web.config] به‌درستی بازیابی شده‌اند. کلاس جهانی برنامه مکان مناسبی برای ذخیره‌سازی اطلاعاتی است که توسط همه کاربران به اشتراک گذاشته می‌شود.

2.5. مدیریت داده‌های در محدوده جلسه

در اینجا، ما در حال بررسی نحوه ذخیره اطلاعات در سرتاسر درخواست‌های یک کاربر مشخص هستیم:

هر کاربر حافظه‌ی مخصوص به خود را دارد که به آن جلسه (session) گفته می‌شود.

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

  • Session_Start: شروع یک جلسه
  • Session_end: پایان یک جلسه

مکانیزم جلسه به شرح زیر عمل می‌کند:

  • وقتی کاربر اولین درخواست خود را ارسال می‌کند، وب‌سرور یک توکن جلسه ایجاد کرده و آن را به کاربر اختصاص می‌دهد. این توکن یک رشتهٔ منحصربه‌فرد از کاراکترها برای هر کاربر است. این توکن توسط سرور در پاسخ به اولین درخواست کاربر ارسال می‌شود.
  • در درخواست‌های بعدی، کاربر (مرورگر وب) توکن جلسه را که به او اختصاص داده شده است، در درخواست خود درج می‌کند. این امر به وب‌سرور امکان می‌دهد تا او را شناسایی کند.
  • یک جلسه (session) دارای یک دوره زمانی (lifetime) است. هنگامی که وب‌سرور درخواستی را از کاربر دریافت می‌کند، زمان سپری‌شده از آخرین درخواست را محاسبه می‌کند. اگر این زمان از دوره زمانی جلسه فراتر رود، یک جلسه جدید برای کاربر ایجاد می‌شود. داده‌های جلسه قبلی از بین می‌رود. در سرور وب IIS مایکروسافت (Internet Information Server)، جلسات دارای عمر پیش‌فرض ۲۰ دقیقه هستند. این مقدار را می‌توان توسط مدیر سرور وب تغییر داد.
  • سرور وب می‌داند که در حال رسیدگی به اولین درخواست کاربر است زیرا این درخواست حاوی توکن جلسه نیست. این تنها درخواست است.

هر صفحه ASP.NET از طریق خاصیت Session صفحه که از نوع [System.Web.SessionState.HttpSessionState] است، به جلسه کاربر دسترسی دارد. ما از ویژگی‌های P و متدهای M زیر کلاس HttpSessionState استفاده خواهیم کرد:

نام
نوع
نقش
Item[String clé]
P
جلسه می‌تواند به صورت یک فرهنگ‌لغت ساختاردهی شود. Item[clé] عنصر جلسه است که توسط clé شناسایی می‌شود. به جای نوشتن [HttpSessionState].Item[clé]، می‌توان [HttpSessionState].[clé] را نیز نوشت.
پاک کردن
M
واژه‌نامه جلسه را پاک می‌کند
لغو
M پاک کردن فرهنگ لغت جلسهWithdrawal پایان جلسه را اعلام می‌کند. پس از آن، جلسه دیگر معتبر نخواهد بود
جلسه را پایان می‌دهد. پس از آن، جلسه دیگر معتبر نخواهد بود. یک جلسه جدید با درخواست بعدی کاربر آغاز خواهد شد.

به‌عنوان مثالی از حافظهٔ کاربر، تعداد دفعات کلیک کاربر روی دکمهٔ [Valider] را شمارش می‌کنیم. برای این کار، باید یک شمارنده در طول جلسهٔ کاربر نگهداری شود.

صفحه [Default.aspx] به شرح زیر تغییر می‌کند:

کلاس جهانی برنامه [Global.asax.cs] به شرح زیر تکامل می‌یابد:


using System;
using System.Configuration;

namespace Intro
{
  public class Global : System.Web.HttpApplication
  {
    public static string Param1 { get; set; }
...

    protected void Application_Start(object sender, EventArgs e)
    {
...
    }

    protected void Session_Start(object sender, EventArgs e)
    {
      // شمارنده درخواست
      Session["nbRequêtes"] = 0;
    }

  }
}

در خط ۱۹، از جلسه کاربر برای ذخیره یک شمارنده درخواست با کلید «nbRequêtes» استفاده می‌شود. این شمارنده توسط پردازشگر [ButtonValider_Click] در صفحه [Default.aspx] به‌روزرسانی می‌شود:


using System;

namespace Intro
{
  public partial class _Default : System.Web.UI.Page
  {
....

    protected void ButtonValider_Click(object sender, EventArgs e)
    {
      //رویداد ثبت می‌شود
      ListBoxEvts.Items.Insert(0, string.Format("{0}: ButtonValider_Click", DateTime.Now.ToString("hh:mm:ss")));
      // نمایش نام و سن ارسال‌شده
      LabelPost.Text = string.Format("nom={0}, age={1}", TextBoxNom.Text.Trim(), TextBoxAge.Text.Trim());
      // تعداد درخواست‌ها
      Session["nbRequêtes"] = (int)Session["nbRequêtes"] + 1;
      LabelNbRequetes.Text = Session["nbRequêtes"].ToString();
      // آیا صفحه معتبر است؟
      Page.Validate();
      if (!Page.IsValid)
      {
...
      }
...
    }
  }
}
  • خط ۱۶: شمارنده درخواست افزایش می‌یابد
  • خط ۱۷: شمارنده در صفحه نمایش داده می‌شود

در اینجا مثالی از خروجی آورده شده است:

2.6. پردازش GET / POST هنگام بارگذاری یک صفحه

ما اشاره کردیم که دو نوع درخواست به یک صفحه ASPX وجود دارد:

  • درخواست اولیه از مرورگر با استفاده از فرمان HTTP یا GET. سرور با ارسال صفحهٔ درخواستی پاسخ می‌دهد. فرض می‌کنیم این صفحه یک فرم به نام c.a.d است و صفحه‌ای که ارسال شده (ASPX) دارای تگ <form runat="server"...> است.
  • درخواست‌های بعدی توسط مرورگر در پاسخ به برخی عملیات کاربر روی فرم ارسال می‌شوند. سپس مرورگر درخواستی ارسال می‌کند: HTTP POST.

چه درخواست GET باشد چه درخواست POST، متد [Page_Load] اجرا می‌شود. در طول GET، این متد معمولاً برای اولیه کردن صفحه‌ای که به مرورگر کلاینت ارسال می‌شود، استفاده می‌شود. سپس، از طریق مکانیزم VIEWSTATE، صفحه در حالت اولیه باقی می‌ماند و تنها توسط رویدادپردازهایی که POST را فعال می‌کنند، تغییر می‌یابد. نیازی به بازآماده‌سازی صفحه در Page_Load نیست. از این رو، این روش برای تعیین اینکه آیا درخواست کلاینت یک GET است یا یک POST، مورد استفاده قرار می‌گیرد.

بیایید به مثال زیر نگاه کنیم. یک لیست کشویی به صفحه [Default.aspx] اضافه شده است. محتوای این لیست در هاندر Page_Load برای درخواست GET تعریف خواهد شد:

فهرست کشویی در [Default.aspx.designer.cs] به شرح زیر اعلام شده است:


        protected global::System.Web.UI.WebControls.DropDownList DropDownListNoms;

ما از روش‌های زیر M و ویژگی‌های P کلاس [DropDownList] استفاده خواهیم کرد:

نام
نوع
نقش
موارد
P
مجموعه‌ای از نوع ListItemCollection حاوی عناصری از نوع ListItem از لیست کشویی
SelectedIndex
P
شاخص، با شروع از ۰، مورد انتخاب‌شده از فهرست کشویی هنگام ارسال فرم
SelectedItem
P
عنصر از نوع ListItem که هنگام ارسال فرم از لیست کشویی انتخاب شده است
SelectedValue
P
مقدار از نوع string برای عنصر از نوع ListItem که هنگام ارسال فرم از لیست کشویی انتخاب می‌شود. ما به زودی این مفهوم مقدار را تعریف خواهیم کرد.

کلاس ListItem برای عناصر در یک لیست کشویی برای تولید تگ‌های <option> درون تگ‌های HTML و <select> استفاده می‌شود:

1
2
3
4
5
<select ....>
    <option value="val1">texte1</option>
    <option value="val2">texte2</option>
....
</select>

درون تگ <option>

  • textei متنی است که در لیست کشویی نمایش داده می‌شود
  • vali مقداری است که توسط مرورگر ارسال می‌شود اگر textei متنی باشد که از لیست کشویی انتخاب شده است

هر گزینه می‌تواند توسط یک شیء LisItem که با استفاده از سازنده ListItem(string text, string value) ایجاد شده است، تولید شود.

در [Default.aspx.cs]، کد برای دستگیرکننده [Page_Load] به شرح زیر تغییر می‌کند:


    protected void Page_Load(object sender, EventArgs e)
    {
      // رویداد را ثبت می‌کند
      ...
      // اطلاعات را از کلاس جهانی برنامه بازیابی می‌کند
      ...
      // فقط در هنگام راه‌اندازی اولیه، لیست کشویی نام را inicialise می‌کند GET
      if (!IsPostBack)
      {
        for (int i = 0; i < 3; i++)
        {
          DropDownListNoms.Items.Add(new ListItem("nom"+i,i.ToString()));
        }
      }
}
  • خط ۸: کلاس Page دارای یک ویژگی IsPostBack از نوع Boolean است. در واقع، این بدان معناست که درخواست کاربر یک POST است. دستورالعمل‌های ۱۰ تا ۱۳ بنابراین تنها در GET اولیهٔ مشتری اجرا می‌شوند.
  • خط ۱۲: یک عنصر از نوع ListItem (متن رشته‌ای، مقدار رشته‌ای) به لیست [DropDownListNoms] اضافه می‌شود. متن نمایش داده شده برای عنصر (i+1)ام nomi خواهد بود و مقدار ارسال شده برای این عنصر، در صورت انتخاب، i خواهد بود.

هندلر [ButtonValider_Click] اصلاح شده است تا مقداری را که از طریق لیست کشویی ارسال شده است نمایش دهد:


    protected void ButtonValider_Click(object sender, EventArgs e)
    {
      // رویداد را ثبت کنید
...
      //نمایش مقادیر ارسال‌شده
      LabelPost.Text = string.Format("nom={0}, age={1}, combo={2}", TextBoxNom.Text.Trim(), TextBoxAge.Text.Trim(), DropDownListNoms.SelectedValue);
      // تعداد درخواست‌ها
...
}

در خط ۶، مقدار ارسال‌شده برای لیست [DropDownListNoms] با استفاده از خاصیت SelectedValue آن لیست به دست می‌آید. در اینجا مثالی از اجرای آن آمده است:

  • در [1]، محتوای لیست کشویی پس از GET اولیه و درست قبل از اولین POST
  • در [2]، صفحه پس از اولین POST.
  • در [3]، مقداری که برای لیست کشویی ارسال شده است. این معادل ویژگی value از ListItem انتخاب‌شده از لیست است.
  • در [4]، فهرست کشویی. این فهرست شامل همان موارد پس از GET اولیه است. این امر به دلیل مکانیزم VIEWSTATE است.

برای درک تعامل بین VIEWSTATE در لیست DropDownListNoms و شرط if (! IsPostBack) در دستگیرکننده Page_Load از [Default.aspx]، خواننده دعوت می‌شود تا آزمون قبلی را با پیکربندی‌های زیر تکرار کند:

مورد
DropDownListNoms.EnableViewState
if test (! IsPostBack) در Page_Load از [Default.aspx]
1
true
présent
2
false
présent
3
true
absent
4
false
absent

آزمایش‌های مختلف نتایج زیر را می‌دهند:

  1. این مورد همان موردی است که در بالا توضیح داده شد
  2. فهرست در طول عملیات اولیه GET پر می‌شود اما در طول عملیات بعدی POST پر نمی‌شود. از آنجا که EnableViewState مقدار false را برمی‌گرداند، فهرست پس از هر POST خالی است
  3. لیست هم پس از اجرای اولیه GET و هم در طول اجراهای بعدی POST پر می‌شود. از آنجایی که EnableViewState با vrai مطابقت دارد، پس از GET اولیه ۳ نام، پس از اولین POST ۶ نام، پس از دومین POST ۹ نام، ...
  4. این فهرست هم پس از GET اولیه و هم در طول عملیات بعدی POST پر می‌شود. از آنجا که EnableViewState با faux یکسان است، فهرست تنها با سه نام برای هر پرس‌وجو پر می‌شود، چه پرس‌وجوی اولیه GET باشد یا پرس‌وجوهای بعدی POST. این رفتار مشابه مورد ۱ است. بنابراین دو راه برای دستیابی به نتیجه یکسان وجود دارد.

2.7. پردازش عناصر VIEWSTATE در یک صفحه ASPX

به طور پیش‌فرض، تمام عناصر در یک صفحه ASPX دارای خاصیت EnableViewState با مقدار True هستند. هر بار که صفحه ASPX به مرورگر کلاینت ارسال می‌شود، این صفحه حاوی فیلد مخفی __VIEWSTATE است که مقدار آن رشته‌ای است که تمام مقادیر کامپوننت‌هایی را که ویژگی‌هایشان در بازه EnableViewState تا True قرار دارد، رمزگذاری می‌کند. برای به حداقل رساندن اندازه این رشته، می‌توان تعداد کامپوننت‌هایی را که ویژگی‌هایشان در بازه EnableViewState تا True قرار دارند، کاهش داد.

بیایید به یاد بیاوریم که چگونه اجزای صفحه‌ای با شناسه ASPX مقادیر خود را پس از یک POST دریافت می‌کنند:

  1. صفحه ASPX نمونه سازی می‌شود. اجزا با مقادیر طراحی خود اولیه می‌شوند.
  2. مقدار __VIEWSTATE ارسال‌شده توسط مرورگر برای تنظیم اجزا به همان مقداری که هنگام ارسال صفحه ASPX به مرورگر در بار قبلی داشتند، استفاده می‌شود.
  3. مقادیر ارسال‌شده توسط مرورگر به کامپوننت‌ها اختصاص داده می‌شوند
  4. پردازشگرهای رویداد اجرا می‌شوند. آن‌ها ممکن است مقادیر برخی از مؤلفه‌ها را تغییر دهند.

از این توالی می‌توان نتیجه گرفت که کامپوننت‌هایی که:

  • ارزش‌هایشان ارسال می‌شود
  • ارزش‌هایشان توسط یک رویدادپرداز تغییر می‌کند

ممکن است ویژگی آن‌ها روی EnableViewState یا Faux تنظیم شود، زیرا مقدار VIEWSTATE (مرحله ۲) آن‌ها توسط مرحله ۳ یا ۴ تغییر خواهد کرد.

فهرست کامپوننت‌های صفحه ما در [Default.aspx.designer.cs] موجود است:


namespace Intro {
    public partial class _Default {
        protected global::System.Web.UI.HtmlControls.HtmlForm form1;
        protected global::System.Web.UI.WebControls.TextBox TextBoxNom;
        protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidatorNom;
        protected global::System.Web.UI.WebControls.TextBox TextBoxAge;
        protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidatorAge;
        protected global::System.Web.UI.WebControls.RangeValidator RangeValidatorAge;
        protected global::System.Web.UI.WebControls.DropDownList DropDownListNoms;
        protected global::System.Web.UI.WebControls.Button ButtonValider;
        protected global::System.Web.UI.WebControls.ListBox ListBoxEvts;
        protected global::System.Web.UI.WebControls.Label LabelPost;
        protected global::System.Web.UI.WebControls.Label LabelValidation;
        protected global::System.Web.UI.WebControls.Label LabelErreursSaisie;
        protected global::System.Web.UI.WebControls.Label LabelGlobal;
        protected global::System.Web.UI.WebControls.Label LabelNbRequetes;
    }
}

مقدار ویژگی EnableViewState برای این مؤلفه‌ها می‌تواند به شرح زیر باشد:

Composant
مقدار ارسال‌شده
EnableViewState
Pourquoi
TextBoxNom
مقدار وارد شده در TextBox
نادرست
مقدار کامپوننت ارسال شده است
TextBoxAge
همین
  
RequiredFieldValidatorNom
هیچ
نادرست
هیچ ارزشی برای مؤلفه مشخص نشده است
RequiredFieldValidatorAge
همان
  
RangeValidatorAge
همان
  
LabelPost
هیچ
نادرست
توسط یک رویدادپرداز تنظیم می‌شود
LabelValidation
همان
  
LabelErreursSaisie
همان
  
LabelGlobal
همان
  
LabelNbRequetes
همان
  
DropDownListNoms
"value" عنصر انتخاب‌شده
درست
ما می‌خواهیم محتوای لیست را در تمام درخواست‌ها بدون نیاز به بازتولید مجدد آن حفظ کنیم
ListBoxEvts
«value» عنصر انتخاب‌شده
False
محتوای لیست توسط یک رویدادپرداز تولید می‌شود
ButtonValider
برچسب دکمه
False
کامپوننت مقدار طراحی خود را حفظ می‌کند

2.8. ارسال از یک صفحه به صفحه دیگر

تا کنون، عملیات GET و POST همیشه همان صفحه، [Default.aspx] را بازگردانده‌اند. ما موردی را در نظر می‌گیریم که یک درخواست توسط دو صفحه متوالی ASPX، [Default.aspx] و [Page1.aspx] پردازش می‌شود و در آن صفحه آخر به کلاینت بازگردانده می‌شود. علاوه بر این، خواهیم دید که چگونه صفحه [Default.aspx] می‌تواند اطلاعات را از طریق حافظه‌ای که آن را حافظه درخواست می‌نامیم، به صفحه [Page1.aspx] منتقل کند.

ما در حال ساخت صفحه [Page1.aspx] هستیم:

  • در [1]، یک عنصر جدید به پروژه اضافه می‌کنیم
  • در [2]، ما یک عنصر [Web Form] به نام [Page1.aspx] [3] اضافه می‌کنیم
  • در [4]، صفحه اضافه شد
  • به [5]، صفحه‌ای که یک‌بار ساخته شده است

کد منبع برای [Page1.aspx] به شرح زیر است:


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Page1.aspx.cs" Inherits="Intro.Page1" %>

<!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>Page1</title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <h1>
      Page 1</h1>
    <asp:Label ID="Label1" runat="server"></asp:Label>
    <br />
    <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/Default.aspx">Retour 
      vers page [Default]</asp:HyperLink>
  </div>
  </form>
</body>
</html>
  • خط ۱۳: یک برچسب که برای نمایش اطلاعاتی که از صفحه [Default.aspx] ارسال شده است، استفاده می‌شود
  • خط ۱۵: یک لینک HTML به صفحه [Default.aspx]. وقتی کاربر روی این لینک کلیک می‌کند، مرورگر با استفاده از عملیات GET صفحه [Default.aspx] را درخواست می‌کند. سپس صفحه [Default.aspx] بارگذاری می‌شود، گویی کاربر آدرس آن را مستقیماً در مرورگر خود وارد کرده است.

صفحه [Default.aspx] با یک مؤلفه جدید از نوع LinkButton تقویت شده است:

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


  <asp:LinkButton ID="LinkButtonToPage1" runat="server" CausesValidation="False" 
    EnableViewState="False" onclick="LinkButtonToPage1_Click">Forward vers Page1</asp:LinkButton>
  • CausesValidation="False": کلیک بر روی لینک باعث اجرای POST به [Defaul.aspx] خواهد شد. کامپوننت [LinkButton] به همان شیوه‌ای رفتار می‌کند که کامپوننت [Button] رفتار می‌کند. در اینجا، ما نمی‌خواهیم کلیک روی لینک باعث اجرای اعتبارسنج‌ها شود.
  • EnableViewState="False": نیازی به حفظ وضعیت لینک در بین درخواست‌ها نیست. این ویژگی مقادیر طراحی خود را حفظ می‌کند.
  • onclick="LinkButtonToPage1_Click": نام متدی است که در [Defaul.aspx.cs]، رویداد Click را در کامپوننت LinkButtonToPage1 مدیریت می‌کند.

کد برای دست‌پرداز LinkButtonToPage1_Click به شرح زیر است:


  // به صفحهٔ 1
  protected void LinkButtonToPage1_Click(object sender, EventArgs e)
  {
    // اطلاعات زمینه را تنظیم می‌کند
    Context.Items["msg1"] = "Message de Default.aspx pour Page1";
    // درخواست را به صفحهٔ 1 ارسال می‌کند
    Server.Transfer("Page1.aspx",true);
}

در خط ۷، درخواست با استفاده از متد [Server.Transfer] به صفحه [Page1.aspx] ارسال می‌شود. پارامتر دوم این متد، که true است، نشان می‌دهد که تمام اطلاعاتی که در طول POST به [Default.aspx] ارسال شده است، باید به [Page1.aspx] منتقل شود. این امکان را می‌دهد، برای مثال، [Page1.aspx] از طریق مجموعه‌ای به نام Request.Form به مقادیر ارسال‌شده دسترسی پیدا کند. خط ۵ از چیزی به نام زمینهٔ درخواست استفاده می‌کند. به این مورد از طریق خاصیت Context کلاس Page دسترسی پیدا می‌شود. این زمینه می‌تواند به‌عنوان یک حافظه مشترک بین صفحات مختلف که یک درخواست را پردازش می‌کنند، در این مورد [Default.aspx] و [Page1.aspx]، عمل کند. فرهنگ لغت Items برای این منظور استفاده می‌شود.

هنگامی که [Page1.aspx] توسط عملیات Server.Transfer("Page1.aspx", true) بارگذاری می‌شود، این مانند این است که [Page1.aspx] توسط GET از یک مرورگر فراخوانی شده باشد. دست‌پرداز Page_Load برای [Page1.aspx] به طور معمول اجرا می‌شود. ما از این برای نمایش پیامی که توسط [Default.aspx] در زمینه درخواست تنظیم شده است، استفاده خواهیم کرد:


using System;

namespace Intro
{
  public partial class Page1 : System.Web.UI.Page
  {
    protected void Page_Load(object sender, EventArgs e)
    {
      Label1.Text = Context.Items["msg1"] as string;
    }
  }
}

در خط ۹، پیامی که توسط [Default.aspx] در زمینه درخواست تنظیم شده است، در Label1 نمایش داده می‌شود.

در اینجا مثالی از اجرای آن آمده است:

  • در صفحه [Default.aspx] [1]، روی پیوند [2] کلیک کنید که شما را به صفحه Page1 می‌برد
  • در [3]، صفحه Page1 نمایش داده می‌شود
  • در [4]، پیامی که در [Default.aspx] ایجاد شده و توسط [Page1.aspx] نمایش داده می‌شود
  • در [5]، صفحه‌ای که در مرورگر نمایش داده می‌شود URL است که مربوط به صفحه [Default.aspx] می‌باشد

2.9. ارسال مجدد از یک صفحه به صفحه‌ی دیگر

در اینجا تکنیک دیگری را ارائه می‌دهیم که از نظر عملکردی مشابه روش قبلی است: هنگامی که کاربر از طریق POST صفحه [Default.aspx] را درخواست می‌کند، در پاسخ صفحه دیگری، [Page2.aspx]، دریافت می‌کند. در روش قبلی، درخواست کاربر به‌صورت متوالی توسط دو صفحه پردازش می‌شد: [Default.aspx] و [Page1.aspx]. در روش هدایت صفحه که اکنون ارائه می‌کنیم، دو درخواست جداگانه از مرورگر ارسال می‌شود:

  • به [1]، مرورگر درخواستی (POST) به صفحه [Default.aspx] ارسال می‌کند. این صفحه درخواست را پردازش کرده و یک پاسخ هدایت (redirect response) به مرورگر ارسال می‌کند. این پاسخ یک جریان ساده از HTTP (خطوط متن) است که به مرورگر دستور می‌دهد به یک URL دیگر، یعنی [Page2.aspx]، هدایت (redirect) شود. [Default.aspx] در این پاسخ اولیه هیچ استریم HTML را ارسال نمی‌کند.
  • در [2]، مرورگر درخواستی (GET) به صفحه [Page2.aspx] ارسال می‌کند. این درخواست سپس به‌عنوان پاسخ به مرورگر بازگردانده می‌شود.
  • اگر صفحه [Default.aspx] بخواهد اطلاعاتی را به صفحه [Page2.aspx] منتقل کند، می‌تواند این کار را از طریق جلسه کاربری انجام دهد. برخلاف روش قبلی، در اینجا نمی‌توان از زمینه درخواست استفاده کرد، زیرا دو درخواست جداگانه وجود دارد و در نتیجه دو زمینه مجزا نیز وجود دارد. بنابراین باید از جلسهٔ کاربر استفاده کنیم تا صفحات بتوانند با یکدیگر ارتباط برقرار کنند.

همان‌طور که برای [Page1.aspx] انجام شد، صفحه [Page2.aspx] را به پروژه اضافه می‌کنیم:

  • در [1]، [Page2.aspx] به پروژه اضافه شده است
  • در [2]، ظاهر بصری [Page2.aspx]
  • در [3]، ما یک کامپوننت LinkButton [4] به صفحه [Default.aspx] اضافه می‌کنیم که کاربر را به [Page2.aspx] هدایت خواهد کرد.

کد منبع [Page2.aspx] مشابه کد منبع [Page1.aspx] است:


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Page2.aspx.cs" Inherits="Intro.Page2" %>

<!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>Page2</title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <h1>
      Page 2</h1>
    <asp:Label ID="Label1" runat="server"></asp:Label>
    <br />
    <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/Default.aspx">Retour 
      vers page [Default]</asp:HyperLink>
  </div>
  </form>
</body>
</html>

در [Default.aspx]، افزودن کامپوننت LinkButton کد منبع زیر را تولید کرد:


<asp:LinkButton ID="LinkButtonToPage2" runat="server" 
    onclick="LinkButtonToPage2_Click">Redirection vers Page2</asp:LinkButton>

این هَندلر [LinkButtonToPage2_Click] است که هدایت به [Page2.aspx] را مدیریت می‌کند. کد آن در [Defaul.aspx.cs] به شرح زیر است:


    protected void LinkButtonToPage2_Click(object sender, EventArgs e)
    {
      // پیامی به جلسه اضافه می‌شود
      Session["msg2"] = "Message de [Default.aspx] pour [Page2.aspx]";
      // کلاینت را به [Page2.aspx] هدایت می‌کند
      Response.Redirect("Page2.aspx");
}
  • خط ۴: پیامی به جلسه کاربر اضافه می‌شود
  • خط ۵: شیء Response یک ویژگی هر صفحه ASPX است. این شی پاسخ ارسال‌شده به کلاینت را نشان می‌دهد. این شی دارای متدی به نام Redirect است که تضمین می‌کند پاسخ ارسال‌شده به کلاینت یک فرمان هدایت HTTP باشد.

وقتی مرورگر دستور هدایت به [Page2.aspx] را دریافت می‌کند، یک GET را روی آن صفحه اجرا خواهد کرد. در این صفحه، متد [Page_Load] اجرا خواهد شد. ما از این متد برای بازیابی پیام تنظیم‌شده توسط [Default.aspx] در جلسه و نمایش آن استفاده خواهیم کرد. کد مربوط به [Page2.aspx.cs] به شرح زیر است:


using System;

namespace Intro
{
  public partial class Page2 : System.Web.UI.Page
  {
    protected void Page_Load(object sender, EventArgs e)
    {
      //پیامی که توسط [Default.aspx] در جلسه قرار داده شده است نمایش داده می‌شود
      Label1.Text = Session["msg2"] as string;
    }
  }
}

پس از اجرا، نتایج زیر به دست می‌آیند:

  • در [1]، ما روی لینک هدایت به [Default.aspx] کلیک می‌کنیم. یک هدایت از POST به صفحه [Default.aspx] انجام می‌شود
  • در [2]، مرورگر به [Page2.aspx] هدایت شده است. این موضوع از URL که توسط مرورگر نمایش داده شده است، قابل مشاهده است. در روش قبلی، این URL برابر با [Default.aspx] بود، زیرا تنها درخواستی که مرورگر انجام داد به آن URL بود. در اینجا، یک درخواست اولیه از POST به [Default.aspx] وجود دارد که به دنبال آن – بدون اطلاع کاربر – یک درخواست دوم از GET به [Page2.aspx] انجام می‌شود.
  • در [3] می‌توانیم ببینیم که [Page2.aspx] به‌درستی پیامی را که توسط [Default.aspx] در جلسه قرار داده شده بود، بازیابی کرده است.

2.10. Conclusion

ما با استفاده از چند مثال، مفاهیم ASP.NET را معرفی کردیم که در ادامه این سند برای ما مفید خواهند بود. این مقدمه نکات ظریف ارتباط کلاینت/سرور در یک برنامه وب را پوشش نمی‌دهد. برای این منظور، ممکن است بخواهید مطالعه کنید:

  • برنامه‌نویسی ASP.NET [Développement WEB avec ASP.NET 1.1 ]