Skip to content

4. التطبيق [SimuPaie] – الإصدار 1 – ASP.NET

4.1. Introduction

نرغب في كتابة تطبيق .NET يسمح للمستخدم بإجراء محاكاة لحساب رواتب المربيات في جمعية "Maison de la petite enfance" في إحدى البلديات.

سيكون شكل نموذج حساب الراتب ASP.NET كما يلي:

سيكون للتطبيق ASP.NET البنية التالية:

  • عند إجراء أول طلب إلى التطبيق، يتم إنشاء مثيل لكائن من النوع [Global] مشتق من النوع [System.Web.HttpApplication]. وهو الذي سيقوم باستغلال ملف التكوين [web.config] الخاص بالتطبيق الويب وتخزين بعض بيانات قاعدة البيانات في ذاكرة التخزين المؤقت (العملية 0 أعلاه).
  • عند الطلب الأول (العملية 1) المقدم إلى الصفحة [Default.aspx]، وهي الصفحة الوحيدة للتطبيق، تتم معالجة الحدث [Load]. يتم فيه معالجة ملء قائمة الموظفين المنسدلة. يتم طلب البيانات اللازمة لقائمة الاختيار من الكائن [Global] الذي قام بتخزينها مؤقتًا. هذه هي العملية 2 أعلاه. ترسل العملية 4 الصفحة التي تم تهيئتها بهذه الطريقة إلى المستخدم.
  • عند طلب حساب الراتب (العملية 1) المقدم إلى الصفحة [Default.aspx]، تتم معالجة الحدث [Load] مرة أخرى. لا يتم تنفيذ أي إجراء لأن الطلب من النوع POST، وقد تمت كتابة المدير [Pam_Load] بحيث لا يقوم بأي إجراء في هذه الحالة (استخدام القيمة المنطقية IsPostBack). بعد معالجة الحدث [Load]، يتم بعد ذلك معالجة الحدث [Click] على الزر [Salaire]. يحتاج هذا الحدث إلى بيانات لم يتم تخزينها مؤقتًا في [Global]. لذلك يطلبها مدير الحدث من قاعدة البيانات. هذه هي العملية 3 أعلاه. يتم بعد ذلك حساب الراتب وترسل العملية 4 النتائج إلى المستخدم.

4.2. مشروع Visual Web Developer 2008

  • في [1]، يتم إنشاء مشروع جديد
  • في [2]، من النوع [Web / Application Web ASP.NET]
  • في [3]، نسمي المشروع
  • في [4]، نحدد اسمه وفي [5] نحدد موقعه. سيتم إنشاء مجلد [c:\temp\pam-aspnet\pam-v1-adonet] للمشروع.
  • في [5]، مشروع Visual Web Developer
  • في [6]، خصائص المشروع (انقر بزر الماوس الأيمن على المشروع / خصائص / التطبيق).
  • إلى [7]، اسم التجميع الذي سيتم إنتاجه من خلال إنشاء المشروع
  • في [8]، مساحة الأسماء الافتراضية التي نرغب في الحصول عليها لفئات المشروع. أما الفئة [_Default] المحددة في الملفين [Default.aspx.cs] و [Default.aspx.designer.cs] فقد تم إنشاؤها في مساحة الاسم [pam_v1_adonet] المشتقة من اسم المشروع. يمكن تغيير مساحة الأسماء هذه مباشرةً في كود هذين الملفين:

[Default.aspx.cs]


using System;
....

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

[Default.aspx.designer.cs]


//------------------------------------------------------------------------------
// <تم إنشاؤه تلقائيًا>
//      تم إنشاء هذا الرمز بواسطة أداة.
//      إصدار وقت التشغيل: 2.0.50727.3603
//
//      قد تؤدي التعديلات التي تم إجراؤها على هذا الملف إلى حدوث سلوك غير صحيح وستفقد إذا
//      تم إعادة إنشاء الرمز.
// </auto-generated>
//------------------------------------------------------------------------------

