Skip to content

2. مقدمة سريعة إلى ASP.NET

نقترح هنا تقديم مفاهيم ASP.NET التي ستكون مفيدة لنا في بقية الوثيقة، وذلك باستخدام بعض الأمثلة. لا تسمح هذه المقدمة بفهم التفاصيل الدقيقة للتبادلات بين العميل والخادم في تطبيق ويب. لهذا الغرض، يمكن قراءة:

هذه المقدمة مخصصة لأولئك الذين يرغبون في التقدم بسرعة، مع قبولهم، في البداية، بترك بعض النقاط التي قد تكون مهمة في الخلفية. ويتيح الجزء التالي من الوثيقة التعمق في هذه النقاط. يمكن لأولئك الذين يعرفون ASP.NET الانتقال مباشرة إلى الفقرة 3.

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 في هذه الحالة. عادةً ما يكون المنفذ المستمع هو المنفذ 80. في [1]، لم يتم طلب أي صفحة. في هذه الحالة، يتم عرض الصفحة [Default.aspx]، ومن هنا جاء اسم الصفحة الافتراضي.
  • في [2]، تكون الصفحة [Default.aspx] فارغة.
  • في Visual Web Developer، يمكن إنشاء الصفحة [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>
  • السطر 1 هو توجيه 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.
  • تصف الأسطر 4-14 الصفحة [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>

في السطر 6، نضع عنوانًا للصفحة باستخدام العلامة HTML <title>. في السطر 9، نضيف نصًا إلى نص الصفحة (<body>). إذا قمنا بتشغيل المشروع (Ctrl-F5)، نحصل على النتيجة التالية في المتصفح:

 

2.1.3. الملفان [Default.aspx.designer.cs] و [Default.aspx.cs]

يعلن الملف [Default.aspx.designer.cs] عن مكونات الصفحة [Defaul.aspx]:


//------------------------------------------------------------------------------
// <تم إنشاؤه تلقائيًا>
//      تم إنشاء هذا الرمز بواسطة أداة.
//      إصدار وقت التشغيل: 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. وبالتالي، فإن المكون في السطر 23 أعلاه يتوافق مع العلامة


  <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] هي نفسها (السطر 10): Intro._Default. الكلمة الرئيسية partial هي التي تتيح توسيع نطاق تعريف الفئة ليشمل عدة ملفات، وهنا ملفين.

في السطر 10 أعلاه، نرى أن الفئة [_Default] توسع نطاق الفئة [Page] وترث أحداثها. أحدها هو الحدث Load الذي يحدث عند تحميل الصفحة بواسطة خادم الويب. السطر 12، الطريقة Page_Load التي تدير الحدث Load للصفحة. عادةً ما يتم هنا تهيئة الصفحة قبل عرضها في متصفح العميل. هنا، لا تقوم الطريقة Page_Load بأي شيء.

يتم إنشاء الفئة المرتبطة بصفحة ويب، وهي هنا الفئة Intro._Default، في بداية طلب العميل ويتم إتلافها عند إرسال الرد إلى العميل. وبالتالي، لا يمكن استخدامها لتخزين المعلومات بين طلبين. ولهذا الغرض، يجب استخدام مفهوم جلسة المستخدم.

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] (السطر 5) ثلاثة أحداث:

  • حدث Init (السطر 7) الذي يحدث عند تهيئة الصفحة
  • الحدث Load (السطر 13) الذي يحدث عندما يتم تحميل الصفحة بواسطة خادم الويب. يحدث الحدث Init قبل الحدث Load.
  • حدث Click على الزر ButtonValider (السطر 19) الذي يحدث عندما ينقر المستخدم على الزر [Valider]

تتمثل إدارة كل من هذه الأحداث الثلاثة في إضافة رسالة إلى المكون Listbox المسمى ListBoxEvts. تعرض هذه الرسالة وقت الحدث واسمه. يتم وضع كل رسالة في بداية القائمة. وبالتالي، فإن الرسائل الموضوعة في أعلى القائمة هي الأحدث.

عند تشغيل المشروع، نحصل على الصفحة التالية:

يُلاحظ في [1] أن الحدثين Page_Init و Page_Load قد وقعا بهذا الترتيب. يُذكر أن الحدث الأحدث يظهر في أعلى القائمة. عندما يطلب المتصفح الصفحة [Default.aspx] مباشرةً عبر عنوان URL الخاص بها [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]. هذا هو السلوك الطبيعي، ما لم يكن هناك نقل أو إعادة توجيه للصفحة بواسطة مديري أحداث الصفحة. يمكن ملاحظة حدوث حدثين جديدين:

  • الحدث 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" ...> تسمى الحقل المخفي (السطر 10 أدناه).
<!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>
..............................

في حقل المعرف "__VIEWSTATE"، يقوم خادم الويب بتشفير قيمة جميع مكونات الصفحة. ويقوم بذلك سواء في الرمز الأولي GET أو في الرموز التالية POST. عندما يحدث POST على صفحة P:

  • يطلب المتصفح الصفحة P عن طريق إرسال قيم جميع المكونات الموجودة داخل العلامة <form> في طلبه. فيما سبق، يمكننا أن نرى أن المكون "__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());
    }
  }
}

السطر 24، يتم تحديث المكون 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"، وهي قيمة غير صالحة. سنقوم بإضافة مكونات تسمى أدوات التحقق إلى الصفحة. وهي تستخدم للتحقق من صحة البيانات المرسلة. يمكن التحقق من هذه الصحة في مكانين:

  • على العميل. تتيح خيار تكوين أداة التحقق تحديد ما إذا كان سيتم إجراء الاختبارات على المتصفح أم لا. يتم إجراؤها بعد ذلك بواسطة كود مدمج في الصفحة. عندما يقوم المستخدم بإجراء POST للقيم المدخلة في النموذج، يتم التحقق منها أولاً بواسطة كود جافا سكريبت. إذا فشل أحد الاختبارات، لا يتم تنفيذ POST. وبذلك يتم تجنب عملية الذهاب والإياب مع الخادم، مما يجعل الصفحة أكثر استجابة.
  • على الخادم. إذا كانت الاختبارات من جانب العميل اختيارية، فإنها تكون إلزامية من جانب الخادم سواء تم التحقق من جانب العميل أم لا. في الواقع، عندما تتلقى الصفحة قيمًا مرسلة، لا يمكنها معرفة ما إذا كان العميل قد تحقق منها قبل إرسالها. لذلك، يجب على المطور دائمًا التحقق من صحة البيانات المرسلة من جانب الخادم.

تتطور الصفحة [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>

تمت إضافة أدوات التحقق من الصحة إلى الأسطر 20 و32 و35. في السطر 58، يتم استخدام مكون Label لعرض القيم المرسلة الصحيحة. في السطر 60، يتم استخدام مكون 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 افتراضيًا عندما لا يتم تعيينها صراحةً كما هو موضح أعلاه.
  • Display: وضع عرض أداة التحقق من الصحة. هناك وضعان:
    • 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 لا يتم تنفيذها إلا عندما تكون القيم المرسلة صالحة. قد يتساءل المرء إذن عن معنى الكود الموجود بدءًا من السطر 8. يجب أن نتذكر أنه من الممكن دائمًا كتابة عميل مبرمج ينشر قيمًا غير متحقق منها إلى الصفحة [Default.aspx]. لذا يجب على هذه الصفحة إعادة إجراء اختبارات الصحة دائمًا.

  • السطر 8: يبدأ تنفيذ جميع أدوات التحقق من الصحة في الصفحة. في حالة ما إذا كان زر [Valider] يحتوي على السمة CausesValidation إلى True، يتم ذلك تلقائيًا ولا داعي لإعادة القيام به. هناك تكرار هنا.
  • الأسطر 9-15: الحالة التي فشل فيها أحد أدوات التحقق
  • الأسطر 16-19: الحالة التي نجحت فيها جميع أدوات التحقق

فيما يلي مثالان على التنفيذ:

  • في [1]، مثال على التنفيذ في الحالة التي:
    • الزر [Valider] له خاصية CausesValidation إلى True
    • تم تغيير خاصية المدققين من EnableClientScript إلى 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]: يسمح بتعريف فئة، تسمى فئة التطبيق الشاملة، والتي تستمر طوال عمر التطبيق، بالإضافة إلى مديري بعض الأحداث الخاصة بهذا التطبيق نفسه.

