4. Додаток [SimuPaie] — версія 1 — ASP.NET
4.1. Introduction
Ми хочемо написати додаток .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] такий:
![]() |
Компоненти такі:
№ | Тип | Назва | Роль |
DropDownList | ComboBoxEmployes | Містить список імен співробітників | |
TextBox | TextBoxHeures | Кількість відпрацьованих годин — фактична кількість | |
TextBox | TextBoxJours | Кількість відпрацьованих днів – ціле число | |
Кнопка | ButtonSalaire | Запит на розрахунок заробітної плати | |
TextBox | TextBoxErreur | Інформаційне повідомлення для користувача ReadOnly=true, TextMode=MultiLine | |
Мітка | LabelNom | Ім'я співробітника, обраного в пункті (1) | |
Мітка | LabelPrénom | Ім'я обраного працівника (1) | |
Мітка | LabelAdresse | Адреса | |
Етикетка | LabelVille | Місто | |
Етикетка | LabelCP | Поштовий індекс | |
Етикетка | LabelIndice | Індекс | |
Етикетка | LabelCSGRDS | Ставка внеску CSGRDS | |
Етикетка | LabelCSGD | Ставка внеску CSGD | |
Етикетка | LabelRetraite | Ставка страхового внеску на пенсійне забезпечення | |
Мітка | LabelSS | Ставка внесків на соціальне страхування | |
Етикетка | LabelSH | Базова погодинна заробітна плата для індексу, зазначеного в (11) | |
Мітка | LabelEJ | Добова надбавка на утримання для індексу, зазначеного в (11) | |
Мітка | LabelRJ | Добова надбавка на харчування за індексом, зазначеним у (11) | |
Мітка | LabelCongés | Ставка надбавки за оплачувану відпустку, що застосовується до базової заробітної плати | |
Мітка | LabelSB | Сума базової заробітної плати | |
Мітка | LabelCS | Сума соціальних внесків, що підлягають сплаті | |
Мітка | LabelIE | Сума виплат на утримання дитини, що перебуває під опікою | |
Мітка | LabelIR | Сума дотацій на харчування дитини, що перебуває під опікою | |
Мітка | LabelSN | Чиста заробітна плата, що підлягає виплаті працівнику |
Форма також містить два контейнери типу [Panel]:
містить компонент (5) TextBoxErreur | |
містить компоненти від (6) до (24) |
Компонент типу [Panel] можна зробити видимим або невидимим програмно за допомогою його булевого властивості [Panel].Visible.
4.2.2. Перевірка введених даних
Для розрахунку заробітної плати користувач:
- вибирає працівника в [1]
- вводить кількість відпрацьованих годин у полі [2]. Це число може бути десятковим, наприклад 2,5 для 2 годин 30 хвилин.
- вводить кількість відпрацьованих днів у полі [3]. Це число є цілим.
- запитуйте заробітну плату за допомогою кнопки [4]
![]() |
Коли користувач вводить неправильні дані в поля [2] та [3], вони перевіряються, щойно користувач переходить до іншого поля введення. Так, наведений нижче знімок екрана було зроблено ще до того, як користувач натиснув кнопку [Salaire]:
![]() |
Для забезпечення описаної вище поведінки необхідні дві умови:
- властивість EnableClientScript компонентів перевірки повинна мати значення «true»:
![]() |
- браузер, що відображає сторінку, повинен мати можливість виконувати код JavaScript, вбудований у сторінку HTML.
Якщо клієнтський браузер самостійно не перевіряє валідність даних, їх перевірка відбуватиметься лише тоді, коли браузер надішле дані, введені у форму, на сервер. Саме тоді код, розміщений на сервері та призначений для обробки запиту браузера, перевірить валідність даних. Нагадаємо, що ця перевірка має виконуватися завжди, навіть якщо сторінка, що відображається в браузері клієнта, містить код JavaScript, який здійснює ту саму перевірку. Адже сервер не може бути впевнений, що запит POST, який надходить до нього, дійсно походить з цієї сторінки і що, отже, перевірка даних була виконана.
Список валідаторів такий:
№ | Тип | Назва | Роль |
RequiredFieldValidator | RequiredFieldValidatorHeures | перевіряє, чи поле [2] [TextBoxHeures] не є порожнім | |
RangeValidator | RangeValidatorHeures | перевіряє, чи поле [2] [TextBoxHeures] є дійсним числом в інтервалі [0, 200] | |
RequiredFieldValidator | RequiredFieldValidatorJours | перевіряє, чи поле [3] [TextBoxJours] не є порожнім | |
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.
Завдання: внести ці параметри у файл [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.Employes], c.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].