namespace pam_v1 {
    
    
    public partial class _Default {
        
.........

يجب أيضًا تعديل ترميز الملف [Default.aspx]:

  

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

يشير السمة Inherits أعلاه إلى الفئة المحددة في الملفين [Default.aspx.cs] و [Default.aspx.designer.cs]. ويستخدم فيها مساحة الأسماء pam_v1.

4.2.1. النموذج [Default.aspx]

المظهر المرئي للنموذج [Default.aspx] هو كما يلي:

المكونات هي كما يلي:

رقم
النوع
الاسم
الدور
1
DropDownList
ComboBoxEmployes
يحتوي على قائمة بأسماء الموظفين
2
TextBox
TextBoxHeures
عدد ساعات العمل – العدد الفعلي
3
TextBox
TextBoxJours
عدد أيام العمل – عدد صحيح
4
زر
ButtonSalaire
طلب حساب الراتب
5
TextBox
TextBoxErreur
رسالة إعلامية موجهة إلى المستخدم
ReadOnly=true، TextMode=MultiLine
6
التسمية
LabelNom
اسم الموظف المحدد في (1)
7
التسمية
LabelPrénom
الاسم الأول للموظف المحدد في (1)
8
التسمية
LabelAdresse
العنوان
9
الملصق
LabelVille
المدينة
10
العلامة
LabelCP
الرمز البريدي
11
الملصق
LabelIndice
المؤشر
12
التسمية
LabelCSGRDS
معدل الاشتراك CSGRDS
13
التسمية
LabelCSGD
معدل الاشتراك CSGD
14
التسمية
LabelRetraite
معدل الاشتراك في التقاعد
15
التسمية
LabelSS
معدل اشتراك الضمان الاجتماعي
16
العلامة
LabelSH
الراتب الأساسي بالساعة للمؤشر المشار إليه في (11)
17
التسمية
LabelEJ
بدل الإعاشة اليومي للمؤشر المشار إليه في (11)
18
التسمية
LabelRJ
بدل الوجبات اليومي للمؤشر المشار إليه في (11)
19
التسمية
LabelCongés
معدل بدلات الإجازات المدفوعة التي تطبق على الراتب الأساسي
20
التسمية
LabelSB
مبلغ الراتب الأساسي
21
التسمية
LabelCS
مبلغ الاشتراكات الاجتماعية المستحقة
22
التسمية
LabelIE
مبلغ إعانات إعالة الطفل المربى
23
التسمية
LabelIR
مبلغ بدل وجبات الطفل المربى
24
التسمية
LabelSN
الراتب الصافي المستحق الدفع للموظف/الموظفة

يحتوي النموذج أيضًا على حاويتين من النوع [Panel]:

PanelErreurs
يحتوي على المكون (5) TextBoxErreur
PanelSalaire
يحتوي على المكونات من (6) إلى (24)

يمكن جعل مكون من النوع [Panel] مرئيًا أو غير مرئي برمجيًا بفضل خاصيته المنطقية [Panel].Visible.

4.2.2. التحقق من المدخلات

لحساب الراتب، يقوم المستخدم بما يلي:

  • يختار موظفًا في [1]
  • يدخل عدد ساعات العمل في [2]. يمكن أن يكون هذا الرقم عشريًا، مثل 2.5 لـ 2 ساعة و 30 دقيقة.
  • يدخل عدد أيام العمل في [3]. هذا الرقم صحيح.
  • اطلب الراتب باستخدام الزر [4]

عندما يقوم المستخدم بإدخال بيانات خاطئة في [2] و [3]، يتم التحقق منها بمجرد أن ينتقل المستخدم إلى حقل إدخال آخر. وبالتالي، تم الحصول على لقطة الشاشة أدناه قبل أن ينقر المستخدم على الزر [Salaire]:

هناك شرطان لتحقيق السلوك السابق:

  • يجب أن تكون خاصية EnableClientScript لمكونات التحقق من الصحة هي "صحيح":
  