تسمح فئة التطبيق الشاملة بتحديد البيانات التي ستكون متاحة لجميع طلبات جميع المستخدمين.

  • البيانات المشتركة بين طلبات نفس العميل. يتم تخزين هذه البيانات في كائن يسمى Session. ونستخدم مصطلح "جلسة العميل" للإشارة إلى ذاكرة العميل. يمكن لجميع طلبات العميل الوصول إلى هذه الجلسة. ويمكنها تخزين المعلومات وقراءتها فيها

فيما يلي، نعرض أنواع الذاكرة التي يمكن لصفحة ASPX الوصول إليها:

  • ذاكرة التطبيق التي تحتوي في الغالب على بيانات للقراءة فقط ويمكن لجميع المستخدمين الوصول إليها.
  • ذاكرة مستخدم معين، أو جلسة عمل، تحتوي على بيانات للقراءة/الكتابة ويمكن الوصول إليها من خلال الطلبات المتتالية لنفس المستخدم.
  • غير موضحة أعلاه، توجد ذاكرة طلب، أو سياق طلب. يمكن معالجة طلب مستخدم ما بواسطة عدة صفحات ASPX متتالية. يسمح سياق الطلب لصفحة 1 بنقل المعلومات إلى صفحة 2.

نحن مهتمون هنا ببيانات النطاق Application، وهي تلك التي يتم مشاركتها بين جميع المستخدمين. يمكن إنشاء الفئة العامة للتطبيق على النحو التالي:

  • في [1]، نضيف عنصرًا جديدًا إلى المشروع
  • في [2]، نضيف فئة التطبيق الشاملة
  • في [3]، يتم الاحتفاظ بالاسم الافتراضي [Global.asax] للعنصر الجديد
  • في [4]، تمت إضافة ملفين جديدين إلى المشروع
  • في [5]، يتم عرض ترميز [Global.asax]

<%@ Application Codebehind="Global.asax.cs" Inherits="Intro.Global" Language="C#" %>
  • تحل العلامة Application محل العلامة Page التي كانت موجودة سابقًا لـ [Default.aspx]. وهي تحدد فئة التطبيق الشاملة
  • Codebehind: يحدد الملف الذي تم فيه تعريف فئة التطبيق العامة
  • Inherits: يحدد اسم هذه الفئة

الفئة 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)
    {

    }
  }
}
  • السطر 5: فئة التطبيق العامة مشتقة من فئة HttpApplication

يتم إنشاء الفئة مع هياكل أساسية لمعالجات أحداث التطبيق:

  • السطران 8 و 38: يديران الأحداث Application_Start (بدء تشغيل التطبيق) و Application_End (إنهاء التطبيق عند إيقاف تشغيل خادم الويب أو عند قيام المسؤول بإلغاء تحميل التطبيق)
  • السطران 13 و33: تدير الأحداث Session_Start (بدء جلسة عمل جديدة للعميل عند وصول عميل جديد أو عند انتهاء صلاحية جلسة عمل قائمة) و Session_End (إنهاء جلسة عمل العميل إما بشكل صريح عن طريق البرمجة أو بشكل ضمني عن طريق تجاوز المدة المسموح بها للجلسة).
  • السطر 28: يدير الحدث Application_Error (ظهور استثناء لا يديره كود التطبيق ويتم رفعه إلى الخادم)
  • السطر 18: يدير الحدث Application_BeginRequest (وصول طلب جديد).
  • السطر 23: يدير الحدث 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>

بالنسبة لتطبيقنا الحالي، هذا الملف غير ضروري. إذا قمنا بحذفه أو إعادة تسميته، سيستمر التطبيق في العمل بشكل طبيعي. سنركز على العلامات الموجودة في السطرين 8 و9:

  • <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)
    {

    }

  }
}
  • الأسطر 8-11: أربع خصائص ثابتة P. نظرًا لأن مدة حياة الفئة Global هي مدة حياة التطبيق، فإن أي استعلام يتم إجراؤه على التطبيق سيتمكن من الوصول إلى هذه الخصائص P عبر بناء الجملة Global.P.
  • الأسطر 17-19: يمكن الوصول إلى الملف [Web.config] عبر الفئة [System.Configuration.ConfigurationManager]
  • السطور 17-18: يسترد عناصر العلامة <appSettings> من الملف [Web.config] عبر السمة key.
  • السطر 19: يسترد عناصر العلامة <connectionStrings> من الملف [Web.config] عبر السمة name.

