5. تطبيق [SimuPaie] – الإصدار 2 – AJAX / ASP.NET
5.1. مقدمة
تجمع تقنية AJAX (Asynchronous JavaScript and XML) بين مجموعة من التقنيات:
- JavaScript: يمكن لصفحة HTML المعروضة في متصفح أن تتضمن كود JavaScript. يتم تنفيذ هذا الكود بواسطة المتصفح إذا لم يقم المستخدم بتعطيل تنفيذ JavaScript في متصفحه. هذه التقنية موجودة منذ الأيام الأولى للويب وقد شهدت اهتمامًا متجددًا منذ عام 2005 بفضل AJAX.
- DOM: نموذج كائن المستند. يمكن لرمز JavaScript المضمن في صفحة HTML الوصول إلى المستند في شكل شجرة كائنات، وهي DOM. يتم تمثيل كل عنصر من عناصر المستند (حقل إدخال، علامة div مسماة، علامة select، إلخ) بعقدة في الشجرة. يمكن لرمز JavaScript تغيير المستند المعروض عن طريق تعديل DOM. على سبيل المثال، يمكنه تغيير النص المعروض في حقل إدخال عبر عقدة DOM التي تمثل هذا الحقل.
يستخدم AJAX JavaScript لإجراء التبادلات بين المتصفح والخادم في الخلفية. للاستجابة لحدث مثل النقر على زر، يقوم المتصفح بتنفيذ كود JavaScript لإرسال طلب HTTP إلى الخادم. يحتوي هذا الطلب على معلمات تخبر الخادم بما يجب القيام به. ثم يقوم الخادم بتنفيذ الإجراء المطلوب. وردًا على ذلك، يرسل إلى المتصفح دفق HTTP يحتوي على بيانات تتيح تحديثًا جزئيًا للصفحة المعروضة حاليًا. ويتم تنفيذ ذلك عبر DOM الخاص بالمستند وتنفيذ كود JavaScript المضمن في المستند. يمكن أن تكون البيانات التي يعيدها الخادم بتنسيقات مختلفة: XML، HTML، JSON، نص عادي، إلخ.
تكمن فائدة هذه التقنية في هذا التحديث الجزئي للمستند المعروض. وهذا يعني:
- تبادل بيانات أقل بين العميل والخادم، مما يؤدي إلى استجابة أسرع
- واجهة رسومية أكثر سلاسة في الاستخدام، حيث لا تؤدي إجراءات المستخدم إلى إعادة تحميل الصفحة بالكامل.
في شبكة داخلية حيث حركة مرور الشبكة سريعة، تتيح AJAX إنشاء تطبيقات ويب تعمل بشكل مشابه لواجهات Windows التقليدية. من الممكن التعامل مع أحداث مثل تغيير التحديد في قائمة وتحديث الصفحة فوراً وجزئياً لتعكس هذا التغيير. حقيقة أن الصفحة لا يتم إعادة تحميلها بالكامل تمنح المستخدم نفس الشعور بالسلاسة الذي يختبره مع تطبيقات Windows. بالنسبة لتطبيقات الويب، حيث قد تكون أوقات الاستجابة طويلة، تظل تقنية AJAX قابلة للاستخدام، لكن السلاسة الملحوظة تعتمد على أداء الشبكة.
التحدي الرئيسي مع AJAX هو لغة JavaScript. تم إنشاؤها في الأيام الأولى للويب،
- وقد ثبت أنها غير عملية للبرمجة الموجهة للكائنات. على سبيل المثال، فهي ليست لغة مكتوبة. لا تقوم بتحديد نوع البيانات التي يتم معالجتها. في هذا الصدد، فهي تشبه لغات مثل Perl أو PHP.
- لا يوجد معيار مقبول من قبل جميع المتصفحات. لكل متصفح امتدادات JavaScript الخاصة به، مما يعني أن كود JavaScript المكتوب لـ Internet Explorer قد لا يعمل في Mozilla Firefox، والعكس صحيح.
- من الصعب تصحيح الأخطاء، حيث لا توفر المتصفحات أدوات قوية لتصحيح أخطاء كود JavaScript الذي تقوم بتنفيذه.
كل هذه العيوب في JavaScript جعلت من استخدامها نادرًا قبل ظهور AJAX. وبمجرد فهم قيمة تنفيذ كود JavaScript في الخلفية — لإجراء طلبات HTTP إلى خادم الويب واستخدام استجابته لإجراء تحديث جزئي للوثيقة المعروضة عبر DOM — بدأت فرق التطوير العمل واقترحت أطر عمل تتيح AJAX دون الحاجة إلى أن يكتب المطور كود JavaScript. ولتحقيق ذلك، تم تطوير مكتبات JavaScript قادرة على التكيف مع متصفح العميل. يتم إدراج كود JavaScript في صفحة HTML المرسلة إلى المتصفح من جانب الخادم، باستخدام تقنيات تختلف باختلاف إطار عمل AJAX المستخدم. تتوفر أطر عمل AJAX لـ Java و.NET وPHP وRuby وغيرها. تم دمج AJAX في Visual Web Developer 2008.
5.2. مشروع Visual Web Developer في طبقة [ web-ui-ajax]
يتم إنشاء الإصدار الجديد عن طريق نسخ الإصدار السابق. سيتم تعديل صفحة [Default.aspx] فقط.
![]() |
- في [1]، باستخدام Windows Explorer، قم بنسخ مجلد المشروع [pam-v1-adonet] وأعد تسميته [pam-v2-adonet-ajax]. ثم، باستخدام Visual Web Developer، افتح المشروع (File / Open Project) من هذا المجلد الجديد [2]
- في [3]، قم بتغيير اسمه
![]() |
- في خصائص المشروع الجديد، قم بتغيير اسم التجميع [4] ومساحة الاسم الافتراضية [5].
بمجرد الانتهاء من ذلك، استبدل مساحة الاسم [pam_v1] بمساحة الاسم [pam_v2] في الملفات [Default.aspx، Default.aspx.cs، Default.aspx.designer.cs، Global.asax، Global.asax.cs] لضمان الاتساق مع مساحة الاسم الافتراضية. على سبيل المثال، يصبح [Default.aspx] [6] كما يلي:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="pam_v2._Default" %>
...
سيتم تعديل صفحة [ Default.aspx] على النحو التالي:
![]() |
- إضافة مكونات Ajax إلى النموذج [Default.aspx] (انظر [2] أعلاه).
- 2A: مكون <asp:ScriptManager> مطلوب لأي مشروع AJAX
- 2B: يُستخدم مكون <asp:UpdatePanel> لتحديد المنطقة المراد تحديثها عندما يرسل المستخدم طلب POST. يمنع هذا المكون إعادة تحميل الصفحة بأكملها.
- 2C: يُستخدم مكون <asp:UpdateProgress> لعرض نص أو صورة أثناء التحديث لإعلام المستخدم، كما هو موضح أدناه:
![]() |
- (تابع)
- 2D: عنصر تحكم Label باسم LabelHeureLoad سيعرض الوقت الذي يتم فيه تشغيل معالج حدث Load للصفحة.
- 2E: عنصر Label باسم LabelHeureSalaire يعرض الوقت الذي يتم فيه تنفيذ معالج حدث النقر (Click) للزر [Salaire]. نريد أن نوضح أن Ajax لا يعيد تحميل الصفحة بالكامل عند النقر على الزر [Salaire]. يظهر هذا في لقطة الشاشة السابقة، حيث يمكن رؤية وقتين مختلفين في عنصري Label.
يمكن إجراء عملية Ajaxification السابقة للنموذج مباشرةً في شفرة المصدر لـ [Default.aspx] عن طريق إضافة علامات امتداد Ajax:
...
<body style="text-align: left" bgcolor="#ffccff">
<h3>
Feuille de salaire
<asp:Label ID="LabelHeureLoad" runat="server" BackColor="#C0C000"></asp:Label></h3>
<hr />
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true" />
<asp:UpdatePanel runat="server" ID="UpdatePanelPam" UpdateMode="Conditional">
<ContentTemplate>
<div>
<table>
<tr>
...
<tr>
<td>
<asp:DropDownList ID="ComboBoxEmployes" runat="server">
</asp:DropDownList></td>
<td>
<asp:TextBox ID="TextBoxHeures" runat="server" EnableViewState="False">
</asp:TextBox></td>
<td>
<asp:TextBox ID="TextBoxJours" runat="server" EnableViewState="False">
</asp:TextBox></td>
<td>
<asp:Button ID="ButtonSalaire" runat="server" Text="Salaire" CausesValidation="False" /></td>
<td> <asp:UpdateProgress ID="UpdateProgress1" runat="server">
<ProgressTemplate>
<img src="images/indicator.gif" />
<asp:Label ID="Label5" runat="server" BackColor="#FF8000" EnableViewState="False"
Text="Calcul en cours. Patientez ...."></asp:Label>
</ProgressTemplate>
</asp:UpdateProgress>
<asp:Label ID="LabelHeureSalaire" runat="server" BackColor="#C0C000"></asp:Label></td>
</tr>
<tr>
...
</tr>
</table>
</div>
<br />
....
<table>
<tr>
<td>
Salaire net à payer :
</td>
<td align="center" bgcolor="#C0C000" height="20px">
<asp:Label ID="LabelSN" runat="server" EnableViewState="False"></asp:Label></td>
</tr>
</table>
</asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
- السطر 8: يجب أن تتضمن أي نموذج يدعم Ajax العلامة <asp:ScriptManager>. تتيح هذه العلامة استخدام مكونات Ajax الجديدة:
![]() |
- يمكن إضافة العلامة <asp:ScriptManager> بالنقر المزدوج فوق مكون [ScriptManager] أعلاه. تأكد من أن هذه العلامة موجودة داخل العلامة <form> في شفرة المصدر. السمة [EnablePartialRendering="true"] في السطر 8 غير موجودة افتراضيًا. وبما أن "true" هي قيمتها الافتراضية، فهي ليست ضرورية تمامًا.
- السطر 9: تُستخدم علامة <asp:UpdatePanel> لتحديد مناطق الصفحة التي تحتاج إلى التحديث أثناء التحديث الجزئي للصفحة. تشير السمة [UpdateMode="Conditional"] إلى أنه يجب تحديث المنطقة فقط استجابةً لحدث AJAX من مكون داخل المنطقة. القيمة الأخرى هي [UpdateMode="Always"]، وهي القيمة الافتراضية. باستخدام هذه السمة، يتم تحديث منطقة UpdatePanel بشكل منهجي حتى إذا كان حدث AJAX الذي وقع قد نشأ من مكون في منطقة UpdatePanel أخرى. بشكل عام، هذا السلوك غير مرغوب فيه.
تدعم العلامة <asp:UpdatePanel> علامتين فرعيتين: <ContentTemplate> و <Triggers>.
- تحدد علامات <asp:ContentTemplate> في السطرين 10 و 53 منطقة الصفحة التي سيتم تحديثها جزئيًا.
- الأسطر 27–33: مكون Ajax <asp:UpdateProgress> يعرض نصًا طوال عملية تحديث الصفحة. على سبيل المثال، يؤدي النقر فوق الزر [Salary] إلى تشغيل طلب POST في الخلفية. لا يعرض المتصفح رمز الساعة الرملية، لذا قد يميل المستخدم إلى مواصلة استخدام النموذج. تعرض علامة <asp:UpdateProgress> نصًا يشير إلى أن الصفحة قيد التحديث. يمكن أيضًا عرض صورة. هنا، يتم عرض صورة متحركة (السطر 29) ونص (السطران 30-31):
![]() |
- الأسطر 28–32: تحدد علامة <ProgressTemplate> المحتوى الذي سيتم عرضه طوال فترة تحديث عنصر UpdatePanel الذي توجد فيه علامة UpdateProgress.
- الأسطر 29–31: الصورة المتحركة والنص اللذان سيتم عرضهما أثناء تحديث UpdatePanel.
- السطر 5: يتم وضع التسمية LabelHeureLoad خارج المنطقة التي تدعم AJAX
- السطر 34: يتم وضع التسمية LabelHeureSalaire داخل المنطقة التي تدعم AJAX
يتغير كود صفحة [ Default.aspx.cs] على النحو التالي:
protected void Page_Load(object sender, System.EventArgs e)
{
// time of each page load
LabelHeureLoad.Text = DateTime.Now.ToString("hh:mm:ss");
// initial request processing
if (!IsPostBack)
{
....
}
- السطر 4: تحديث وقت تحميل الصفحة
protected void ButtonSalaire_Click(object sender, System.EventArgs e)
{
// hourly wage calculation
LabelHeureSalaire.Text = DateTime.Now.ToString("hh:mm:ss");
// data verification
....
}
- السطر 4: تحديث وقت حساب الراتب
لإكمال صفحة [Default.aspx]، نحتاج إلى تضمين الصورة المتحركة المشار إليها في السطر 4 من شفرة المصدر التالية في الصفحة:
<td>
<asp:UpdateProgress ID="UpdateProgress1" runat="server">
<ProgressTemplate>
<img src="images/indicator.gif" />
<asp:Label ID="Label5" runat="server" BackColor="#FF8000" EnableViewState="False"
Text="Calcul en cours. Patientez ...."></asp:Label>
</ProgressTemplate>
</asp:UpdateProgress>
<asp:Label ID="LabelHeureSalaire" runat="server" BackColor="#C0C000"></asp:Label>
</td>
باستخدام مستكشف Windows، نضيف الملف [images/indicator.gif] إلى مجلد المشروع [1]:
![]() |
- في [2]، نعرض جميع ملفات المشروع
- في [3]، نختار مجلد [images]
- في [4]، نضمّن مجلد [images] في المشروع
![]() |
- في [5]، تم تضمين مجلد [images] في المشروع
- في [6]، نخفي الملفات التي ليست جزءًا من المشروع
- في [7]، المشروع الجديد
5.3. اختبار حل Ajax
عند تشغيل المشروع (CTRL-F5)، ستظهر لك الصفحة التالية:
![]() |
- في [1]، وقت تحميل الصفحة
اختبر التطبيق وتأكد من أن زر [الراتب] لا يتسبب في إعادة تحميل الصفحة بالكامل. يمكنك ملاحظة ذلك من خلال مقارنة الوقت المعروض لمعالجة النقر على زر [الراتب] [2]، والذي يختلف عن الوقت الذي استغرقته الصفحة في التحميل الأولي [3]:
![]() |
كرر الاختبارات عن طريق تعيين الخاصية EnablePartialRendering لمكون ScriptManager1 إلى False:
![]() |
لاحظ أن السلوك يشبه الآن سلوك الصفحة غير المستندة إلى AJAX. يتم إعادة تحميل الصفحة بالكامل عند النقر فوق الزر [الراتب]. كرر الاختبارات باستخدام متصفح مختلف. الغرض من الاختبار عبر المتصفحات هو إثبات أن JavaScript الذي تولده مكونات خادم ASP/AJAX يتم تفسيره بشكل صحيح من قبل المتصفحات المختلفة.
أخيرًا، دعونا نسلط الضوء على دور العلامة <asp:UpdateProgress>. في كود الإجراء [ButtonSalaire_Click] في [Default.aspx.cs]، أضف عبارة توقف الإجراء لمدة 3 ثوانٍ:
using System.Threading;
...
protected void ButtonSalaire_Click(object sender, System.EventArgs e)
{
// hourly wage calculation
LabelHeureSalaire.Text = DateTime.Now.ToString("hh:mm:ss");
// waiting
Thread.Sleep(3000);
// data verification
....
}
تؤدي السطر 8 إلى جعل الخيط الذي ينفذ الإجراء [ButtonSalaire_Click] ينتظر لمدة 5 ثوانٍ. وبمجرد الانتهاء من ذلك، دعونا نجري الاختبارات مرة أخرى (بعد تعيين الخاصية EnablePartialRendering لمكون ScriptManager1 على True). هذه المرة، نرى النص الوارد في [UpdateProgress] بالإضافة إلى الصورة المتحركة أثناء حساب الراتب:

5.4. الخلاصة
أظهرت الدراسة السابقة أنه من الممكن إضافة وظائف AJAX إلى تطبيقات ASP.NET الحالية. تتجاوز امتدادات ASP.NET AJAX ما رأيناه للتو. ندعو القراء لزيارة الموقع الإلكتروني [http://ajax.asp.net].