  • يجب أن يكون المتصفح الذي يعرض الصفحة قادرًا على تنفيذ كود جافا سكريبت المضمن في الصفحة HTML.

إذا لم يتحقق متصفح العميل بنفسه من صحة البيانات، فلن يتم التحقق منها إلا عندما يقوم المتصفح بإرسال إدخالات النموذج إلى الخادم. عندئذٍ سيتحقق كود موجود على الخادم ويعالج طلب المتصفح من صحة البيانات. يُذكر أن هذا التحقق يجب أن يتم دائمًا حتى إذا كانت الصفحة المعروضة في متصفح العميل تحتوي على كود جافا سكريبت يقوم بنفس التحقق. في الواقع، لا يمكن للخادم التأكد من أن الطلب POST الموجه إليه يأتي بالفعل من هذه الصفحة، وبالتالي أن التحقق من البيانات قد تم.

قائمة أدوات التحقق هي كما يلي:

رقم
النوع
الاسم
الدور
25
RequiredFieldValidator
RequiredFieldValidatorHeures
تحقق من أن الحقل [2] [TextBoxHeures] ليس فارغًا
26
RangeValidator
RangeValidatorHeures
تحقق من أن الحقل [2] [TextBoxHeures] هو عدد حقيقي في النطاق [0, 200]
27
RequiredFieldValidator
RequiredFieldValidatorJours
تحقق من أن الحقل [3] [TextBoxJours] ليس فارغًا
28
RangeValidator
RangeValidatorJours
تحقق من أن الحقل [3] [TextBoxJours] هو عدد صحيح في النطاق [0,31]

المهمة المطلوبة: إنشاء الصفحة [Default.aspx]. سنقوم أولاً بوضع الحاويتين [PanelErreurs] و [PanelSalaire] حتى نتمكن بعد ذلك من وضع المكونات التي يجب أن تحتوي عليها.


4.2.3. كيانات التطبيق

بمجرد قراءتها، سيتم وضع أسطر الجداول [cotisations] و [employes] و [indemnites] في كائنات من النوع [Cotisations]، [Employe] و [Indemnites] المُعرَّفة على النحو التالي:


namespace Pam.Entites
{
  public class Cotisations
  {
    // الخصائص التلقائية
    public double CsgRds { get; set; }
    public double Csgd { get; set; }
    public double Secu { get; set; }
    public double Retraite { get; set; }

    // المنشئون
    public Cotisations()
    {
    }

    public Cotisations(double csgRds, double csgd, double secu, double retraite)
    {
      CsgRds = csgRds;
      Csgd = csgd;
      Secu = secu;
      Retraite = retraite;
    }

    // ToString
    public override string ToString()
    {
      return string.Format("[{0},{1},{2},{3}]", CsgRds, Csgd, Secu, Retraite);
    }
  }
}

namespace Pam.Entites
{
  public class Employe
  {
    // خصائص تلقائية
    public string SS { get; set; }
    public string Nom { get; set; }
    public string Prenom { get; set; }
    public string Adresse { get; set; }
    private string Ville { get; set; }
    private string CodePostal { get; set; }
    private int Indice { get; set; }

    // الشركات المصنعة
    public Employe()
    {

    }

    public Employe(string ss, string nom, string prenom, string adresse, string codePostal, string ville, int indice)
    {
      SS = ss;
      Nom = nom;
      Prenom = prenom;
      Adresse = adresse;
      CodePostal = codePostal;
      Ville = ville;
      Indice = indice;
    }

    // ToString
    public override string ToString()
    {
      return string.Format("[{0},{1},{2},{3},{4},{5},{6}]", SS, Nom, Prenom, Adresse, Ville, CodePostal, Indice);
    }
  }
}

namespace Pam.Entites
{
  public class Indemnites
  {

    // خصائص تلقائية
    public int Indice { get; set; }
    public double BaseHeure { get; set; }
    public double EntretienJour { get; set; }
    public double RepasJour { get; set; }
    public double IndemnitesCP { get; set; }

    // المصنعون
    public Indemnites()
    {

    }

    public Indemnites(int indice, double baseHeure, double entretienJour, double repasJour, double indemnitesCP)
    {
      Indice = indice;
      BaseHeure = baseHeure;
      EntretienJour = entretienJour;
      RepasJour = repasJour;
      IndemnitesCP = indemnitesCP;
    }

    // الهوية
    public override string ToString()
    {
      return string.Format("[{0}, {1}, {2}, {3}, {4}]", Indice, BaseHeure, EntretienJour, RepasJour, IndemnitesCP);
    }

  }
}

4.2.4. تكوين التطبيق

سيكون الملف [Web.config] الذي يقوم بتكوين التطبيق كما يلي:


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

<configuration>
    <configSections>
...
    </configSections>