يمكن الوصول إلى السمات الثابتة للسطور 8-11 من أي معالج أحداث للصفحات 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);
}
  • السطر 6: تُستخدم السمات الثابتة الأربع للفئة العامة للتطبيق لتغذية تسمية جديدة في الصفحة [Default.aspx]

عند التنفيذ، نحصل على النتيجة التالية:

فيما سبق، نرى أن معلمات [web.config] قد تم استردادها بشكل صحيح. تعد فئة التطبيق العامة المكان المناسب لتخزين المعلومات المشتركة بين جميع المستخدمين.

2.5. إدارة بيانات نطاق الجلسة

نحن مهتمون هنا بكيفية تخزين المعلومات عبر طلبات مستخدم معين:

لكل مستخدم ذاكرته الخاصة التي نسميها جلسته.

لقد رأينا أن فئة التطبيق العامة تحتوي على مديريْن لإدارة الأحداث:

  • Session_Start: بداية الجلسة
  • Session_end: نهاية الجلسة

يتم تنفيذ آلية الجلسة بالطريقة التالية:

  • عند الطلب الأول من المستخدم، يقوم خادم الويب بإنشاء رمز جلسة عمل ويخصصه للمستخدم. هذا الرمز عبارة عن سلسلة أحرف فريدة لكل مستخدم. يتم إرساله من قبل الخادم في الرد على الطلب الأول للمستخدم.
  • عند الطلبات التالية، يقوم المستخدم (متصفح الويب) بتضمين رمز الجلسة الذي تم تخصيصه له في طلبه. وبذلك يتمكن خادم الويب من التعرف عليه.
  • للجلسة مدة صلاحية. عندما يتلقى خادم الويب طلبًا من مستخدم، فإنه يحسب الوقت الذي انقضى منذ الطلب السابق. إذا تجاوز هذا الوقت مدة صلاحية الجلسة، يتم إنشاء جلسة جديدة للمستخدم. تُفقد بيانات الجلسة السابقة. مع خادم الويب IIS (Internet Information Server) من Microsoft، تبلغ مدة صلاحية الجلسات افتراضيًا 20 دقيقة. يمكن لمسؤول خادم الويب تغيير هذه القيمة.
  • يعرف خادم الويب أنه يتعامل مع الطلب الأول لمستخدم ما لأن هذا الطلب لا يحتوي على رمز جلسة. إنه الطلب الوحيد.

تتمتع كل صفحة ASP.NET بإمكانية الوصول إلى جلسة عمل المستخدم عبر خاصية Session للصفحة، من النوع [System.Web.SessionState.HttpSessionState]. سنستخدم الخصائص P والطرق M التالية للفئة HttpSessionState:

الاسم
النوع
الدور
Item[String clé]
P
يمكن بناء الجلسة كقاموس. Item[clé] هو عنصر الجلسة المحدد بواسطة clé. بدلاً من كتابة [HttpSessionState].Item[clé]، يمكن أيضًا كتابة [HttpSessionState].[clé].
مسح
M
إفراغ قاموس الجلسة
إلغاء
M
ينهي الجلسة. عندئذٍ تصبح الجلسة غير صالحة. وستبدأ جلسة جديدة مع الطلب التالي للمستخدم.

كمثال على ذاكرة المستخدم، سنقوم بحساب عدد المرات التي ينقر فيها المستخدم على الزر [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;
    }

  }
}

في السطر 19، يتم استخدام جلسة عمل المستخدم لتخزين عداد الطلبات المحدد بالمفتاح "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)
      {
...
      }
...
    }
  }
}
  • السطر 16: يتم زيادة عداد الطلبات
  • السطر 17: يتم عرض العداد على الصفحة

فيما يلي مثال على التنفيذ:

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
الرقم الترتيبي، بدءًا من 0، للعنصر المحدد في القائمة المنسدلة عند إرسال النموذج
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 texte, string valeur).

