Skip to content

4. برنامه [SimuPaie] – نسخه 1 از ASP.NET

4.1. Introduction

ما می‌خواهیم یک برنامه .NET بنویسیم که به کاربر امکان انجام شبیه‌سازی‌های حقوق و دستمزد برای پرستاران کودک در انجمن «Maison de la petite enfance» در یک نهاد محلی را بدهد.

فرم ASP.NET برای محاسبه حقوق به شرح زیر خواهد بود:

Image

برنامه ASP.NET معماری زیر را خواهد داشت:

  • هنگامی که اولین درخواست به برنامه ارسال می‌شود، یک شی از نوع [Global] که از نوع [System.Web.HttpApplication] مشتق شده است، ایجاد می‌شود. این شیء فایل پیکربندی وب‌اپلیکیشن [web.config] را پردازش کرده و داده‌های خاصی را از پایگاه داده کش می‌کند (عملیات 0 بالا).
  • در اولین درخواست (عملیات ۱) به صفحه [Default.aspx] – که تنها صفحهٔ برنامه است – رویداد [Load] پردازش می‌شود. این رویداد مسئول پر کردن لیست کشویی کارمندان است. داده‌های مورد نیاز برای لیست کشویی از شیء [Global] که آن‌ها را در کش ذخیره کرده است، بازیابی می‌شود. این عملیات ۲ فوق است. عملیات ۴ صفحه را که اکنون اولیه شده است برای کاربر ارسال می‌کند.
  • هنگامی که درخواستی برای محاسبه حقوق (عملیات ۱) به صفحه [Default.aspx] ارسال می‌شود، رویداد [Load] مجدداً پردازش می‌شود. هیچ اتفاقی نمی‌افتد زیرا این یک درخواست از نوع POST است و هندلر [Pam_Load] طوری نوشته شده است که در این مورد هیچ کاری انجام ندهد (با استفاده از بولین IsPostBack). پس از پردازش رویداد [Load]، رویداد [Click] روی دکمه [Salaire] نیز پردازش می‌شود. این رویداد به داده‌هایی نیاز دارد که در [Global] کش نشده‌اند. بنابراین، رویدادپرداز این داده‌ها را از پایگاه داده بازیابی می‌کند. این عملیات ۳ بالا است. سپس حقوق محاسبه می‌شود و عملیات ۴ نتایج را برای کاربر ارسال می‌کند.

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]، ویژگی‌های پروژه (روی پروژه کلیک راست کنید / Properties / Application).
  • به [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
پیام اطلاعاتی برای کاربر
خواندنی=true، حالت متن=چندخطی
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
مزد ساعتی پایه برای شاخص مشخص‌شده در (۱۱)
17
برچسب
LabelEJ
سربار روزانه برای شاخص مشخص‌شده در (۱۱)
18
برچسب
LabelRJ
کمک‌هزینه روزانه غذا برای شاخص مشخص‌شده در (۱۱)
19
برچسب
LabelCongés
نرخ فوق‌العاده مرخصی پرداختی که باید بر حقوق پایه اعمال شود
20
برچسب
LabelSB
مبلغ حقوق پایه
21
برچسب
LabelCS
مبلغ حق بیمه تأمین اجتماعی قابل پرداخت
22
برچسب
LabelIE
مبلغ کمک‌هزینه نگهداری کودک
23
برچسب
LabelIR
مبلغ کمک‌هزینه غذا برای کودک تحت سرپرستی
24
برچسب
LabelSN
حقوق خالص پرداختی به کارمند

این فرم همچنین شامل دو کانتینر از نوع [Panel] است:

PanelErreurs
حاوی مؤلفه (۵) TextBoxErreur
PanelSalaire
حاوی اجزای (۶) تا (۲۴) است

یک کامپوننت از نوع [Panel] را می‌توان به‌صورت برنامه‌ای با استفاده از خاصیت بولین آن، [Panel].Visible، قابل مشاهده یا مخفی کرد.

4.2.2. اعتبارسنجی ورودی

برای محاسبه حقوق، کاربر:

  • یک کارمند را در [1] انتخاب می‌کند
  • تعداد ساعات کاری را در [2] وارد می‌کند. این عدد می‌تواند اعشاری باشد، مانند ۲.۵ برای ۲ ساعت و ۳۰ دقیقه.
  • تعداد روزهای کاری را در [3] وارد کنید. این عدد یک عدد صحیح است.
  • درخواست حقوق را با استفاده از دکمه [4] انجام می‌دهد

هنگامی که کاربر داده‌های نادرستی را در [2] و [3] وارد می‌کند، این داده‌ها به محض اینکه کاربر به فیلد ورودی دیگری می‌رود، بررسی می‌شوند. بنابراین، اسکرین‌شات زیر حتی قبل از اینکه کاربر دکمه [Salaire] را کلیک کند، گرفته شده است:

برای وقوع رفتاری که در بالا توضیح داده شد، دو شرط باید برقرار باشد:

  • کامپوننت‌های اعتبارسنجی باید ویژگی EnableClientScript آن‌ها روی true تنظیم شده باشد:
  
  • مرورگری که صفحه را نمایش می‌دهد باید قادر به اجرای کد جاوااسکریپت تعبیه‌شده در صفحه باشد 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>
  • خط ۹: رشته اتصال به سرور SQL که قبلاً ذکر شد را تعریف می‌کند
  • خطوط ۱۳–۱۶: پرس‌وجوهایی را که توسط برنامه استفاده می‌شوند، تعریف می‌کنند تا از کدنویسی سخت آن‌ها در کد جلوگیری شود.
  • خط ۱۳: پرس‌وجوی SQL پیکربندی شده است. نحو پارامترها مختص سرور SQL است.

وظیفه: این پارامترها را در فایل [Web.config] وارد کنید. خط ۹ برای مسیر واقعی پایگاه داده [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;
      }
    }
  }
}
  • خط ۲۰: متد [Application_Start] هنگام راه‌اندازی برنامه وب اجرا می‌شود. این متد تنها یک بار اجرا می‌شود.
  • خطوط ۱۲–۱۷: فیلدهای عمومی و ایستا کلاس. یک فیلد ایستا بین همه نمونه‌های کلاس مشترک است. بنابراین، اگر چندین نمونه از کلاس [Global] ایجاد شوند، همه آنها از یک فیلد استاتیک یکسان [Employes] استفاده می‌کنند که از طریق ارجاع [Global.Employesc.a.d قابل دسترسی است. [NomDeClasse].ChampStatique. [Global] نام یک کلاس است. بنابراین، یک نوع داده است. این نام دلخواه است. این کلاس همیشه از [System.Web.HttpApplication] ارث می‌برد.

بیایید به کلاس خود [Global] بازگردیم. ممکن است این سؤال پیش بیاید که آیا لازم است فیلدهای آن را به صورت استاتیک (static) اعلام کرد یا خیر. در واقع، به نظر می‌رسد که در برخی موارد، ممکن است چندین نمونه از کلاس [Global] وجود داشته باشد، که این امر توجیه می‌کند فیلدهایی را که باید توسط همه این نمونه‌ها به اشتراک گذاشته شوند، استاتیک در نظر بگیریم.

راه دیگری برای اشتراک‌گذاری داده‌های با دامنه «application» بین صفحات مختلف یک برنامه وب وجود دارد. بنابراین، آرایه کارمندان Employes می‌تواند به صورت زیر در رویه Application_Start ذخیره شود:


            Application.Add("employes",Employes);

به طور پیش‌فرض، در هر برنامه‌ای، [Application] مرجعی به یک نمونه از کلاسی است که توسط ASP.NET تعریف شده است. Application یک کانtejner است که قادر به ذخیره اشیاء از هر نوعی می‌باشد. آرایه Employes سپس می‌تواند در کد هر صفحه از برنامه وب به صورت زیر بازیابی شود:


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

از آنجا که مخزن Application اشیاء از هر نوع را ذخیره می‌کند، ما نوع Object را بازیابی می‌کنیم که سپس باید به نوع مناسب تبدیل شود. این روش هنوز قابل استفاده است، اما اشتراک‌گذاری داده‌ها از طریق فیلدهای ایستا و نوع‌دارِ شیء [Global] از تبدیل نوع جلوگیری می‌کند و به کامپایلر امکان می‌دهد تا بررسی‌های نوع را انجام دهد که به توسعه‌دهنده کمک می‌کند. این روشی است که در اینجا استفاده خواهد شد.

داده‌های مشترک بین همه کاربران به شرح زیر است:

  • خط ۱۲: آرایه از اشیاء از نوع [Employe]، که لیست ساده‌شده (SS, NOM, PRENOM) تمام کارمندان را ذخیره خواهد کرد
  • خط ۱۳: شیء از نوع [Cotisations] که نرخ‌های مشارکت را ذخیره خواهد کرد
  • خط ۱۴: فرهنگ‌لغت که مزایای مرتبط با شاخص‌های مختلف کارکنان را ذخیره خواهد کرد. این فرهنگ‌لغت بر اساس شاخص کارمند نمایه‌بندی شده و مقادیر آن از نوع [Indemnites] خواهد بود.
  • خط ۱۵: پیامی که نتیجهٔ آغازسازی را (موفق یا با خطا) نشان می‌دهد
  • خط ۱۶: یک مقدار بولی که نشان می‌دهد آیا فرایند اولیه با خطا پایان یافته است یا خیر
  • خط ۱۷: رشته اتصال به پایگاه داده.

سؤال: کد کلاس [Application_Start] را تکمیل کنید.


4.3. رویدادهای فرم [Default.aspx]

4.3.1. روند [Page_Load]

وقتی فرم [Default.aspx] بارگذاری می‌شود، نام کارمندان را از جدول [Global.Employes] (خط ۱۲) بازیابی کرده و در لیست کشویی [1] قرار می‌دهد:

  • فهرست کشویی [1] پر شده است
  • TextBox و [5] نشان می‌دهند که پایگاه داده به درستی خوانده شده است

اگر هنگام راه‌اندازی برنامه خطاهای инициализация رخ داده باشد، TextBox و [5] این را نشان می‌دهند:

Image


سؤال: رویه [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] را بنویسید.