  <connectionStrings>
    <add name="dbpamSqlServer2005" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=C:\data\...\dbpam.mdf;User Id=sa;Password=msde;Connect Timeout=30;" providerName="System.Data.SqlClient"/>
  </connectionStrings>

  <appSettings>
    <add key="selectEmploye" value="select NOM,PRENOM,ADRESSE,VILLE,CODEPOSTAL,INDICE from EMPLOYES where SS=@SS"/>
    <add key="selectEmployes" value="select PRENOM, NOM, SS from EMPLOYES"/>
    <add key="selectCotisations" value="select CSGRDS,CSGD,SECU,RETRAITE from COTISATIONS"/>
    <add key="SelectIndemnites" value="select INDICE,BASEHEURE,ENTRETIENJOUR,REPASJOUR,INDEMNITESCP from INDEMNITES"/>
  </appSettings>

  <system.web>
        <!-- 
            Définissez compilation debug="true" pour insérer des symboles 
            de débogage dans la page compilée. Comme ceci 
            affecte les performances, définissez cette valeur à true uniquement 
            lors du développement.
        -->
        <compilation debug="false">
...
</configuration>
  • السطر 9: يحدد سلسلة الاتصال بقاعدة البيانات SQL Server السابقة
  • الأسطر 13-16: تحدد الاستعلامات SQL التي يستخدمها التطبيق لتجنب تضمينها بشكل ثابت في الكود.
  • السطر 13: يتم تعيين معلمات الاستعلام SQL. صيغة المعلمات خاصة بـ SQL Server.

المهمة المطلوبة: إدخال هذه المعلمات في الملف [Web.config]. سيتم تعديل السطر 9 ليتناسب مع المسار الفعلي لقاعدة البيانات [dbpam.mdf].


4.2.5. تهيئة التطبيق

يتم تهيئة تطبيق ASP.NET بواسطة الملف [Global.asax.cs]. ويتم إنشاء هذا الملف على النحو التالي:

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

<%@ Application Codebehind="Global.asax.cs" Inherits="pam_v1.Global" Language="C#" %>

يتم تعريف الفئة [pam_v1.Global] في الملف [Global.asax.cs]. بالنسبة لمشكلتنا، سيتم تعريفها على النحو التالي:


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlClient;
using Pam.Entites;

namespace pam_v1
{
  public class Global : System.Web.HttpApplication
  {
    // --- بيانات التطبيق الثابتة ---
    public static Employe[] Employes;
    public static Cotisations Cotisations;
    public static Dictionary<int, Indemnites> Indemnites = new Dictionary<int, Indemnites>();
    public static string Msg = string.Empty;
    public static bool Erreur = false;
    public static string ConnectionString = null;