في [Default.aspx.cs]، يتطور كود المعالج [Page_Load] على النحو التالي:


    protected void Page_Load(object sender, EventArgs e)
    {
      // تسجيل الحدث
      ...
      // يتم استرداد معلومات فئة التطبيق العامة
      ...
      // تهيئة قائمة الأسماء المنسدلة فقط عند GET الأولي
      if (!IsPostBack)
      {
        for (int i = 0; i < 3; i++)
        {
          DropDownListNoms.Items.Add(new ListItem("nom"+i,i.ToString()));
        }
      }
}
  • السطر 8: تحتوي الفئة Page على سمة IsPostBack من النوع المنطقي. في الواقع، هذا يعني أن طلب المستخدم هو POST. وبالتالي، لا يتم تنفيذ الأسطر 10-13 إلا على GET الأولي للعميل.
  • السطر 12: نضيف إلى قائمة [DropDownListNoms] عنصرًا من النوع ListItem (سلسلة نصية، قيمة سلسلة). سيكون النص المعروض للعنصر (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);
      // عدد الطلبات
...
}

السطر 6، يتم الحصول على القيمة المنشورة لقائمة [DropDownListNoms] باستخدام خاصية SelectedValue الخاصة بالقائمة. فيما يلي مثال على التنفيذ:

  • في [1]، محتوى القائمة المنسدلة بعد GET الأولي وقبل POST الأول مباشرة
  • في [2]، الصفحة بعد أول POST.
  • في [3]، القيمة التي تم إرسالها للقائمة المنسدلة. تتوافق مع السمة value لـ ListItem المحدد في القائمة.
  • في [4]، القائمة المنسدلة. تحتوي على نفس العناصر الموجودة بعد GET الأولي. آلية VIEWSTATE هي التي تفسر ذلك.

لفهم التفاعل بين VIEWSTATE في قائمة DropDownListNoms واختبار if (! IsPostBack) في مدير Page_Load لـ [Default.aspx]، يُطلب من القارئ إعادة إجراء الاختبار السابق باستخدام التكوينات التالية:

الحالة
DropDownListNoms.EnableViewState
اختبار if(! IsPostBack) في Page_Load من [Default.aspx]
1
true
présent
2
false
présent
3
true
absent
4
false
absent

تُعطي الاختبارات المختلفة النتائج التالية:

  1. هذا هو الحالة المذكورة أعلاه
  2. يتم ملء القائمة عند GET الأولي ولكن ليس عند POST التالية. وبما أن EnableViewState غير صحيح، فإن القائمة تكون فارغة بعد كل POST
  3. يتم ملء القائمة بعد GET الأولي وكذلك خلال عمليات POST التالية. وبما أن EnableViewState هو vrai، فإننا نحصل على 3 أسماء بعد GET الأولي، و6 أسماء بعد POST الأول، و9 أسماء بعد POST الثاني، ...
  4. يتم ملء القائمة بعد GET الأول وكذلك أثناء عمليات POST التالية. نظرًا لأن EnableViewState يسبق faux، يتم ملء القائمة بثلاثة أسماء فقط في كل استعلام، سواء كان الاستعلام الأولي GET أو الاستعلامات التالية POST. نجد هنا نفس سلوك الحالة 1. وبالتالي، هناك طريقتان للحصول على نفس النتيجة.

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 (الخطوة 2) ستتغير في إحدى الخطوتين 3 أو 4.

قائمة مكونات صفحتنا متوفرة في [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
False
تم نشر قيمة المكون
TextBoxAge
كما سبق
  
RequiredFieldValidatorNom
لا شيء
False
عدم وجود مفهوم لقيمة المكون
RequiredFieldValidatorAge
كما سبق
  
RangeValidatorAge
نفس الشيء
  
LabelPost
لا شيء
False
يتم الحصول على قيمته من خلال مدير الأحداث
LabelValidation
كما سبق
  
LabelErreursSaisie
نفس الشيء
  
LabelGlobal
نفس الشيء
  
LabelNbRequetes
نفس الشيء
  
DropDownListNoms
"القيمة" للعنصر المحدد
صحيح
نريد الاحتفاظ بمحتوى القائمة مع كل طلب دون الحاجة إلى إعادة إنشائها
ListBoxEvts
"القيمة" للعنصر المحدد
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>
  • السطر 13: تسمية ستُستخدم لعرض معلومات مرسلة من الصفحة [Default.aspx]
  • السطر 15: رابط HTML إلى الصفحة [Default.aspx]. عندما ينقر المستخدم على هذا الرابط، يطلب المتصفح الصفحة [Default.aspx] باستخدام عملية GET. ثم يتم تحميل الصفحة [Default.aspx] كما لو أن المستخدم قد أدخل عنوان URL الخاص بها مباشرة في متصفحه.

يتم إثراء الصفحة [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);
}

السطر 7، يتم تمرير الطلب إلى الصفحة [Page1.aspx] باستخدام الطريقة [Server.Transfer]. يشير المعامل الثاني للطريقة الموجودة في true إلى ضرورة تمرير جميع المعلومات التي تم إرسالها إلى [Default.aspx] أثناء POST إلى [Page1.aspx]. وهذا يسمح، على سبيل المثال، لـ [Page1.aspx] بالوصول إلى القيم التي تم إرسالها عبر مجموعة تسمى Request.Form. يستخدم السطر 5 ما يُسمى بسياق الطلب. يمكن الوصول إليه عبر الخاصية 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;
    }
  }
}

في السطر 9، يتم عرض الرسالة التي وضعها [Default.aspx] في سياق الاستعلام، في Label1.

فيما يلي مثال على التنفيذ:

  • في الصفحة [Default.aspx] [1]، نضغط على الرابط [2] الذي يقودنا إلى الصفحة Page1
  • في [3]، يتم عرض الصفحة Page1
  • في [4]، يتم عرض الرسالة التي تم إنشاؤها في [Default.aspx] وعرضها بواسطة [Page1.aspx]
  • في [5]، فإن URL المعروضة في المتصفح هي تلك الخاصة بالصفحة [Default.aspx]

2.9. إعادة توجيه صفحة إلى أخرى

نقدم هنا تقنية أخرى مشابهة وظيفياً للتقنية السابقة: عندما يطلب المستخدم الصفحة [Default.aspx] عبر POST، يتلقى رداً بصفحة أخرى هي [Page2.aspx]. في الطريقة السابقة، تمت معالجة طلب المستخدم بالتتابع من خلال صفحتين: [Default.aspx] و [Page1.aspx]. في طريقة إعادة توجيه الصفحة التي نقدمها الآن، هناك طلبان منفصلان من المتصفح:

  • في [1]، يقوم المتصفح بإرسال طلب POST إلى الصفحة [Default.aspx]. تعالج هذه الصفحة الطلب وترسل استجابة تسمى إعادة التوجيه إلى المتصفح. هذه الاستجابة عبارة عن تدفق بسيط HTTP (سطور نصية) تطلب من المتصفح إعادة التوجيه إلى عنوان URL آخر [Page2.aspx]. لا ترسل [Default.aspx] تدفق HTML في هذا الرد الأول.
  • في [2]، يقوم المتصفح بإرسال طلب GET إلى الصفحة [Page2.aspx]. ثم يتم إرسال هذه الصفحة كاستجابة إلى المتصفح.
  • إذا أرادت الصفحة [Default.aspx] إرسال معلومات إلى الصفحة [Page2.aspx]، فيمكنها القيام بذلك عبر جلسة عمل المستخدم. على عكس الطريقة السابقة، لا يمكن استخدام سياق الطلب هنا، لأن هناك طلبين منفصلين وبالتالي سياقين منفصلين. لذلك، يجب استخدام جلسة عمل المستخدم لتسهيل التواصل بين الصفحات.

كما تم في حالة [Page1.aspx]، نضيف إلى المشروع الصفحة [Page2.aspx]:

  • في [1]، تمت إضافة [Page2.aspx] إلى المشروع
  • في [2]، تم تغيير المظهر المرئي لـ [Page2.aspx]
  • في [3]، نضيف إلى الصفحة [Default.aspx] مكونًا LinkButton [4] الذي سيعيد توجيه المستخدم إلى [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");
}
  • السطر 4: يتم وضع رسالة في جلسة عمل المستخدم
  • السطر 5: الكائن 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 ]