    // بدء تشغيل التطبيق
    public void Application_Start(object sender, EventArgs e)
    {
...
      try
      {
        // تسجيل الدخول
        ConnectionString = ...
        using (SqlConnection connexion = new SqlConnection(ConnectionString))
        {
          connexion.Open();
          // يتم استرداد قائمة الموظفين التي يتم وضعها في المصفوفة الثابتة [Employes]
...
          // استرداد معدلات الاشتراكات في المتغير الثابت [Cotisations]
...
          // يتم استرداد التعويضات في القاموس الثابت [Indemnites]
...
          // تم النجاح
          Msg = "Base chargée...";
        }
      }
      catch (Exception ex)
      {
        // يتم تسجيل الخطأ
        Msg = string.Format("L'erreur suivante s'est produite lors de l'accès à la base de données : {0}", ex);
        Erreur = true;
      }
    }
  }
}
  • السطر 20: يتم تنفيذ الطريقة [Application_Start] عند بدء تشغيل تطبيق الويب. ولا يتم تنفيذها سوى مرة واحدة.
  • الأسطر 12-17: الحقول العامة والثابتة للفئة. يتم مشاركة الحقل الثابت بين جميع مثيلات الفئة. وبالتالي، إذا تم إنشاء عدة مثيلات للفئة [Global]، فإنها تتشارك جميعها في نفس الحقل الثابت [Employes]، الذي يمكن الوصول إليه عبر المرجع [Global.Employesc.a.d. [NomDeClasse].ChampStatique. [Global] هو اسم فئة. وهو بالتالي نوع من أنواع البيانات. هذا الاسم تعسفي. الفئة مشتقة دائمًا من [System.Web.HttpApplication].

لنعد إلى فئتنا [Global]. قد نتساءل عما إذا كان من الضروري إعلان حقولها على أنها ثابتة. في الواقع، يبدو أنه في بعض الحالات، يمكن أن يكون لدينا عدة نسخ من الفئة [Global]، مما يبرر جعل الحقول التي يجب مشاركتها بين جميع هذه المثيلات ثابتة.

هناك طريقة أخرى لمشاركة البيانات ذات نطاق "التطبيق" بين الصفحات المختلفة لتطبيق ويب. وبالتالي، يمكن تخزين المصفوفة Employes الخاصة بالموظفين في الإجراء Application_Start بالطريقة التالية:


            Application.Add("employes",Employes);

[Application] هو افتراضيًا في أي تطبيق ASP.NET مرجع إلى مثيل للفئة المحددة بواسطة [Global.asax.cs]. Application هو حاوية يمكنها تخزين كائنات من أي نوع. يمكن بعد ذلك استرداد المصفوفة Employes في كود أي صفحة من صفحات تطبيق الويب بالطريقة التالية:


            Employe[] employes=Application.Get["employes"] as Employe[];

نظرًا لأن الحاوية Application تخزن كائنات من جميع الأنواع، فإننا نحصل على نوع Object الذي يتعين بعد ذلك تحويله. لا تزال هذه الطريقة قابلة للاستخدام، ولكن مشاركة البيانات عبر الحقول الثابتة المُصنفة للكائن [Global] تتجنب عمليات التحويل بين الأنواع وتسمح للمترجم بإجراء عمليات التحقق من النوع التي تساعد المطور. هذه هي الطريقة التي سيتم استخدامها هنا.

البيانات المشتركة بين جميع المستخدمين هي التالية:

  • السطر 12: مصفوفة الكائنات من النوع [Employe] التي ستخزن القائمة المبسطة (SS، NOM، PRENOM) لجميع الموظفين
  • السطر 13: الكائن من النوع [Cotisations] الذي سيخزن معدلات الاشتراكات
  • السطر 14: القاموس الذي سيخزن التعويضات المرتبطة بمؤشرات الموظفين المختلفة. سيتم فهرسته حسب مؤشر الموظف وستكون قيمه من النوع [Indemnites]
  • السطر 15: رسالة تشير إلى كيفية انتهاء التهيئة (بنجاح أو بخطأ)
  • السطر 16: قيمة منطقية تشير إلى ما إذا كانت عملية التهيئة قد انتهت بخطأ أم لا.
  • السطر 17: سلسلة الاتصال بقاعدة البيانات.

السؤال: أكمل كود الفئة [Application_Start].


4.3. أحداث النموذج [Default.aspx]

4.3.1. الإجراء [Page_Load]

عند تحميل النموذج [Default.aspx]، يبحث في الجدول [Global.Employes] (السطر 12) عن أسماء الموظفين لإدراجها في القائمة المنسدلة [1]:

  • تم ملء القائمة المنسدلة [1]
  • يشير TextBox [5] إلى أن قاعدة البيانات قد تمت قراءتها بشكل صحيح

إذا حدثت أخطاء في التهيئة عند بدء تشغيل التطبيق، فإن TextBox [5] تشير إلى ذلك:


السؤال: اكتب الإجراء [Page_Load] من صفحة الويب [Default.aspx] الذي، عند تنفيذه عند بدء تشغيل التطبيق، يضمن التشغيل السابق.


4.3.2. حساب الراتب

يؤدي النقر على الزر [4] إلى تشغيل المدير:


    protected void ButtonSalaire_Click(object sender, System.EventArgs e)

يبدأ هذا المدير بالتحقق من صحة الإدخالات التي تمت في [2] و [3]. إذا كان أحدهما غير صحيح، يتم الإبلاغ عن الخطأ كما هو موضح سابقًا. بمجرد التحقق من صحة الإدخالات في [2] و [3] وتأكيد صحتها، يجب أن تعرض التطبيق بيانات إضافية عن المستخدم المحدد في [1] بالإضافة إلى راتبه (انظر لقطة الشاشة في الفقرة 4.1).


السؤال: اكتب كود الإجراء [ButtonSalaire_Click].