1. بخش ۱
نسخه PDF سند در |ICI| موجود است.
نمونههای موجود در سند در |ICI| در دسترس هستند.
1.1. Introduction
اهداف این مقاله:
- نوشتن یک برنامه وب سهلایه [interface utilisateur, métier, accès aux données]
- برای پیکربندی برنامه با استفاده از Spring IOC
- برای نوشتن نسخههای مختلف با تغییر پیادهسازی یکی یا چند تا از سه لایه.
ابزارهای مورد استفاده:
- Visual Studio.net برای توسعه – به بخش ۳.۱ در پیوست مراجعه کنید؛
- سرور وب Cassini برای اجرا – به بخش ۳.۲ پیوست مراجعه کنید؛
- Nunit برای تست واحد – به بخش 3.4 پیوست مراجعه کنید؛
- Spring برای یکپارچهسازی و پیکربندی لایههای اپلیکیشن وب – به بخش 3.3 پیوست مراجعه کنید؛
در مقیاس مبتدی–میانی–پیشرفته، این سند در دسته [intermédiaire-avancé] قرار میگیرد. درک آن نیازمند پیشنیازهای مختلفی است. برخی از این پیشنیازها را میتوان در اسنادی که من نوشتهام یافت. در مواردی که چنین است، به آنها ارجاع میدهم. بدیهی است که این صرفاً یک پیشنهاد است و خواننده آزاد است از اسناد مورد علاقه خود استفاده کند.
- [مقدمهای بر VB.NET از طریق مثالها (۲۰۰۴)];
- [توسعه وب با ASP.NET 1.1 (2004)];
- [Spring IoC برای .NET (۲۰۰۵)];
- مستندات Spring.net: [Spring.NET | Homepage ]
این سند از ساختار سندی که برای جاوا [معماریهای سه لایه و معماریهای MVC با Struts، Spring و Java ] نوشته شده است، پیروی میکند. ما در حال ساخت اپلیکیشن وب سهلایه MVC هستیم که با استفاده از VB.NET به زبان جاوا نوشته شده است. نکتهٔ ما این است که پلتفرمهای توسعهٔ جاوا و .NET بهاندازهٔ کافی شبیه به هم هستند که مهارتهای کسبشده در هر یک از این دو حوزه را بتوان در حوزهی دیگر نیز بهکار برد.
به نظر نمیرسد راهحل توسعهٔ MVC ASP.NET شناختهشدهای وجود داشته باشد. راهحل زیر از روشی که در سند [توسعه وب با ASP.NET 1.1 (2004)] معرفی شده است، پیروی میکند. اگرچه این روش از این مزیت برخوردار است که از مفاهیمی که در توسعه J2EE به طور گسترده رایج هستند، استفاده میکند، با این حال باید به همان شکلی که هست در نظر گرفته شود: c.a.d، تنها یکی از روشهای متعدد توسعه MVC. به محض اینکه یک روش توسعه برای MVC در ASP.NET به طور گسترده پذیرفته شود، باید از آن روش استفاده کرد. نسخه .NET از Spring که در حال حاضر در دست توسعه است، میتواند یک راهحل اولیه باشد.
1.2. برنامهٔ webarticles
در اینجا اجزای یک اپلیکیشن وب تجارت الکترونیک سادهشده را ارائه میدهیم. این به کاربران وب امکان میدهد تا:
- مشاهده فهرستی از اقلام موجود در پایگاه داده
- تا برخی از آنها را به سبد خرید آنلاین اضافه کنند
- تا انتخاب خود را تأیید کنند. این تأیید به سادگی سطوح موجودی اقلام خریداری شده را در پایگاه داده بهروز میکند.
نماهای مختلفی که به کاربر ارائه میشوند به شرح زیر خواهد بود:
- نمای «LISTE» که فهرستی از اقلام قابل فروش را نمایش میدهد ![]() | - نمای [INFOS] که اطلاعات بیشتری در مورد یک محصول ارائه میدهد: ![]() |
- نماهای [PANIER] و [PANIERVIDE] که محتویات سبد خرید مشتری را نمایش میدهند
![]() | ![]() |
- نمای [ERREURS] که هرگونه خطای برنامه را گزارش میکند

1.3. معماری کلی برنامه
ما میخواهیم یک برنامه با معماری سهلایه زیر بسازیم:
![]() |
- سه لایه از طریق استفاده از رابطها مستقل شدهاند
- یکپارچهسازی لایههای مختلف توسط Spring انجام میشود
- به هر لایه فضای نام (namespace) مخصوص به خود اختصاص داده شده است: web (لایه UI)، domain (لایه کسبوکار) و DAO (لایه دسترسی به داده).
برنامه از معماری MVC (مدل–نما–کنترلکننده) پیروی خواهد کرد. اگر به نمودار لایهای بالا مراجعه کنیم، معماری MVC به شرح زیر در آن جای میگیرد:
![]() |
پردازش یک درخواست مشتری مراحل زیر را دنبال میکند:
- کلاینت درخواستی را به کنترلر ارسال میکند. در این مورد، کنترلر یک صفحه .aspx است که یک نقش خاص به آن اختصاص داده شده است. این صفحه تمام درخواستهای کلاینت را مدیریت میکند. این نقطه ورود به برنامه است. این «C» در ساختار MVC است.
- کنترلکننده این درخواست را پردازش میکند. برای این کار، ممکن است به کمک لایه کسبوکار، که در معماری MVC بهعنوان مدل «M» شناخته میشود، نیاز داشته باشد.
- کنترلکننده پاسخی را از لایه کسبوکار دریافت میکند. درخواست مشتری پردازش شده است. این ممکن است به چندین پاسخ احتمالی منجر شود. یک مثال کلاسیک این است
- یک صفحهٔ خطا اگر درخواست نتوانست به درستی پردازش شود
- در غیر این صورت، یک صفحه تأیید
- کنترلکننده پاسخ (= نما) را برای ارسال به کلاینت انتخاب میکند. این معمولاً صفحهای حاوی عناصر پویا است. کنترلکننده این عناصر را در اختیار نما قرار میدهد.
- ویو به کلاینت ارسال میشود. این «V» در ساختار MVC است.
1.4. مدل
در اینجا به M در MVC میپردازیم. مدل شامل عناصر زیر است:
- کلاسهای کسبوکار
- کلاسهای دسترسی به داده
- پایگاه داده
1.4.1. پایگاه داده
پایگاه داده تنها شامل یک جدول به نام ARTICLES است. این جدول با استفاده از دستورات زیر SQL ایجاد شده است:
CREATE TABLE ARTICLES (
ID INTEGER NOT NULL,
NOM VARCHAR(20) NOT NULL,
PRIX NUMERIC(15,2) NOT NULL,
STOCKACTUEL INTEGER NOT NULL,
STOCKMINIMUM INTEGER NOT NULL
);
/* محدودیتها */
ALTER TABLE ARTICLES ADD CONSTRAINT CHK_ID check (ID>0);
ALTER TABLE ARTICLES ADD CONSTRAINT CHK_PRIX check (PRIX>=0);
ALTER TABLE ARTICLES ADD CONSTRAINT CHK_STOCKACTUEL check (STOCKACTUEL>=0);
ALTER TABLE ARTICLES ADD CONSTRAINT CHK_STOCKMINIMUM check (STOCKMINIMUM>=0);
ALTER TABLE ARTICLES ADD CONSTRAINT CHK_NOM check (NOM<>'');
ALTER TABLE ARTICLES ADD CONSTRAINT UNQ_NOM UNIQUE (NOM);
/* کلید اصلی */
ALTER TABLE ARTICLES ADD CONSTRAINT PK_ARTICLES PRIMARY KEY (ID);
کلید اصلی که یک آیتم را بهطور منحصربهفرد شناسایی میکند | |
نام آیتم | |
قیمت آن | |
موجودی فعلی | |
سطح موجودی که در زیر آن باید سفارش مجدد ثبت شود |
1.4.2. فضای نامهای مدل
مدل M در اینجا به صورت دو فضای نام ارائه شده است:
- istia.st.articles.dao: شامل کلاسهای دسترسی به دادهها برای لایه [dao] است
- istia.st.articles.domain: شامل کلاسهای کسبوکار لایه [domain] است
هر یک از این فضاهای نام در فایل «assembly» مخصوص به خود تولید خواهند شد:
contenu | rôle | |
- [IArticlesDao]: رابط دسترسی به لایه [dao]. این تنها رابط قابل مشاهده برای لایه [domain] است. این لایه رابطهای دیگری را نمیبیند. - [Article]: کلاسی که یک آیتم را تعریف میکند - [ArticlesDaoArrayList]: کلاس پیادهسازی برای رابط [IArticlesDao] با [ArrayList] | لایه دسترسی به داده - به طور کامل در داخل [dao] از معماری سهلایه برنامه وب | |
- [IArticlesDomain]: رابطی که دسترسی به لایه [domain] را فراهم میکند. این تنها رابطی است که برای لایه وب قابل مشاهده است. این لایه رابطهای دیگری را نمیبیند. - [AchatsArticles]: کلاسی که [IArticlesDomain] را پیادهسازی میکند - [Achat]: کلاسی که نمایانگر خرید مشتری است - [Panier]: کلاسی که تمام خریدهای یک مشتری را نشان میدهد | نماینده مدل خریدهای آنلاین است وب – کاملاً در داخل قرار دارد لایه [domain] از معماری اپلیکیشن وب سهلایه |
1.4.3. لایه [dao]
لایه [dao] شامل عناصر زیر است:
-
[IArticlesDao]: رابط دسترسی به لایه [dao]
-
[Article]: کلاسی که یک آیتم را تعریف میکند
-
[ArticlesDaoArrayList]: یک کلاس پیادهسازی برای رابط [IArticlesDao]، با استفاده از کلاس [ArrayList]
ساختار پروژه [Visual Studio] در لایه [dao] به شرح زیر است:

توضیحات:
- پروژه [dao] از نوع [bibliothèque de classes] است
- کلاسها در یک ساختار درختی قرار گرفتهاند که پوشه [istia] بهعنوان ریشه است. همگی در فضای نام [istia.st.articles.dao] قرار دارند.
1.4.3.1. کلاس [Article]
کلاس تعریفکننده یک مقاله به شرح زیر است:
Imports System
Namespace istia.st.articles.dao
Public Class Article
' fields خصوصی
Private _id As Integer
Private _nom As String
Private _prix As Double
Private _stockactuel As Integer
Private _stockminimum As Integer
'شناسه آیتم
Public Property id() As Integer
Get
Return _id
End Get
Set(ByVal Value As Integer)
If Value <= 0 Then
Throw New Exception("Le champ id [" + Value.ToString + "] est invalide")
End If
Me._id = Value
End Set
End Property
' نام آیتم
Public Property nom() As String
Get
Return _nom
End Get
Set(ByVal Value As String)
If Value Is Nothing OrElse Value.Trim.Equals("") Then
Throw New Exception("Le champ nom [" + Value + "] est invalide")
End If
Me._nom = Value
End Set
End Property
' قیمت کالا
Public Property prix() As Double
Get
Return _prix
End Get
Set(ByVal Value As Double)
If Value < 0 Then
Throw New Exception("Le champ prix [" + Value.ToString + "] est invalide")
End If
Me._prix = Value
End Set
End Property
' موجودی فعلی کالا
Public Property stockactuel() As Integer
Get
Return _stockactuel
End Get
Set(ByVal Value As Integer)
If Value < 0 Then
Throw New Exception("Le champ stockActuel [" + Value.ToString + "] est invalide")
End If
Me._stockactuel = Value
End Set
End Property
'حداقل موجودی برای کالا
Public Property stockminimum() As Integer
Get
Return _stockminimum
End Get
Set(ByVal Value As Integer)
If Value < 0 Then
Throw New Exception("Le champ stockMinimum [" + Value.ToString + "] est invalide")
End If
Me._stockminimum = Value
End Set
End Property
' تولیدکننده پیشفرض
Public Sub New()
End Sub
' تولیدکننده دارای ویژگیها
Public Sub New(ByVal id As Integer, ByVal nom As String, ByVal prix As Double, ByVal stockactuel As Integer, ByVal stockminimum As Integer)
Me.id = id
Me.nom = nom
Me.prix = prix
Me.stockactuel = stockactuel
Me.stockminimum = stockminimum
End Sub
' روش شناسایی آیتم
Public Overrides Function ToString() As String
Return "[" + id.ToString + "," + nom + "," + prix.ToString + "," + stockactuel.ToString + "," + stockminimum.ToString + "]"
End Function
End Class
End Namespace
این کلاس فراهم میکند:
- یک سازنده برای تنظیم پنج بخش اطلاعات یک آیتم: [id, nom, prix, stockactuel, stockminimum]
- ویژگیهای عمومی برای خواندن و نوشتن این پنج مورد اطلاعات.
- اعتبارسنجی دادههای واردشده برای آیتم. اگر دادهها نادرست باشند، یک استثنا پرتاب میشود.
- یک متد، toString، که مقدار یک آیتم را به صورت یک رشته بازیابی میکند. این امر اغلب برای اشکالزدایی یک برنامه کاربردی مفید است.
1.4.3.2. رابط [IArticlesDao]
رابط [IArticlesDao] به شرح زیر تعریف شده است:
Imports System
Imports System.Collections
Namespace istia.st.articles.dao
Public Interface IArticlesDao
' فهرست تمام اقلام
Function getAllArticles() As IList
' یک آیتم اضافه میکند
Function ajouteArticle(ByVal unArticle As Article) As Integer
' یک آیتم را حذف میکند
Function supprimeArticle(ByVal idArticle As Integer) As Integer
' ویرایش یک آیتم
Function modifieArticle(ByVal unArticle As Article) As Integer
'جستجوی یک آیتم
Function getArticleById(ByVal idArticle As Integer) As Article
' تمام اقلام را حذف میکند
Sub clearAllArticles()
'سطح موجودی یک آیتم را تغییر میدهد
Function changerStockArticle(ByVal idArticle As Integer, ByVal mouvement As Integer) As Integer
End Interface
End Namespace
نقش روشهای مختلف در رابط کاربری به شرح زیر است:
بازگرداندن تمام رکوردها از منبع داده | |
منبع داده را پاک میکند | |
شیء [Article] را که با کلید اصلیاش شناسایی شده است بازمیگرداند | |
امکان افزودن یک آیتم به منبع داده را فراهم میکند | |
به شما امکان میدهد یک آیتم را در منبع داده اصلاح کنید | |
به شما امکان میدهد یک آیتم را از منبع داده حذف کنید | |
به شما امکان میدهد سطح موجودی یک آیتم را در منبع داده تغییر دهید |
رابط، برنامههای کلاینت را با تعدادی متد فراهم میکند که تنها بر اساس امضاهایشان تعریف شدهاند. این رابط به نحوه پیادهسازی واقعی این متدها کاری ندارد. این امر انعطافپذیری را در یک برنامه فراهم میکند. برنامه کلاینت به جای یک پیادهسازی خاص از آن رابط، به خود رابط فراخوانی میکند.
![]() |
انتخاب یک پیادهسازی خاص از طریق یک فایل پیکربندی Spring انجام خواهد شد. برای نشان دادن اینکه هنگام تست اپلیکیشن وب، تنها رابط دسترسی به داده اهمیت دارد—و نه کلاس پیادهسازی آن—ابتدا منبع داده را با استفاده از یک شیء ساده [ArrayList] پیادهسازی خواهیم کرد. سپس، راهحلی مبتنی بر SGBD ارائه خواهیم داد.
1.4.3.3. کلاس پیادهسازی [ArticlesDaoArrayList]
کلاس پیادهسازی [ArticlesDaoArrayList] به صورت زیر تعریف شده است:
Imports System
Imports System.Collections
Namespace istia.st.articles.dao
Public Class ArticlesDaoArrayList
Implements istia.st.articles.dao.IArticlesDao
Private articles As New ArrayList
Private Const nbArticles As Integer = 4
'تولیدکننده پیشفرض
Public Sub New()
'تولید برخی اقلام
For i As Integer = 1 To nbArticles
articles.Add(New Article(i, "article" + i.ToString, i * 10, i * 10, i * 10))
Next
End Sub
'فهرست تمام اقلام
Public Function getAllArticles() As IList Implements IArticlesDao.getAllArticles
' فهرست اقلام را بازمیگرداند
SyncLock Me
Return articles
End SyncLock
End Function
' حذف همه اقلام
Public Sub clearAllArticles() Implements IArticlesDao.clearAllArticles
' پاک کردن فهرست آیتمها
SyncLock Me
articles.Clear()
End SyncLock
End Sub
'بازیابی یک آیتم با شناسهٔ کلید آن
Public Function getArticleById(ByVal idArticle As Integer) As Article Implements IArticlesDao.getArticleById
'جستجوی آیتم در لیست
SyncLock Me
Dim ipos As Integer = posArticle(articles, idArticle)
If ipos <> -1 Then
Return CType(articles(ipos), Article)
Else
Return Nothing
End If
End SyncLock
End Function
' افزودن یک آیتم به فهرست آیتمها
Public Function ajouteArticle(ByVal unArticle As Article) As Integer Implements IArticlesDao.ajouteArticle
' مورد به فهرست موارد اضافه میشود
SyncLock Me
'بررسی میکند که قبلاً وجود نداشته باشد
Dim ipos As Integer = posArticle(articles, unArticle.id)
If ipos <> -1 Then
Throw New Exception("L'article d'id [" + unArticle.id.ToString + "] existe déjà")
End If
'آیتم اضافه میشود
articles.Add(unArticle)
' بازگرداندن نتیجه
Return 1
End SyncLock
End Function
' ویرایش یک آیتم
Public Function modifieArticle(ByVal articleNouveau As Article) As Integer Implements IArticlesDao.modifieArticle
' ویرایش یک آیتم
SyncLock Me
'بررسی میکند که وجود دارد
Dim ipos As Integer = posArticle(articles, articleNouveau.id)
' اگر وجود نداشته باشد
If ipos = -1 Then Return 0
' وجود دارد – آن را ویرایش میکنیم
articles(ipos) = articleNouveau
' نتیجه را بازگردانید
Return 1
End SyncLock
End Function
' حذف یک آیتم با شناسهٔ کلیدش
Public Function supprimeArticle(ByVal idArticle As Integer) As Integer Implements IArticlesDao.supprimeArticle
' حذف یک آیتم
SyncLock Me
'بررسی وجود آن
Dim ipos As Integer = posArticle(articles, idArticle)
' اگر وجود نداشته باشد
If ipos = -1 Then Return 0
' وجود دارد – آن را حذف کنید
articles.RemoveAt(ipos)
' نتیجه را بازمیگرداند
Return 1
End SyncLock
End Function
'تغییر سطح موجودی یک آیتم مشخصشده با کلید آن
Public Function changerStockArticle(ByVal idArticle As Integer, ByVal mouvement As Integer) As Integer Implements IArticlesDao.changerStockArticle
'تغییر سطح موجودی یک کالا
SyncLock Me
'بررسی میکند که آیا وجود دارد
Dim ipos As Integer = posArticle(articles, idArticle)
' اگر وجود نداشته باشد
If ipos = -1 Then Return 0
' اگر موجود باشد – در صورت امکان موجودی آن را بهروزرسانی کنید
Dim unArticle As Article = CType(articles(ipos), Article)
' فقط در صورتی موجودی را تغییر میدهیم که موجودی کافی باشد
If unArticle.stockactuel + mouvement >= 0 Then
unArticle.stockactuel += mouvement
Return 1
Else
Return 0
End If
End SyncLock
End Function
'جستجوی یک آیتم با استفاده از کلید آن
Private Function posArticle(ByVal listArticles As ArrayList, ByVal idArticle As Integer) As Integer
'موقعیت آیتم [idArticle] را در لیست بازمیگرداند، یا در صورت عدم یافتن -1
Dim unArticle As Article
For i As Integer = 0 To listArticles.Count - 1
unArticle = CType(listArticles(i), Article)
If unArticle.id = idArticle Then
Return i
End If
Next
' یافت نشد
Return -1
End Function
End Class
End Namespace
توضیحات:
- منبع داده توسط فیلد خصوصی [articles] از نوع [ArrayList] شبیهسازی میشود.
- سازنده کلاس بهطور پیشفرض ۴ آیتم در منبع داده ایجاد میکند.
- تمام روشهای دسترسی به دادهها همگامسازی شدهاند تا از بروز مشکلات ناشی از دسترسی همزمان به منبع داده جلوگیری شود. در هر لحظه، تنها یک نخ به یک روش مشخص دسترسی دارد.
- متد [posArticle] برای تعیین موقعیت [0..N] در منبع [ArrayList] یک آیتم که با شماره آن شناسایی شده است، استفاده میشود. اگر آیتم وجود نداشته باشد، متد موقعیت -1 را برمیگرداند. این متد توسط متدهای دیگر به طور مکرر فراخوانی میشود.
- روش [ajouteArticle] برای افزودن یک آیتم به فهرست آیتمها استفاده میشود. این روش تعداد آیتمهای درجشده را برمیگرداند: 1 اگر آیتم وجود داشته باشد، در غیر این صورت 0. اگر آیتم از قبل وجود داشته باشد، یک استثنا پرتاب میشود.
- روش [modifieArticle] برای اصلاح یک آیتم موجود استفاده میشود. این روش تعداد آیتمهای اصلاحشده را برمیگرداند: 1 اگر آیتم وجود داشته باشد، در غیر این صورت 0.
- روش [supprimeArticle] برای حذف یک آیتم موجود استفاده میشود. این روش تعداد آیتمهای حذفشده را برمیگرداند: 1 اگر آیتم وجود داشته باشد، در غیر این صورت 0.
- روش [getAllArticles] فهرستی از تمام آیتمها را بازمیگرداند
- روش [getArticleById] برای بازیابی یک آیتم با شمارهٔ آن استفاده میشود. مقدار [nothing] در صورتی که آیتم وجود نداشته باشد، بازگردانده میشود.
- این کد هیچ دشواری واقعی ندارد. خواندن و درک آن را به خواننده واگذار میکنیم.
1.4.3.4. تولید اسمبلی لایه [dao]
پروژه Visual Studio برای تولید اسمبلی [webarticles-dao.dll] پیکربندی شده است. این اسمبلی در پوشه [bin] پروژه تولید میشود:
![]() | ![]() |
1.4.3.5. تستهای NUnit برای لایه [dao]
در جاوا، کلاسها با استفاده از چارچوب [Junit] تست میشوند. در .NET، چارچوب Nunit همان قابلیتهای تست واحد را ارائه میدهد:

ساختار پروژه تست Visual Studio به شرح زیر است:

توضیحات:
- پروژه [tests] از نوع [bibliothèque de classes] است
- تستهای [NUnit] به یک مرجع به اسمبلی [nunit.framework.dll] نیاز دارند
- کلاس تست [NUnit] یک نمونه از شیء تحت تست را از طریق Spring بازیابی میکند. بنابراین،
- در پوشه [bin]، فایلهای کلاس Spring
- در [References]، مرجعی به اسمبلی [Spring-Core.dll] از پوشه [bin]
- در [bin]، یک فایل پیکربندی برای Spring
- کلاس تست به اسمبلی [webarticles-dao.dll] از لایه [dao] نیاز دارد. این اسمبلی در پوشه [bin] قرار داده شده و ارجاع آن به ارجاعات پروژه اضافه شده است.
کلاس تست [NUnit] نیازمند دسترسی به کلاسهای در فضای نام [NUnit.Framework] است. بنابراین شامل دستور import زیر است:
فضا نام [NUnit.Framework] در «اسمبلی» [nunit.framework.dll] قرار دارد که باید به مراجع پروژه اضافه شود:
![]() | ![]() |
اگر [Nunit] نصب شده باشد، assembly [nunit.framework.dll] باید در لیست ارائهشده ظاهر شود. برای افزودن آن به پروژه، کافی است روی assembly دوبار کلیک کنید:

کلاس تست [NUnit] برای لایه [dao] میتواند به صورت زیر باشد:
Imports System
Imports System.Collections
Imports NUnit.Framework
Imports istia.st.articles.dao
Imports System.Threading
Imports Spring.Objects.Factory.Xml
Imports System.IO
Namespace istia.st.articles.tests
<TestFixture()> _
Public Class NunitTestArticlesArrayList
' ابجکت مورد آزمایش
Private articlesDao As IArticlesDao
<SetUp()> _
Public Sub init()
' یک نمونه از سازندهٔ شیء Spring را بازیابی میکند
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config.xml", FileMode.Open))
' درخواست نمونهسازی شیء articlesdao
articlesDao = CType(factory.GetObject("articlesdao"), IArticlesDao)
End Sub
<Test()> _
Public Sub testGetAllArticles()
' بررسی بصری
listArticles()
End Sub
<Test()> _
Public Sub testClearAllArticles()
' حذف همه مقالات
articlesDao.clearAllArticles()
' بازیابی تمام مقالات
Dim articles As IList = articlesDao.getAllArticles
'بررسی: باید 0 باشد
Assert.AreEqual(0, articles.Count)
End Sub
<Test()> _
Public Sub testAjouteArticle()
' حذف همه آیتمها
articlesDao.clearAllArticles()
' بررسی: جدول آیتمها باید خالی باشد
Dim articles As IList = articlesDao.getAllArticles
Assert.AreEqual(0, articles.Count)
' افزودن دو آیتم
articlesDao.ajouteArticle(New Article(3, "article3", 30, 30, 3))
articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
'بررسی: باید دو آیتم وجود داشته باشد
articles = articlesDao.getAllArticles
Assert.AreEqual(2, articles.Count)
' بررسی بصری
listArticles()
End Sub
<Test()> _
Public Sub testSupprimeArticle()
' حذف همه آیتمها
articlesDao.clearAllArticles()
'بررسی: جدول آیتمها باید خالی باشد
Dim articles As IList = articlesDao.getAllArticles
Assert.AreEqual(0, articles.Count)
'دو آیتم اضافه میشوند
articlesDao.ajouteArticle(New Article(3, "article3", 30, 30, 3))
articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
'بررسی: باید ۲ آیتم وجود داشته باشد
articles = articlesDao.getAllArticles
Assert.AreEqual(2, articles.Count)
' آیتم ۴ حذف شد
articlesDao.supprimeArticle(4)
' بررسی: باید یک آیتم باقی بماند
articles = articlesDao.getAllArticles
Assert.AreEqual(1, articles.Count)
' بررسی بصری
listArticles()
End Sub
<Test()> _
Public Sub testModifieArticle()
' تمام موارد حذف شدند
articlesDao.clearAllArticles()
'بررسی
Dim articles As IList = articlesDao.getAllArticles
Assert.AreEqual(0, articles.Count)
' افزودن ۲ مورد
articlesDao.ajouteArticle(New Article(3, "article3", 30, 30, 3))
articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
'بررسی
articles = articlesDao.getAllArticles
Assert.AreEqual(2, articles.Count)
' جستجوی آیتم ۳
Dim unArticle As Article = articlesDao.getArticleById(3)
' تأیید
Assert.AreEqual(unArticle.nom, "article3")
' جستجو برای مورد ۴
unArticle = articlesDao.getArticleById(4)
' تأیید
Assert.AreEqual(unArticle.nom, "article4")
' اصلاحیه ماده ۴
articlesDao.modifieArticle(New Article(4, "article4", 44, 44, 44))
' تأیید
unArticle = articlesDao.getArticleById(4)
Assert.AreEqual(unArticle.prix, 44, 0.000001)
' بررسی بصری
listArticles()
End Sub
<Test()> _
Public Sub testGetArticleById()
' حذف اقلام
articlesDao.clearAllArticles()
' تأیید
Dim articles As IList = articlesDao.getAllArticles
Assert.AreEqual(0, articles.Count)
' افزودن ۲ مورد
articlesDao.ajouteArticle(New Article(3, "article3", 30, 30, 3))
articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
' تأیید
articles = articlesDao.getAllArticles
Assert.AreEqual(2, articles.Count)
' جستجوی آیتم ۳
Dim unArticle As Article = articlesDao.getArticleById(3)
' تأیید
Assert.AreEqual(unArticle.nom, "article3")
' جستجو برای آیتم ۴
unArticle = articlesDao.getArticleById(4)
' تأیید
Assert.AreEqual(unArticle.nom, "article4")
End Sub
'فهرست صفحهای
Private Sub listArticles()
Dim articles As IList = articlesDao.getAllArticles
For i As Integer = 0 To articles.Count - 1
Console.WriteLine(CType(articles(i), Article).ToString)
Next
End Sub
<Test()> _
Public Sub testArticleAbsent()
' حذف همه آیتمها
articlesDao.clearAllArticles()
' جستجوی آیتم ۱
Dim article As article = articlesDao.getArticleById(1)
' تأیید
Assert.IsNull(article)
' ویرایش یک آیتم موجود نیست
Dim i As Integer = articlesDao.modifieArticle(New article(1, "1", 1, 1, 1))
' هیچ ردیفی اصلاح نشد
Assert.AreEqual(i, 0)
' حذف یک آیتم موجود نیست
i = articlesDao.supprimeArticle(1)
' لازم نبود هیچ ردیفی را حذف کند
Assert.AreEqual(0, i)
End Sub
<Test()> _
Public Sub testChangerStockArticle()
' حذف تمام آیتمها
articlesDao.clearAllArticles()
' یک آیتم اضافه شده است
Dim nbArticles As Integer = articlesDao.ajouteArticle(New Article(3, "article3", 30, 101, 3))
Assert.AreEqual(nbArticles, 1)
' یک مقاله اضافه شد
nbArticles = articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
Assert.AreEqual(nbArticles, 1)
' ایجاد ۱۰۰ تاپیک
Dim taches(99) As Thread
For i As Integer = 0 To taches.Length - 1
' موضوع i را ایجاد میکند
taches(i) = New Thread(New ThreadStart(AddressOf décrémente))
' تنظیم نام تاپیک
taches(i).Name = "tache_" & i
' اجرای نخ i
taches(i).Start()
Next
' انتظار تا پایان همهٔ نخها
For i As Integer = 0 To taches.Length - 1
taches(i).Join()
Next
'بررسیها – آیتم ۳ باید سطح موجودی ۱ داشته باشد
Dim unArticle As Article = articlesDao.getArticleById(3)
Assert.AreEqual(unArticle.nom, "article3")
Assert.AreEqual(1, unArticle.stockactuel)
' کاهش موجودی برای آیتم ۴
Dim erreur As Boolean = False
Dim nbLignes As Integer = articlesDao.changerStockArticle(4, -100)
'بررسی: موجودی آن نباید تغییر کرده باشد
Assert.AreEqual(0, nbLignes)
' بازرسی چشمی
listArticles()
End Sub
Public Sub décrémente()
' رشته آغاز شد
System.Console.Out.WriteLine(Thread.CurrentThread.Name + " lancé")
' کاهش موجودی در رشته
articlesDao.changerStockArticle(3, -1)
' رشته کامل شد
System.Console.Out.WriteLine(Thread.CurrentThread.Name + " terminé")
End Sub
End Class
End Namespace
توضیحات:
- ما میخواستیم یک برنامهٔ تست برای رابط [IArticlesDao] بنویسیم که مستقل از کلاس پیادهسازی آن باشد. بنابراین از Spring استفاده کردیم تا نام کلاس پیادهسازی را از برنامهٔ تست پنهان کنیم.
- متد ویژگی <Setup()> یک مرجع به شی [articlesdao] که قرار است تست شود را از Spring بازیابی میکند. این در فایل زیر [spring-config.xml] تعریف شده است:
<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE objects PUBLIC "-//SPRING//DTD OBJECT//EN"
"http://www.springframework.net/dtd/spring-objects.dtd">
<objects>
<object id="articlesdao" type="istia.st.articles.dao.ArticlesDaoArrayList, webarticles-dao"/>
</objects>
این فایل نام کلاس پیادهسازی [istia.st.articles.dao.ArticlesDaoArrayList] را برای رابط [IArticlesDao] و محل یافتن آن را مشخص میکند: [ webarticles-dao.dll]. از آنجایی که نمونهسازی به هیچ پارامتری نیاز ندارد، هیچکدام در اینجا تعریف نشدهاند.
- اکثر تستها بهسادگی قابل درک هستند. خواننده تشویق میشود که نظرات را بخواند.
- متد [testChangerStockArticle] نیاز به توضیح دارد. این متد ۱۰۰ نخ ایجاد میکند که وظیفه کاهش موجودی یک کالا را بر عهده دارند.
<Test()> _
Public Sub testChangerStockArticle()
' حذف همه آیتمها
articlesDao.clearAllArticles()
' افزودن یک آیتم
Dim nbArticles As Integer = articlesDao.ajouteArticle(New Article(3, "article3", 30, 101, 3))
Assert.AreEqual(nbArticles, 1)
' افزودن یک آیتم
nbArticles = articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
Assert.AreEqual(nbArticles, 1)
' ایجاد ۱۰۰ نخ
Dim taches(99) As Thread
For i As Integer = 0 To taches.Length - 1
' ایجاد تاپیک i
taches(i) = New Thread(New ThreadStart(AddressOf décrémente))
' تنظیم نام نخ
taches(i).Name = "tache_" & i
' اجرای نخ i
taches(i).Start()
Next
' منتظر پایان همهٔ نخها بمان
For i As Integer = 0 To taches.Length - 1
taches(i).Join()
Next
'بررسیها – آیتم ۳ باید سطح موجودی ۱ داشته باشد
Dim unArticle As Article = articlesDao.getArticleById(3)
Assert.AreEqual(unArticle.nom, "article3")
Assert.AreEqual(1, unArticle.stockactuel)
' کاهش موجودی برای آیتم ۴
Dim erreur As Boolean = False
Dim nbLignes As Integer = articlesDao.changerStockArticle(4, -100)
'بررسی: موجودی آن نباید تغییر کرده باشد
Assert.AreEqual(0, nbLignes)
' بررسی بصری
listArticles()
End Sub
هدف در اینجا آزمایش دسترسی همزمان به منبع داده است. متد مسئول بهروزرسانی موجودی به شرح زیر است:
Public Sub décrémente()
' رشته راهاندازی شد
System.Console.Out.WriteLine(Thread.CurrentThread.Name + " lancé")
' کاهش موجودی در رشته
articlesDao.changerStockArticle(3, -1)
' رشته کامل شد
System.Console.Out.WriteLine(Thread.CurrentThread.Name + " terminé")
End Sub
مقدار موجودی کالا شمارهٔ ۳ را به اندازهٔ یک واحد کاهش میدهد. اگر به کد روش [testChangerStockArticle] مراجعه کنیم، میتوانیم ببینیم که:
- موجودی قلم شماره ۳ به مقدار اولیه ۱۰۱ مقداردهی شده است
- ۱۰۰ نخ هر کدام این موجودی را به اندازه یک واحد کاهش میدهند
- بنابراین، پس از اتمام اجرای تمام رشتهها، باید سطح موجودی برابر با ۱ باشد.
علاوه بر این، همچنان در همین متد، تلاشی برای منفی کردن موجودی کالا شماره ۴ انجام میشود. این کار باید ناموفق باشد.
برای آزمایش لایه [dao]، ما فایلهای DLL و [tests-webarticles-dao.dll] را در پوشه [bin] از پروژه [tests] ایجاد میکنیم:
![]() | ![]() |
سپس، با استفاده از برنامه [Nunit-Gui]، این DLL را بارگذاری کرده و تستها را اجرا میکنیم:

در پنجره سمت چپ، میتوانیم فهرست متدهای آزمایششده را مشاهده کنیم. رنگ نقطهای که قبل از نام هر متد قرار دارد، نشان میدهد که آیا متد با موفقیت (سبز) یا با شکست (قرمز) مواجه شده است. خوانندگانی که این سند را روی صفحه مشاهده میکنند، خواهند دید که همه تستها با موفقیت پشت سر گذاشته شدهاند. بنابراین فرض میکنیم که یک لایه [dao] عملیاتی در اختیار داریم.
1.4.4. لایه [domain]
لایه [domain] شامل عناصر زیر است:
-
[IArticlesDomain]: رابط دسترسی به لایه [domain]
-
[Achat]: کلاسی که یک خرید را تعریف میکند
-
[Panier]: کلاسی که یک سبد خرید را تعریف میکند
-
[AchatsArticles]: کلاسی که رابط [IArticlesDomain] را پیادهسازی میکند
ساختار راهحل [Visual Studio] در لایه [domain] به شرح زیر است:

توضیحات:
- پروژه [domain] از نوع [bibliothèque de classes] است
- کلاسها در یک ساختار درختی با پوشه [istia] بهعنوان ریشه قرار گرفتهاند. همگی در فضای نام [istia.st.articles.domain] هستند.
- رابط DLL از لایه [dao] در پوشه [bin] پروژه جدید قرار داده شده است. علاوه بر این، این DLL به عنوان یک مرجع به پروژه اضافه شده است.
1.4.4.1. رابط [IArticlesDomain]
رابط [IArticlesDomain] لایه [métier] را از لایه [web] مستقل میکند. این مورد دوم از طریق این رابط به لایه [métier/domain] دسترسی پیدا میکند، بدون اینکه نیازی باشد خود را درگیر کلاسی کند که در واقع آن را پیادهسازی میکند. این رابط عملیات زیر را برای دسترسی به لایه کسبوکار تعریف میکند:
Imports Article = istia.st.articles.dao.Article
Namespace istia.st.articles.domain
Public Interface IArticlesDomain
' روشها
Sub acheter(ByVal panier As Panier)
Function getAllArticles() As IList
Function getArticleById(ByVal idArticle As Integer) As Article
ReadOnly Property erreurs() As ArrayList
End Interface
End Namespace
فهرست اشیاء [Article] را از منبع دادهٔ مرتبط بازمیگرداند | |
شیء [Article] را که توسط [idArticle] شناسایی شده است بازمیگرداند | |
سبد خرید مشتری را با کاهش موجودی اقلام خریداریشده به میزان تعداد خریداریشده اعتبارسنجی میکند – در صورت ناکافی بودن موجودی ممکن است با شکست مواجه شود | |
فهرستی از هرگونه خطاهای رخداده را بازمیگرداند – در صورت عدم وجود خطا خالی است |
1.4.4.2. کلاس [Achat]
کلاس [Achat] یک خرید مشتری را نشان میدهد:
Imports istia.st.articles.dao
Namespace istia.st.articles.domain
Public Class Achat
' fields خصوصی
Private _article As article
Private _qte As Integer
' سازندهٔ پیشفرض
Public Sub New()
End Sub
' سازنده با پارامترها
Public Sub New(ByVal unArticle As article, ByVal qte As Integer)
' دسترسی از طریق ویژگیها
Me.article = unArticle
Me.qte = qte
End Sub
' مورد خریداریشده
Public Property article() As article
Get
Return _article
End Get
Set(ByVal Value As article)
_article = Value
End Set
End Property
' مقدار خریداریشده
Public Property qte() As Integer
Get
Return _qte
End Get
Set(ByVal Value As Integer)
If Value < 0 Then
Throw New Exception("Quantité [" + Value.ToString + "] invalide")
End If
_qte = Value
End Set
End Property
' مجموع خرید
Public ReadOnly Property totalAchat() As Double
Get
Return _qte * _article.prix
End Get
End Property
'شناسه
Public Overrides Function ToString() As String
Return "[" + _article.ToString + "," + _qte.ToString + "]"
End Function
End Class
End Namespace
نظرات:
- کلاس [Achat] دارای ویژگیها و متدهای زیر است:
مورد خریداریشده | |
مقدار خریداریشده | |
مبلغ خرید | |
رشته شناسه شیء |
- این کلاس دارای یک سازنده است که امکان مقداردهی اولیه ویژگیهای [article, qte] را که خرید را تعریف میکنند، فراهم میآورد.
1.4.4.3. کلاس [Panier]
کلاس [Panier] تمام خریدهای مشتری را نشان میدهد:
Namespace istia.st.articles.domain
Public Class Panier
' میدانهای خصوصی
Private _achats As New ArrayList
Private _totalPanier As Double = 0
' تولیدکننده پیشفرض
Public Sub New()
End Sub
' فهرست خرید
Public ReadOnly Property achats() As ArrayList
Get
Return _achats
End Get
End Property
' مجموع خریدها
Public ReadOnly Property totalPanier() As Double
Get
Return _totalPanier
End Get
End Property
' روشها
Public Sub ajouter(ByVal unAchat As Achat)
'بررسی میکند که آیا خرید قبلاً وجود دارد یا خیر
Dim iAchat As Integer = posAchat(unAchat.article.id)
If iAchat <> -1 Then
' یافت شد
Dim achatCourant As Achat = CType(_achats(iAchat), Achat)
achatCourant.qte += unAchat.qte
Else
' یافت نشد
_achats.Add(unAchat)
End If
' افزایش مجموع سبد خرید
_totalPanier += unAchat.totalAchat
End Sub
' حذف یک آیتم
Public Sub enlever(ByVal idAchat As Integer)
' جستجوی آیتم
Dim iachat As Integer = posAchat(idAchat)
' اگر یافت شد، حذف کن
If iachat <> -1 Then
Dim achatCourant As Achat = CType(_achats(iachat), Achat)
' حذف از سبد خرید
_achats.RemoveAt(iachat)
' کاهش مجموع سبد خرید
_totalPanier -= achatCourant.totalAchat
End If
End Sub
Private Function posAchat(ByVal idArticle As Integer) As Integer
' جستجوی خرید در فهرست خریدها
'موقعیت آن را در فهرست بازمیگرداند یا در صورت عدم یافتن، مقدار -1 را برمیگرداند
Dim achatCourant As Achat
Dim trouvé As Boolean = False
Dim i As Integer = 0
While Not trouvé AndAlso i < _achats.Count
' خرید فعلی
achatCourant = CType(_achats(i), Achat)
' مقایسه با مورد در حال جستجو
If achatCourant.article.id = idArticle Then
Return i
End If
'خرید بعدی
i += 1
End While
' یافت نشد
Return -1
End Function
' تابع هویت
Public Overrides Function ToString() As String
Return _achats.ToString
End Function
End Class
End Namespace
نظرات:
- کلاس [Panier] دارای خواص و متدهای زیر است:
فهرست خرید مشتری – فهرستی از اشیاء از نوع [Achat] | |
اضافه کردن یک خرید به فهرست خرید | |
حذف خرید آیتم idAchat | |
مجموع مبلغ اقلام در سبد خرید | |
ردیف شناسه سبد خرید را برمیگرداند |
- متد [posAchat] یک متد کمکی است که جایگاه یک خرید مشخصشده با شماره کالا را در لیست خریدها بازمیگرداند. فهرست خریدها به گونهای مدیریت میشود که یک کالا که چندین بار خریداری شده باشد، تنها یک جایگاه در فهرست را اشغال میکند. بنابراین، یک خرید را میتوان با شماره کالا شناسایی کرد. متد [posAchat] در صورتی که خرید مورد جستجو وجود نداشته باشد، مقدار -1 را برمیگرداند.
- روش [ajouter] یک خرید جدید را به فهرست خریدها اضافه میکند. این کار شامل افزودن یک رکورد جدید به فهرست خریدها در صورتی که کالای خریداریشده قبلاً در فهرست وجود نداشته باشد، یا افزایش مقدار خریداریشده در صورتی که قبلاً وجود داشته باشد، است.
- متد [enlever] امکان حذف یک خرید با شماره مشخص از فهرست خریدها را فراهم میکند. اگر خرید وجود نداشته باشد، این متد هیچ کاری انجام نمیدهد.
- مجموع مبلغ خریدها ([totalPanier]) همزمان با اضافه و حذف خریدها نگهداری میشود.
1.4.4.4. کلاس [AchatsArticles]
رابط [IArticlesDomain] توسط کلاس زیر [AchatsArticles] پیادهسازی خواهد شد:
Imports istia.st.articles.dao
Namespace istia.st.articles.domain
Public Class AchatsArticles
Implements IArticlesDomain
'فیلدهای خصوصی
Private _articlesDao As IArticlesDao
Private _erreurs As ArrayList
' سازنده
Public Sub New(ByVal articlesDao As IArticlesDao)
_articlesDao = articlesDao
End Sub
' فهرست خطاها
Public ReadOnly Property erreurs() As ArrayList Implements IArticlesDomain.erreurs
Get
Return _erreurs
End Get
End Property
' فهرست اقلام
Public Function getAllArticles() As IList Implements IArticlesDomain.getAllArticles
' فهرست تمام اقلام
Try
Return _articlesDao.getAllArticles
Catch ex As Exception
_erreurs = New ArrayList
_erreurs.Add("Erreur d'accès aux données : " + ex.Message)
End Try
End Function
'بازیابی یک آیتم با شمارهٔ آن
Public Function getArticleById(ByVal idArticle As Integer) As Article Implements IArticlesDomain.getArticleById
'یک آیتم مشخص
Try
Return _articlesDao.getArticleById(idArticle)
Catch ex As Exception
_erreurs = New ArrayList
_erreurs.Add("Erreur d'accès aux données : " + ex.Message)
End Try
End Function
'خرید یک سبد
Public Sub acheter(ByVal panier As Panier) Implements IArticlesDomain.acheter
'خرید یک سبد – سطح موجودی اقلام خریداریشده باید کاهش یابد
_erreurs = New ArrayList
Dim achat As achat
Dim achats As ArrayList = panier.achats
For i As Integer = achats.Count - 1 To 0 Step -1
'کاهش موجودی کالا i
achat = CType(achats(i), achat)
Try
If _articlesDao.changerStockArticle(achat.article.id, -achat.qte) = 0 Then
' عملیات با موفقیت انجام نشد
_erreurs.Add("L'achat " + achat.ToString + " n'a pu se faire - Vérifiez les stocks")
Else
' عملیات با موفقیت انجام شد – خرید از سبد خرید حذف شد
panier.enlever(achat.article.id)
End If
Catch ex As Exception
_erreurs = New ArrayList
_erreurs.Add("Erreur d'accès aux données : " + ex.Message)
End Try
Next
End Sub
End Class
End Namespace
توضیحات:
- این کلاس چهار متد رابط [IArticlesDomain] را پیادهسازی میکند. این کلاس دو فیلد خصوصی دارد:
شیء دسترسی به داده | |
فهرست هرگونه خطا. این از طریق ویژگی عمومی [erreurs] قابل دسترسی است. |
- برای ایجاد یک نمونه از کلاس، باید شیئی را که دسترسی به دادهها را ممکن میسازد، فراهم کنید:
- متدهای [getAllArticles] و [getArticleById] بر اساس متدهای همنام در لایه [dao] هستند
- متد [acheter] خرید یک سبد خرید را اعتبارسنجی میکند. این اعتبارسنجی صرفاً شامل کاهش موجودی اقلام خریداریشده است. یک کالا فقط در صورتی قابل خرید است که موجودی کافی داشته باشد. در غیر این صورت، خرید رد میشود: کالا در سبد باقی میماند و یک خطا در لیست [erreurs] گزارش میشود. یک خرید تأیید شده از سبد حذف شده و موجودی کالای مربوطه به میزان خرید کاهش مییابد.
1.4.4.5. تولید اسمبلی لایه [domain]
پروژه Visual Studio برای تولید اسمبلی [webarticles-domain.dll] پیکربندی شده است. این اسمبلی در پوشه [bin] پروژه تولید میشود:
![]() | ![]() |
1.4.4.6. NUnit تستهایی برای لایه [domain]
ساختار پروژه تست ویژوال استودیو به شرح زیر است:

توضیحات:
- پروژه [tests] از نوع [bibliothèque de classes] است
- تستهای [NUnit] به ارجاعی به اسمبلی [nunit.framework.dll] نیاز دارند
- کلاس تست [NUnit] یک نمونه از شیء تحت تست را از طریق Spring بازیابی میکند. بنابراین،
- در پوشه [bin]، فایلهای کلاس Spring
- در [References]، مرجعی به اسمبلی [Spring-Core.dll] از پوشه [bin]
- در [bin]، یک فایل پیکربندی برای Spring
- کلاس تست به اسمبلی [webarticles-dao.dll] از لایه [dao] و اسمبلی [webarticles-domain.dll] از لایه [domain] نیاز دارد. این فایلها در پوشه [bin] قرار داده شده و ارجاع آنها به پروژه اضافه شده است.
یک کلاس آزمایشی NUnit از لایه [domain] ممکن است به شکل زیر باشد:
Imports NUnit.Framework
Imports istia.st.articles.dao
Imports istia.st.articles.domain
Imports Spring.Objects.Factory.Xml
Imports System.IO
Namespace istia.st.articles.tests
<TestFixture()> _
Public Class NunitTestArticlesDomain
' ابجکت مورد آزمایش
Private articlesDomain As IArticlesDomain
Private articlesDao As IArticlesDao
<SetUp()> _
Public Sub init()
' بازیابی یک نمونه از کارخانه اشیاء Spring
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config.xml", FileMode.Open))
'درخواست نمونهسازی شیء DAO مقالات
articlesDao = CType(factory.GetObject("articlesdao"), IArticlesDao)
'سپس شیء 'articlesdomain'
articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDomain)
End Sub
<Test()> _
Public Sub getAllArticles()
' بررسی بصری
listArticles()
End Sub
<Test()> _
Public Sub getArticleById()
' حذف مقالات
articlesDao.clearAllArticles()
'بررسی
Dim articles As IList = articlesDomain.getAllArticles
Assert.AreEqual(0, articles.Count)
' افزودن ۲ آیتم
articlesDao.ajouteArticle(New Article(3, "article3", 30, 30, 3))
articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
' بررسی
articles = articlesDomain.getAllArticles
Assert.AreEqual(2, articles.Count)
' جستجوی آیتم ۳
Dim unArticle As Article = articlesDomain.getArticleById(3)
' تأیید
Assert.AreEqual(unArticle.nom, "article3")
' جستجو برای آیتم ۴
unArticle = articlesDao.getArticleById(4)
' تأیید
Assert.AreEqual(unArticle.nom, "article4")
End Sub
<Test()> _
Public Sub acheterPanier()
' حذف آیتم
articlesDao.clearAllArticles()
' تأیید
Dim articles As IList = articlesDomain.getAllArticles
Assert.AreEqual(0, articles.Count)
' افزودن ۲ آیتم
articlesDao.ajouteArticle(New Article(3, "article3", 30, 30, 3))
articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
'بررسی
articles = articlesDomain.getAllArticles
Assert.AreEqual(2, articles.Count)
' ایجاد یک سبد خرید با دو آیتم
Dim panier As New panier
panier.ajouter(New Achat(New Article(3, "article3", 30, 30, 3), 10))
panier.ajouter(New Achat(New Article(4, "article4", 40, 40, 4), 10))
' بررسیها
Assert.AreEqual(700, panier.totalPanier, 0.000001)
Assert.AreEqual(2, panier.achats.Count)
'تأیید سبد خرید
articlesDomain.acheter(panier)
' بررسیها
Assert.AreEqual(0, articlesDomain.erreurs.Count)
Assert.AreEqual(0, panier.achats.Count)
'جستجوی آیتم ۳
Dim unArticle As Article = articlesDomain.getArticleById(3)
'اعتبارسنجی
Assert.AreEqual(unArticle.stockactuel, 20)
'جستجوی آیتم ۴
unArticle = articlesDao.getArticleById(4)
'تأیید
Assert.AreEqual(unArticle.stockactuel, 30)
'سبد جدید
panier.ajouter(New Achat(New Article(3, "article3", 30, 30, 3), 100))
'تأیید سبد خرید
articlesDomain.acheter(panier)
' چکها
Assert.AreEqual(1, articlesDomain.erreurs.Count)
' جستجوی آیتم ۳
unArticle = articlesDomain.getArticleById(3)
' تأیید
Assert.AreEqual(unArticle.stockactuel, 20)
End Sub
<Test()> _
Public Sub testRetirerAchats()
'پاک کردن محتویات ARTICLES
articlesDao.clearAllArticles()
'جدول ARTICLES را میخواند
Dim articles As IList = articlesDao.getAllArticles()
Assert.AreEqual(0, articles.Count)
' وارد کردن
Dim article3 As New Article(3, "article3", 30, 30, 3)
articlesDao.ajouteArticle(article3)
Dim article4 As New Article(4, "article4", 40, 40, 4)
articlesDao.ajouteArticle(article4)
'جدول ARTICLES را میخواند
articles = articlesDomain.getAllArticles()
Assert.AreEqual(2, articles.Count)
'یک سبد خرید با دو آیتم ایجاد میکند
Dim monPanier As New Panier
monPanier.ajouter(New Achat(article3, 10))
monPanier.ajouter(New Achat(article4, 10))
'بررسی میکند
Assert.AreEqual(700.0, monPanier.totalPanier, 0.000001)
Assert.AreEqual(2, monPanier.achats.Count)
' افزودن یک آیتم که قبلاً خریداری شده است
monPanier.ajouter(New Achat(article3, 10))
'بررسی میکند
' مجموع باید روی ۱۰۰۰ تنظیم شود
Assert.AreEqual(1000.0, monPanier.totalPanier, 0.000001)
' هنوز ۲ قلم در سبد خرید وجود دارد
Assert.AreEqual(2, monPanier.achats.Count)
' مقدار آیتم ۳ باید به ۲۰ تغییر مییافت
Dim unAchat As Achat = CType(monPanier.achats(0), Achat)
Assert.AreEqual(20, unAchat.qte)
' مورد ۳ از سبد حذف شده است
monPanier.enlever(3)
' بررسیها
' مجموع باید به ۴۰۰ بهروزرسانی شده باشد
Assert.AreEqual(400.0, monPanier.totalPanier, 0.000001)
' فقط یک قلم در سبد
Assert.AreEqual(1, monPanier.achats.Count)
' این باید آیتم شماره ۴ باشد
Assert.AreEqual(4, CType(monPanier.achats(0), Achat).article.id)
End Sub
'فهرست صفحه
Private Sub listArticles()
Dim articles As IList = articlesDomain.getAllArticles
For i As Integer = 0 To articles.Count - 1
Console.WriteLine(CType(articles(i), Article).ToString)
Next
End Sub
End Class
End Namespace
توضیحات:
- ما میخواستیم یک برنامهٔ تست برای رابط [IArticlesDomain] بنویسیم که مستقل از کلاس پیادهسازی آن باشد. بنابراین از Spring استفاده کردیم تا نام کلاس پیادهسازی را از برنامهٔ تست پنهان کنیم.
- متد <Setup()> یک مرجع از Spring برای اشیاء [articlesdomain] و [articlesdao] که قرار است تست شوند، دریافت میکند. اینها در فایل زیر [spring-config.xml] تعریف شدهاند:
<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE objects PUBLIC "-//SPRING//DTD OBJECT//EN"
"http://www.springframework.net/dtd/spring-objects.dtd">
<objects>
<object id="articlesdao" type="istia.st.articles.dao.ArticlesDaoArrayList, webarticles-dao" />
<object id="articlesdomain" type="istia.st.articles.domain.AchatsArticles, webarticles-domain">
<constructor-arg index="0">
<ref object="articlesdao" />
</constructor-arg>
</object>
</objects>
این فایل بیان میکند:
- (ادامه)
- برای تکنسخه [articlesdao]، نام کلاس پیادهسازی [istia.st.articles.dao.ArticlesDaoArrayList] و محل یافتن آن: [ webarticles-dao.dll]. از آنجا که نمونهسازی به هیچ پارامتری نیاز ندارد، هیچکدام در اینجا تعریف نشدهاند.
- برای تکنسخه [articlesdomain]، نام کلاس پیادهسازی [istia.st.articles.domain.AchatsArticles] و محل یافتن آن: [ webarticles-domain.dll]. کلاس [AchatsArticles] دارای یک سازنده با یک پارامتر است: تکنفره (singleton) که دسترسی به لایه [dao] را مدیریت میکند. در اینجا، این به عنوان تکنفره (singleton) [articlesdao] که قبلاً تعریف شده است، مشخص شده است.
- کلاس تست یک نمونه از کلاس تحت تست، [articlesdomain]، و همچنین یک نمونه از کلاس دسترسی به دادهها، [articlesdao]، را به دست میآورد. این نکته آخر بحثبرانگیز است. از نظر تئوری، کلاس تست نباید به لایه [dao] دسترسی داشته باشد، لایهای که حتی قرار نیست از آن آگاه باشد. در اینجا، ما این «قاعده» را نادیده گرفتهایم که اگر به آن پایبند میبودیم، مجبور میشدیم متدهای جدیدی در رابط [IArticlesDomain] خود ایجاد کنیم.
برای تست لایه [domain]، ما DLL و [tests-webarticles-domain.dll] را در پوشه [bin] پروژه [tests] تولید میکنیم:
![]() | ![]() |
سپس، با استفاده از برنامه [Nunit-Gui]، این DLL را بارگذاری کرده و تستها را اجرا میکنیم:

خوانندگانی که این سند را روی صفحه نمایش مشاهده میکنند، خواهند دید که تمام تستها با موفقیت پشت سر گذاشته شدهاند. بنابراین، ما فرض میکنیم که اکنون یک لایه عملیاتی [domain] داریم.
1.4.5. نتیجهگیری
به عنوان یادآوری، ما میخواهیم اپلیکیشن وب سهلایه زیر را بسازیم:
![]() |
مدل M برنامه ما MVC اکنون نوشته و آزمایش شده است. این مدل در دو فایل در اختیار ما قرار گرفته است: DLL و [webarticles-dao.dll, webarticles-domain.dll]. اکنون میتوانیم به لایه نهایی، لایه [web]، که شامل کنترلکننده C و ویوهای V است، بپردازیم. ابتدا روشی را که در سند [Développement WEB avec ASP.NET 1.1 ] ارائه شده است، بررسی خواهیم کرد.
- کنترلکننده C توسط دو فایل پیادهسازی شده است، [global.asax, main.aspx]
- ویوهای V توسط صفحات aspx پیادهسازی شدهاند
1.5. لایه [web]
معماری MVC وباپلیکیشن به شرح زیر خواهد بود:
![]() |
کلاسهای کسبوکار [domain]، کلاسهای دسترسی به داده [dao] و منبع داده | |
صفحات ASPX | |
تمام درخواستهای کلاینت HTTP از طریق دو کنترلر زیر عبور میکنند: global.asax: رویدادهای مربوط به راهاندازی اولیهٔ برنامه را مدیریت میکند main.aspx: درخواست هر کلاینت را بهصورت جداگانه پردازش میکند |
1.5.1. دیدگاهها
دیدها همانهایی هستند که در ابتدای این سند ارائه شدهاند:
liste.aspx | نمایها در پوشه [vues] درون برنامه ذخیره میشوند ![]() | |
infos.aspx | ||
panier.aspx | ||
paniervide.aspx | ||
erreurs.aspx |
1.5.2. کنترلکنندهها
همانطور که گفته شد، کنترلر از دو مؤلفه تشکیل خواهد شد:
- [global.asax,global.asax.vb]: عمدتاً برای راهاندازی برنامه و پر کردن زمینهٔ آن با تمام دادههایی که باید بین کلاینتهای مختلف به اشتراک گذاشته شود، استفاده میشود
- [main.aspx, main.aspx.vb]: کنترلکننده واقعی که درخواستهای مشتری HTTP را پردازش میکند.
درخواستهای مختلف کلاینت به کنترلر [main.aspx] ارسال میشوند و شامل پارامتری به نام [action] هستند که اقدام مورد درخواست کلاینت را مشخص میکند:
درخواست | به معنای | عمل کنترلکننده | پاسخهای ممکن |
مشتری فهرستی از اقلام | - درخواست فهرست اقلام از ... کسبوکار | - [LISTE] - [ERREURS] | |
مشتری درخواست میکند اطلاعاتی درباره یکی از اقلام نمایشدادهشده در نما [LISTE] | - آیتم را از لایه کسبوکار درخواست میکند | - [INFOS] - [ERREURS] | |
مشتری یک کالا را خریداری میکند | - درخواست کالا از لایه کسبوکار و آن را به سبد خرید مشتری اضافه میکند | - [INFOS] در صورت وجود خطای مقدار - [LISTE] در صورت عدم وجود خطا | |
مشتری میخواهد یک را حذف کند خرید را از سبد خرید خود حذف کند | - سبد خرید را از جلسه بازیابی میکند و آن را اصلاح میکند | - [PANIER] - [PANIERVIDE] - [ERREURS] | |
مشتری میخواهد خود را مشاهده کند سبد خرید | - سبد خرید را از جلسه بازیابی میکند | - [PANIER] - [PANIERVIDE] - [ERREURS] | |
مشتری خرید خود را تکمیل کرده است و به مرحله پرداخت میرود | - سطوح موجودی را در پایگاه داده بهروز میکند از اقلام خریداریشده - سبد خرید مشتری را خالی میکند که خریدش تأیید شده است | - [LISTE] - [ERREURS] |
1.5.3. پیکربندی برنامه
ما تلاش خواهیم کرد تا برنامه را طوری پیکربندی کنیم که در برابر تغییراتی مانند موارد زیر تا حد امکان انعطافپذیر باشد:
- تغییرات در کلاسهای URL برای نماهای مختلف
- تغییرات در کلاسهای پیادهساز رابطهای [IArticlesDao] و [IArticlesDomain]
- تغییرات در SGBD، پایگاه داده و جدول محصول
1.5.3.1. تغییرات در URL
نامهای views URL در فایل پیکربندی برنامه [web.config] به همراه چند پارامتر دیگر قرار خواهند گرفت:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
..
<appSettings>
<add key="urlMain" value="/webarticles/main.aspx"/>
<add key="urlInfos" value="vues/infos.aspx"/>
<add key="urlErreurs" value="vues/erreurs.aspx"/>
<add key="urlListe" value="vues/liste.aspx"/>
<add key="urlPanier" value="vues/panier.aspx"/>
<add key="urlPanierVide" value="vues/paniervide.aspx"/>
</appSettings>
</configuration>
1.5.3.2. تغییر کلاسهای پیادهسازی برای رابطها
مطابق با اصول معماری سهسطحی، لایهها باید از یکدیگر پنهانسازی شوند. این پنهانسازی به شرح زیر انجام میشود:
- لایهها بهجای کلاسهای مشخص، از طریق رابطها با یکدیگر ارتباط برقرار میکنند
- کد در یک لایه هرگز خودِ کلاس لایه دیگر را برای استفاده از آن instantiate (نمونه سازی) نمیکند. این کد صرفاً یک نمونه از پیادهسازی رابط را از یک ابزار خارجی – در این مورد، Spring – برای لایهای که میخواهد استفاده کند، درخواست میکند. برای انجام این کار، میدانیم که نیازی نیست نام کلاس پیادهسازی را بشناسد، بلکه فقط نام singleton (تکنسخه) Spring را که میخواهد از آن مرجع بگیرد، میداند.
در برنامه کاربردی ما، Spring در فایل [web.config] برنامه کاربردی وب به شرح زیر پیکربندی خواهد شد:
<?xml version="1.0" encoding="iso-8859-1" ?>
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<context type="Spring.Context.Support.XmlApplicationContext, Spring.Core">
<resource uri="config://spring/objects" />
</context>
<objects>
<object id="articlesDao" type="istia.st.articles.dao.ArticlesDaoArrayList, webarticles-dao" />
<object id="articlesDomain" type="istia.st.articles.domain.AchatsArticles, webarticles-domain">
<constructor-arg index="0">
<ref object="articlesDao" />
</constructor-arg>
</object>
</objects>
</spring>
<appSettings>
<add key="urlMain" value="/webarticles/main.aspx"/>
<add key="urlInfos" value="vues/infos.aspx"/>
<add key="urlErreurs" value="vues/erreurs.aspx"/>
<add key="urlListe" value="vues/liste.aspx"/>
<add key="urlPanier" value="vues/panier.aspx"/>
<add key="urlPanierVide" value="vues/paniervide.aspx"/>
</appSettings>
</configuration>
برای دسترسی به لایه [métier]، یک کلاس در لایه [web] میتواند singleton [articlesDomain] را درخواست کند. سپس Spring یک شیء از نوع [istia.st.articles.domain.AchatsArticles] را instantiate میکند. برای این نمونهسازی، به یک شی از نوع [articlesDao] نیاز است، یعنی یک شی از نوع [istia.st.articles.dao.ArticlesDaoArrayList]. اسپرینگ سپس چنین ابجکت را ایجاد میکند. در پایان این عملیات، لایه [web] که singleton [articlesDomain] را درخواست کرده است، کل زنجیرهای را که آن را به منبع داده متصل میکند، در اختیار دارد:
![]() |
1.5.3.3. تغییراتی که مربوط به SGBD یا پایگاه داده هستند
این مورد در اینجا نادیده گرفته میشود زیرا ما در یک برنامه آزمایشی بدون SGBD کار میکنیم. ما در مرحله بعد به پیادهسازی یک لایه [dao] مبتنی بر SGBD خواهیم پرداخت.
1.5.4. کتابخانه تگ <asp:>
بیایید نمای [ERREURS] را در نظر بگیریم که فهرستی از خطاها را نمایش میدهد:

ویو [ERREURS] مسئول نمایش فهرستی از خطاها است که کنترلر [main.aspx] در زمینه درخواست تحت نام [context.Items("erreurs")] قرار داده است. راههای مختلفی برای نوشتن چنین صفحهای وجود دارد. در اینجا، ما تنها به بخش نمایش خطاها میپردازیم.
به یاد داشته باشید که یک صفحه ASPX دارای یک بخش ارائه (HTML) و یک بخش کد (NET) است که دادههای قابل نمایش توسط بخش ارائه را آماده میکند. این دو بخش ممکن است در یک فایل واحد، [aspx] (راه حل WebMatrix)، یا در دو فایل مجزا قرار گیرند: [aspx] برای بخش ارائه و [aspx.vb] برای کد. راه حل دوم، همان چیزی است که توسط ویژوال استودیو استفاده میشود. برای پیچیدهتر کردن موضوع، بخش ارائه HTML ممکن است حاوی کد .NET نیز باشد که از دیدگاه کاربر تمایز بین [contrôleur] و [présentation] را مبهم میکند. این رویکرد عموماً بهشدت توصیه نمیشود. حذف تمام کدها از بخش [présentation] مستلزم ایجاد کتابخانههای تگ بود. این کتابخانهها کد را پشت تگهایی که شبیه تگهای HTML هستند، پنهان میکنند. ما دو راهحل ممکن برای صفحه [ERREURS] ارائه میدهیم.
راه حل اول ما از کد .NET در بخش [présentation] صفحه استفاده میکند. صفحه ASPX لیست خطاهای موجود در درخواست را در بخش کنترلکننده [erreurs.aspx.vb] خود بازیابی میکند:
Protected erreurs As ArrayList
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
...
' بازیابی خطاها
erreurs = CType(context.Items("erreurs"), ArrayList)
End Sub
و سپس آن را در بخش [présentation, erreurs.aspx] نمایش میدهد:
<h2>Les erreurs suivantes se sont produites :</h2>
<ul>
<%
for i as integer=0 to erreurs.count-1
response.write("<li>" & erreurs(i).ToString & "</li>")
next
%>
</ul>
راه حل دوم از تگ <asp:repeater> در کتابخانه تگهای <asp:> در ASP.NET استفاده میکند. اگر یک صفحه ASPX را بهصورت گرافیکی بسازید، این تگ بهعنوان یک کامپوننت سرور در دسترس است که میتوانید آن را به فرم طراحی بکشید و رها کنید. اگر کد ASPX را بهصورت دستی بنویسید، میتوانید به آن بهعنوان یک کتابخانه تگ مراجعه کنید.
با کتابخانه تگ <asp:>، کد ASPX از نمای قبلی [ERREURS] به شکل زیر درمیآید:
<asp:Repeater id="rptErreurs" runat="server">
<HeaderTemplate>
<h3>Les erreurs suivantes se sont produites :
</h3>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<%# Container.DataItem %>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
برچسب
برای تکرار یک الگو HTML در عناصر مختلف یک منبع داده استفاده میشود. عناصر مختلف آن به شرح زیر است:
الگوی HTML که قبل از نمایش عناصر منبع داده نمایش داده میشود | |
الگوی HTML که باید برای هر عنصر منبع داده تکرار شود. عبارت [<%# Container.DataItem %>] برای نمایش مقدار عنصر فعلی منبع داده استفاده میشود. | |
الگوی HTML که پس از نمایش عناصر منبع داده نمایش داده میشود |
منبع داده به تگ متصل میشود، معمولاً در بخش [contrôleur] صفحه:
Protected WithEvents rptErreurs As System.Web.UI.WebControls.Repeater
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
..
'خطاهای پیوند به rptErreurs
With rptErreurs
.DataSource = context.Items("erreurs")
.DataBind()
End With
End Sub
این ارتباط همچنین میتواند در حین طراحی صفحه برقرار شود اگر منبع داده از قبل مشخص باشد، مانند یک پایگاه داده موجود.
در ویوهای ما، از تگ دیگری استفاده خواهیم کرد: <asp:datagrid>، که امکان نمایش یک منبع داده به شکل جدول را فراهم میکند.
1.5.5. ساختار راهحل Visual Studio برای برنامه [webarticles]
یک برنامه وب مانند یک پازل با قطعات بسیار است. پیادهسازی معماری MVC معمولاً تعداد این قطعات را افزایش میدهد. ساختار برنامه [webarticles] تحت [Visual Studio] به شرح زیر است:
![]() | ![]() | ![]() |
![]() |
توضیحات:
- پروژه [web] از نوع [bibliothèque de classes] است و نه از نوع [Application web ASP.NET]، همانطور که ممکن است بهطور منطقی انتظار رود. نوع [Application web ASP.NET] نیازمند وجود وبسرور IIS بر روی ماشین توسعه یا یک ماشین راه دور است. سرور IIS بهطور پیشفرض روی سیستمهای Windows XP Home Edition نصب نشده است. با این حال، بسیاری از سیستمهای PC با این نسخه عرضه میشوند. برای اینکه خوانندگانی که از ویندوز XP استفاده میکنند بتوانند اپلیکیشن مورد بررسی را پیادهسازی کنند، ما از سرور وب Cassini (به ضمیمه مراجعه کنید) که بهصورت رایگان از مایکروسافت در دسترس است، استفاده خواهیم کرد و پروژه [Application web ASP.NET] را با یک پروژه [bibliothèque de classes] جایگزین خواهیم کرد. این امر چند عیب دارد که در ضمیمهها توضیح داده شدهاند.
- فایلهای DLL مورد استفاده توسط برنامه به شرح زیر هستند:
حاوی کلاسهای لایه دسترسی به دادهها است | |
حاوی کلاسهای لایه کسبوکار است | |
حاوی کلاسهای Spring است که به ما امکان میدهد لایههای وب، دامنه و DAO را یکپارچه کنیم | |
کلاسهای لاگگیری – مورد استفاده Spring |
این فایلهای DLL در پوشه [bin] قرار داده شده و به وابستگیهای پروژه اضافه میشوند.
1.5.6. ویوهای ASPX
همانطور که قبلاً توصیه شد، ما در ویوهای ASPX خود از کتابخانه تگ <asp:> استفاده خواهیم کرد.
1.5.6.1. کامپوننت کاربری [entete.ascx]
برای تضمین یکپارچگی در نماهای مختلف، آنها از یک هدر یکسان استفاده میکنند که نام برنامه را در کنار منو نمایش میدهد:
![]() | ![]() |
منو پویا است و توسط کنترلر تعیین میشود. کنترلر در درخواست ارسالشده به صفحه ASPX یک ویژگی کلید به نام «actions» را قرار میدهد که مقدار آن آرایهای از عناصر از نوع Hashtable() است. هر عنصر این آرایه یک دیکشنری است که برای تولید یک گزینه در منوی سربرگ در نظر گرفته شده است. هر دیکشنری دو کلید دارد:
- href: URL مرتبط با گزینه منو
- لینک: متن منو
ما هدر را به یک کنترل کاربری تبدیل خواهیم کرد. یک کنترل کاربری بخشی از یک صفحه (قالببندی و کدهای مرتبط) را در قالبی (component) جای میدهد که سپس میتوان آن را در صفحات دیگر مجدداً استفاده کرد. در اینجا، ما میخواهیم کامپوننت [entete] را در نماهای دیگر برنامه مجدداً استفاده کنیم. کد نمایش در [entete.ascx] و کد کنترل مربوطه در [entete.ascx.vb] قرار خواهد داشت. کد نمایش از یک کامپوننت <asp:repeater> برای نمایش جدول گزینههای منو استفاده خواهد کرد:
![]() |
n° | type | nom | rôle |
۱ | تکرارکننده | rptMenu منبع داده: آرایهای از فرهنگلغتها با دو کلید: href، link | نمایش گزینههای منو |
کد نمایش صفحه به شرح زیر خواهد بود:
نظرات:
- کامپوننت [repeater] در خطوط ۶ تا ۱۴ تعریف شده است
- هر عنصر در منبع داده مرتبط با تکرارگر یک دیکشنری با دو کلید است: href – خط ۹ و link – خط ۱۰
کد کنترل مربوطه به شرح زیر خواهد بود:
توضیحات:
- کامپوننت از نوع [EnteteWebArticles] دارای یک خاصیت عمومی فقط-نوشتن به نام [actions] است – خط ۷
- این خاصیت اجازه میدهد آرایه گزینههایی که توسط کنترلکننده برنامه – خطوط ۱۱–۱۲ – محاسبه شده است، با کامپوننت <asp:repeater> با نام [rptMenu] – خط ۱۰ – مرتبط شود.
سایر نماها در برنامه از هدر تعریفشده توسط [entete.ascx] استفاده خواهند کرد. برای مثال، صفحه [erreurs.aspx] هدر را با استفاده از کد زیر درج خواهد کرد:
توضیحات:
- خط ۱ مشخص میکند که تگ <WA:entete> باید با کامپوننتی که توسط فایل [entete.ascx] تعریف شده است، مرتبط باشد. ویژگیهای [TagPrefix] و [TagName] را میتوان در صورت نیاز تنظیم کرد.
- پس از انجام این کار، این کامپوننت از طریق خط ۹ در کد ارائه صفحه درج میشود. در زمان اجرا، این تگ باعث میشود کد صفحه ASPX که حاوی آن است، کد صفحه [entete.ascx] را شامل شود. کد کنترلی [erreurs.aspx.vb] این کامپوننت را راهاندازی میکند. این کار را به شرح زیر انجام میدهد:
توضیحات:
- خط ۶ یک شیء از نوع [EnteteWebArticles] ایجاد میکند که نوع کامپوننت ایجادشده است
- خط ۱۱ خاصیت [actions] این شیء را مقداردهی اولیه میکند
1.5.6.2. نما [liste.aspx]
1.5.6.2.1. Introduction
این نما لیست اقلام موجود برای فروش را نمایش میدهد:
![]() | ![]() |
این نما پس از درخواست /main?action=list یا /main?action=cartvalidation نمایش داده میشود. پارامترهای درخواست کنترلر به شرح زیر است:
شیء Hashtable() – آرایهٔ گزینههای منو | |
ابجکتهای نوع [Article] | |
شیء رشتهای – پیامی که در پایین صفحه نمایش داده میشود |
هر لینک [Infos] در جدول HTML مقالات دارای یک URL از شکل [?action=infos&id=ID] است، که در آن ID فیلد id از ...مقالهای که در حال نمایش است.
1.5.6.2.2. اجزای صفحه
![]() |
n° | type | nom | rôle |
کامپوننت کاربر | سربرگ | سربرگ نمایش | |
DataGrid | DataGridArticles 3 – ستون مرتبط: سربرگ: نام، فیلد: name 4 – ستون مرتبط: سربرگ: قیمت، فیلد: قیمت ۵ - ستون هایپرمتن: متن: Info، فیلد URL: id, قالب URL: /webarticles/main.aspx?action=infos&id={0} | نمایش اقلام برای فروش | |
برچسب | lblMessage | نمایش یک پیام |
بیایید مرور کنیم که چگونه این ویژگیها را تنظیم کنیم:
- در ویژوال استودیو، [DataGrid] را برای دسترسی به برگهٔ ویژگیهای آن انتخاب کنید:

- برای مدیریت چیدمان جدول نمایشدادهشده، از لینک [Mise en forme automatique] بالا استفاده کنید
- و لینک [Générateur de propriétés] برای مدیریت محتوای آن
1.5.6.2.3. کد ارائه [liste.aspx]
نظرات:
- خط ۹ هدر صفحه را تعریف میکند
- خطوط ۱۲ تا ۲۴ ویژگیهای [DataGrid] را تعریف میکنند
- خط ۲۶ برچسب [lblMessage] را تعریف میکند
1.5.6.2.4. کد کنترلکننده [liste.aspx.vb]
توضیحات:
- اجزای صفحه در خطوط ۱۳–۱۵ ظاهر میشوند. توجه داشته باشید که ما نیاز داشتیم یک شیء [EnteteWebArticles] را با یک اپراتور [new] ایجاد کنیم، در حالی که این کار برای سایر اجزا ضروری نبود. بدون این ایجاد صریح، با خطای زمان اجرا مواجه شدیم که اعلام میکرد شیء [entete] به هیچچیز ارجاع نمیدهد. این نکته ارزش بررسی بیشتر را داشت. به آن رسیدگی نشد.
- جدول گزینههای منوی بالا (header menu) برای راهاندازی کامپوننت [entete] صفحه از زمینه گرفته میشود – خط ۲۰
- فهرست آیتمها از زمینه گرفته میشود – خط ۲۲
- برای راهاندازی کامپوننت [DataGridArticles] – خطوط 24–27
- کامپوننت [lblMessage] با پیامی که در زمینه قرار داده شده است، مقداردهی اولیه میشود – خط ۲۹
1.5.6.3. نما [infos.aspx]
1.5.6.3.1. Introduction
این نما اطلاعاتی درباره یک آیتم نمایش میدهد و همچنین امکان خرید آن را فراهم میکند:

این صفحه پس از درخواست به /main?action=infos&id=ID یا درخواست به /main?action=achat&id=ID زمانی که مقدار خریداریشده نادرست باشد، نمایش داده میشود. اجزای درخواست کنترلر به شرح زیر است:
شیء Hashtable() – آرایه گزینههای منو | |
شیء از نوع [Article] – موردی که باید نمایش داده شود | |
ابژه رشتهای – پیامی برای نمایش در صورت خطای مقدار | |
ابژه رشتهای – مقداری که باید در فیلد ورودی [Qte] نمایش داده شود |
fields [msg] و [qte] در صورت بروز خطای ورودی در مورد مقدار استفاده میشوند:

این صفحه حاوی فرمى است که از طریق دکمه [Acheter] ارسال مىشود. هدف URL برای POST، [?action=achat&id=ID] است، که در آن ID شناسه کالای خریداریشده است.
1.5.6.3.2. اجزای صفحه
![]() |
n° | type | nom | rôle |
کامپوننت کاربر | سربرگ | سربرگ نمایش | |
متنی | litID | نمایش شماره آیتم | |
DataGrid | DataGridArticle 3 – ستون مرتبط: سربرگ: Name، فیلد: name 4 – ستون مرتبط: سربرگ: قیمت، فیلد: price ۵ - ستون مرتبط: سربرگ: موجودی فعلی، فیلد: stockActuel ۶ - ستون مرتبط: سربرگ: حداقل موجودی، فیلد: stockMinimum | نمایش یک آیتم | |
HTML ارسال | ارسال فرم | ||
HTML ورودی runat=server | txtQte | مقدار خریداریشده را وارد کنید | |
برچسب | lblMsgQte | هر پیام خطا |
1.5.6.3.3. کد نمایش [infos.aspx]
توضیحات:
- سربرگ در صفحه گنجانده شده است – خط ۹
- متن [litId] در خط ۱۰ تعریف شده است
- DataGrid و [DataGridArticles] در خطوط ۱۲–۳۴ تعریف شدهاند
- فرم در خطوط ۳۶–۴۶ تعریف شده است. نوع آن POST است.
- هدف برای POST توسط متغیر [strAction] – خط ۳۶ – فراهم میشود. این متغیر باید توسط کنترلر تعریف شود.
- میدان ورودی برای مقدار خریداریشده در خط ۴۱ تعریف شده است. این یک کامپوننت سمت سرور (runat=server) از نوع HTML است. در کد، به آن از طریق یک شی دسترسی پیدا میشود.
- خط ۴۲ برچسب [lblMsgQte] را تعریف میکند که حاوی هرگونه پیام خطا مربوط به مقدار وارد شده خواهد بود
1.5.6.3.4. کد کنترل [infos.aspx.vb]
توضیحات:
- اجزای صفحه در خطوط ۱۰–۱۴ تعریف شدهاند
- کلاس یک ویژگی عمومی [strAction] را تعریف میکند که برای تعیین هدف فرم POST استفاده میشود – خطوط 17–25
- مقالهای که باید نمایش داده شود از زمینهٔ برنامه بازیابی میشود – خط ۳۰
- جدول گزینهها برای منوی سربرگ از زمینه گرفته میشود تا کامپوننت [entete] صفحه را راهاندازی کند – خط ۳۲
- خطوط ۳۳–۳۹: کامپوننت [DataGridArticle] به یک منبع داده از نوع [ArrayList] متصل میشود که تنها شامل آیتمی است که در خط ۳۰ بازیابی شده است
- کامپوننتهای [lblMsgQte, txtQte] با اطلاعاتی که از زمینه گرفته شده، مقداردهی اولیه میشوند – خطوط 42–45
- ویژگی [straction] نیز با اطلاعاتی که از زمینه گرفته شده است مقداردهی اولیه میشود – خط ۴۷. این متغیر برای تولید صفت [action] از نوع HTML که در صفحه وجود دارد، استفاده میشود:
1.5.6.4. نما [panier.aspx]
1.5.6.4.1. Introduction
این نما محتویات سبد را نمایش میدهد:

این صفحه پس از درخواست به /main?action=basket یا /main?action=cancelpurchase&id=ID نمایش داده میشود. پارامترهای درخواست کنترلر به شرح زیر است:
شیء Hashtable() – آرایهٔ گزینههای منو | |
شیء از نوع [Panier] – سبد خریدی که باید نمایش داده شود |
هر لینک [Retirer] در آرایه HTML اقلام سبد خرید دارای یک URL به شکل [?action=retirerachat&id=ID] است، که در آن ID نشاندهنده QZX است.میدان W2HTMLP000461ZQX مربوط به کالایی که باید از سبد خرید حذف شود.
1.5.6.4.2. اجزای صفحه
![]() |
n° | type | nom | rôle |
کامپوننت کاربر | سربرگ | سربرگ نمایش | |
DataGrid | DataGridAchats 3 – ستون مرتبط – سربرگ: Item، فیلد: name 4 – ستون مرتبط – سربرگ: Qty، فیلد: qty ۵ – ستون مرتبط – سربرگ: قیمت، فیلد: price 6 – ستون مرتبط – سربرگ: Total، فیلد: total، قالببندی {0:C} 7 – ستون هایپرمتن – متن: حذف، URL: id، قالب URL: /webarticles/main.aspx?action=retirerachat&id={0} | نمایش لیست اقلام خریداری شده | |
برچسب | lblTotal | نمایش مبلغ قابل پرداخت |
1.5.6.4.3. کد نمایش [panier.aspx]
توضیحات
- خط ۹ شامل سربرگ است
- خطوط ۱۲–۲۷: کامپوننت [DataGridAchats] تعریف شده است
- خط ۲۹: کامپوننت [lblTotal] تعریف شده است
1.5.6.4.4. کد کنترل [panier.aspx.vb]
توضیحات:
- اجزای صفحه در خطوط 11–13 اعلام شدهاند
- ابتداییسازی کامپوننت [entete] با آنچه در صفحات قبلاً بررسیشده یافت میشود یکسان است – خط 17
- سبد خریدی که باید نمایش داده شود از جلسه بازیابی میشود – خط ۱۹
- نمایش این سبد خرید با استفاده از کامپوننت [DataGridAchats] مشکلاتی را به همراه دارد. مشکل از نحوهٔ инициализация این کامپوننت ناشی میشود. بیایید ستونهای آن را مرور کنیم:
- ستون [Article] مرتبط با فیلد [nom] در منبع داده
- ستون [Qté] مرتبط با فیلد [qte] در منبع داده
- ستون [Prix] مرتبط با فیلد [prix] در منبع داده
- ستون [Total] مرتبط با فیلد [total] در منبع داده
منبع دادهای که در اختیار داریم سبد خرید و فهرست خرید آن است. مورد دوم منبع داده برای [DataGrid] خواهد بود. تنها اشیاء [Achat] که سطرهای [DataGrid] را پر میکنند، دارای ویژگیهای [nom, qte, prix, total] مورد انتظار [DataGrid] نیستند. بنابراین، یک منبع داده بهطور خاص برای [DataGrid] ایجاد میشود که عناصر آن دارای ویژگیهای مورد انتظار [DataGrid] هستند. این عناصر از نوع [LigneAchat] خواهند بود، کلاسی که برای این منظور ایجاد شده و از کلاس [Achat] مشتق شده است – خطوط ۳۶–۶۶
- پس از تعریف کلاس [LigneAchat]، منبع داده برای [DataGridAchats] از سبد موجود در جلسه ساخته میشود – خطوط ۲۰–۳۰
- مبلغ کل خرید با استفاده از خاصیت [totalPanier] از کلاس [Panier] نمایش داده میشود – خط ۳۲
1.5.6.5. نما [paniervide.aspx]
1.5.6.5.1. Introduction
این نما اطلاعاتی را نمایش میدهد که نشان میدهد سبد خرید خالی است:

این صفحه پس از درخواست /main?action=basket یا /main?action=checkout&id=ID نمایش داده میشود. پارامترهای درخواست کنترلر به شرح زیر است:
شیء Hashtable() – آرایه گزینههای منو |
1.5.6.5.2. اجزای صفحه
![]() |
n° | type | nom | rôle |
کامپوننت کاربر | سربرگ | سربرگ نمایش |
1.5.6.5.3. کد ارائه [paniervide.aspx]
نظرات:
- سربرگ در خط ۹ درج شده است
1.5.6.5.4. کد کنترلی [paniervide.aspx.vb]
توضیحات:
- ما به سادگی تنها مؤلفهٔ پویا صفحه را مقداردهی اولیه میکنیم – خط ۱۰
1.5.6.6. نما [erreurs.aspx]
1.5.6.6.1. Introduction
این صفحه در صورت بروز خطاها نمایش داده میشود:

این صفحه پس از هر درخواستی که منجر به خطا شود نمایش داده میشود، به جز اقدام خرید با مقدار نادرست که توسط نما [INFOS] پردازش میشود. عناصر درخواست کنترلکننده به شرح زیر است:
شیء Hashtable() – آرایه گزینههای منو | |
ابجکتهای ArrayList، که هر کدام حاوی ابجکتهای [String] هستند که نمایانگر پیامهای خطایی هستند که باید نمایش داده شوند |
1.5.6.6.2. اجزای صفحه
![]() |
n° | type | nom | rôle |
کامپوننت کاربر | سربرگ | سربرگ نمایش | |
تکرارکننده | rptErreurs | نمایش فهرست خطاها |
1.5.6.6.3. کد نمایش [erreurs.aspx]
توضیحات:
- سربرگ در خط ۹ تعریف شده است
- کامپوننت [rptErreurs] در خطوط ۱۳ تا ۱۹ تعریف شده است. محتوای آن از یک منبع داده از نوع [ArrayList] میآید که شامل اشیایی از نوع [String] است.
1.5.6.6.4. کد کنترل [erreurs.aspx.vb]
توضیحات:
- کامپوننت [entete] طبق معمول مقداردهی اولیه میشود، خطوط ۹ و ۱۴
- کامپوننت [rptErreurs] با فهرست خطاهای نوع [ArrayList] یافتشده در زمینه – خطوط 16–19 – مقداردهی اولیه میشود
1.5.7. کنترلکنندههای global.asax و main.aspx
تنها کاری که باقی مانده نوشتن هستهٔ برنامهٔ وب ما است: کنترلر. نقش آن این است که:
- استخراج درخواست مشتری،
- پردازش اقدام درخواستی مشتری با استفاده از کلاسهای کسبوکار،
- بازگرداندن نمای مناسب.
1.5.7.1. کنترلکننده [global.asax.vb]
وقتی برنامه اولین درخواست خود را دریافت میکند، رویه [Application_Start] در فایل [global.asax.vb] اجرا میشود. این تنها یک بار اتفاق میافتد. هدف رویه [Application_Start]، راهاندازی اشیاء مورد نیاز وباپلیکیشن است که بهصورت فقط خواندنی توسط تمام نخهای کلاینت مشترک خواهند بود. این اشیاء مشترک را میتوان در دو مکان قرار داد:
- متغیرهای خصوصی کنترلر
- زمینهٔ اجرای برنامه (Application)
متد [Application_Start] از برنامه [global.asax.vb] اقدامات زیر را انجام خواهد داد:
- فایل [web.config] را برای پارامترهای مورد نیاز برای عملکرد صحیح برنامه بررسی میکند. این موارد در بخش 1.5.3 توضیح داده شدهاند.
- هر فهرست خطا را در قالب یک شیء [ArrayList erreurs] در زمینهٔ برنامه قرار میدهد. این فهرست در صورت عدم وجود خطا خالی خواهد بود، اما با این وجود وجود خواهد داشت.
- اگر خطایی رخ داده باشد، متد [Application_Start] در این نقطه متوقف میشود. در غیر این صورت، یک مرجع به یک شیء تکنسل (singleton) از نوع [IArticlesDomain] را درخواست میکند، که این شیء، شیء کسبوکاری است که کنترلکننده برای مقاصد خود از آن استفاده خواهد کرد. همانطور که در بخش 1.5.3.2 توضیح داده شد، کنترلر این اشیای تکنفره را از فریمورک Spring درخواست خواهد کرد. این فرآیند نمونهسازی ممکن است به خطاهای مختلفی منجر شود. در این صورت، این خطاها مجدداً در شی [erreurs] در زمینه برنامه ذخیره خواهند شد.
کنترلکننده [global.asax.vb] روندی به نام [Session_Start] دارد که هر بار یک مشتری جدید وارد میشود، اجرا میگردد. در این روند، یک سبد خرید خالی برای مشتری ایجاد میشود. این سبد در تمام درخواستهای آن مشتری خاص حفظ میشود. کد ممکن است به این شکل باشد:
توضیحات:
- پارامترهای مورد انتظار در [web.config] در یک آرایه تعریف شدهاند – خط ۱۸
- در [web.config] بررسی میشوند. اگر موجود باشند، در زمینهٔ برنامه ذخیره میشوند؛ در غیر این صورت، یک خطا در لیست خطاهای [erreurs] ثبت میشود – خطوط 21–33
- اگر خطایی وجود نداشته باشد، از Spring درخواست میشود تا مرجعی به singleton [articlesDomain] که مدیریت دسترسی به لایه [domain] برنامه را بر عهده دارد، ارائه دهد – خطوط 35–47. هرگونه خطا در [erreurs] ثبت میشود.
- خطاها در زمینهٔ برنامه ثبت میشوند – خط ۴۹
- در صورت وقوع هرگونه خطا، رویه متوقف میشود – خط ۵۱
- یک آرایه از سه دیکشنری ایجاد میشود. هر یک دو کلید دارد: href و link. این آرایه نمایانگر سه گزینهٔ ممکن منو است – خطوط 52–71
- این آرایه در زمینهٔ برنامه ذخیره میشود – خط ۷۳
- برای هر مشتری جدید، رویه [Session_Start] اجرا میشود. یک سبد خرید خالی در جلسه مشتری ایجاد میشود – خطوط 78–81
1.5.7.2. کنترلکننده [main.aspx.vb]
کنترلکننده [main.aspx.vb] تمام درخواستهای مشتری را مدیریت میکند. این به این دلیل است که همه آنها به شکل [/webarticles/main.aspx?action=XX] هستند. یک درخواست به شرح زیر پردازش میشود:
- شیء [erreurs] در زمینهٔ برنامه بررسی میشود. اگر خالی نباشد، این بدان معناست که در حین راهاندازی برنامه خطاهایی رخ داده و برنامه نمیتواند اجرا شود. در پاسخ، نما [ERREURS] ارسال میشود.
- پارامتر [action] در درخواست بازیابی و بررسی میشود. اگر با هیچ اقدام شناختهشدهای مطابقت نداشته باشد، نمای [ERREURS] همراه با یک پیام خطای مناسب ارسال میشود.
- اگر پارامتر [action] معتبر باشد، درخواست کلاینت برای پردازش به یک رویه مخصوص آن اقدام ارسال میشود:
روش | درخواست | پردازش | پاسخهای ممکن |
GET /main?action=list | - درخواست فهرست اقلام از کلاس تجاری - نمایش آن | [LISTE] یا [ERREURS] | |
GET /main?action=infos&id=ID | - مقاله با شناسه ID را از کلاس بیزینس - نمایش آن | [INFOS] یا [ERREURS] | |
POST /main?action=purchase&id=ID - مقدار خریداریشده در پارامترهای ارسالشده گنجانده شده است | - آیتم با شناسه ID را از کلاس تجاری - آن را در سبد خرید در سشن مشتری | [LISTE] یا [INFOS] یا [ERREURS] | |
GET /main?action=return&id=ID | - حذف آیتم با شناسه=ID از فهرست خرید در سشن مشتری | [PANIER] | |
GET /main?action=basket | - نمایش جلسه مشتری | [PANIER] یا [PANIERVIDE] | |
GET /main?action=validate-basket | - کاهش سطح موجودی تمام اقلام در مشتری سشن مشتری | [LISTE] یا [ERREURS] |
قالب کنترلر برای [main.aspx.vb] میتواند به شرح زیر باشد:
توضیحات:
- کلاس دارای دو فیلد خصوصی است که بین متدها مشترک خواهد بود – خطوط ۱۵–۱۶:
- articlesDomain: کلاس تکنمونه (singleton) که دسترسی به لایه [domain] را فراهم میکند
- options: آرایهٔ دیکشنریها که حاوی گزینههای منو است
- روند [Page_Load]:
- دو فیلد خصوصی کلاس را مقداردهی اولیه میکند
- پارامتر [action] را از درخواست بازیابی کرده و متدی را که این عمل را مدیریت میکند، اجرا میکند.
1.5.7.3. متد [Page_Load]
این اولین رویدادی است که در صفحه رخ میدهد. کد به شرح زیر است:
توضیحات:
- هر بار که صفحه بارگذاری میشود، ما اطمینان حاصل میکنیم که inicialization برنامه که توسط [global.asax] انجام شده، با موفقیت به پایان رسیده است.
- برای این کار، فهرست خطاهایی را که توسط [global.asax] در زمینهٔ برنامه قرار داده شده است، بازیابی میکنیم – خط ۴
- اگر این لیست خالی نبود، نمای [ERREURS] را نمایش میدهیم – خطوط ۶–۱۰
- ما singleton [articlesDomain] را که توسط [global.asax] در زمینهٔ برنامه قرار داده شده است، بازیابی کرده و در فیلد خصوصی [articlesDomain] ذخیره میکنیم تا برای متدهای مختلف کلاس در دسترس باشد – خط ۱۲
- ما یک فرآیند مشابه را با آرایه گزینههای منو انجام میدهیم – خط 14
- پارامتر [action] از درخواست بازیابی میشود – خط 16
- ما متد متناظر با اقدام درخواستی را اجرا میکنیم. یک اقدام غیرمنتظره بهعنوان اقدام [liste] در نظر گرفته میشود – خطوط 16–36
1.5.7.4. پردازش اقدام [liste]
این شامل نمایش لیست اقلام است:

کد به شرح زیر است:
توضیحات:
- هرگونه خطا در [ArrayList] – خط ۴ ثبت میشود
- فهرست آیتمها از singleton [articlesDomain] – خطوط 5–12 درخواست میشود
- اگر خطایی رخ داده باشد، نما [ERREURS] ارسال میشود – خطوط ۱۳–۱۹
- در غیر این صورت، نما [LISTE] ارسال میشود – خطوط ۲۰–۲۴
1.5.7.5. پردازش اقدام [infos]
مشتری اطلاعاتی در مورد یک آیتم خاص درخواست کرده است:

کد به شرح زیر است:
توضیحات:
- هرگونه خطا در [ArrayList] – خط ۴ قرار میگیرد
- شناسهٔ آیتم درخواستی از پرسوجو بازیابی میشود – خط ۶
- این شناسه بررسی میشود. باید موجود باشد و یک عدد صحیح باشد. اگر اینطور نباشد، نما [ERREURS] با پیام خطای مناسب بازگردانده میشود – خطوط 7–27
- پس از تأیید شناسه، آیتم از [articlesDomain] که یک شیء واحد (singleton) است، درخواست میشود. اگر استثنایی رخ دهد، نمای [ERREURS] بازگردانده میشود – خطوط 29–39
- اگر آیتم یافت نشود، ویوی [ERREURS] بازگردانده میشود – خطوط ۴۱–۴۸
- اگر آیتم پیدا شود، در جلسهٔ کاربر قرار میگیرد و سپس در نمای [INFOS] – خطوط ۵۰–۵۶ نمایش داده میشود.
1.5.7.6. پردازش اقدام [achat]
مشتری کالای نمایشدادهشده در نما [INFOS] را خریداری کرده است.

کد به شرح زیر است:
توضیحات:
- مورد قرار داده شده در جلسه بازیابی میشود – خط ۵
- اگر آن وجود نداشته باشد (ممکن است جلسه منقضی شده باشد)، نما [LISTE] نمایش داده میشود – خطوط ۷–۱۰
- مقدار خریداریشده از پرسوجو بازیابی میشود – خط ۱۲
- اعتبار آن بررسی میشود – خطوط ۱۳–۲۹
- اگر نامعتبر باشد، بسته به شرایط، یا نما [LISTE] نمایش داده میشود – خط 16 یا نما [INFOS] – خطوط 24–28
- اگر همه چیز مرتب باشد، خرید به سبد خرید اضافه میشود – خطوط ۳۱–۳۲
- سپس view [LISTE] ارسال میشود – خط 34
1.5.7.7. پردازش اقدام [panier]
مشتری چندین خرید انجام داده و درخواست مشاهده سبد خرید را دارد:

کد به شرح زیر است:
توضیحات:
- سبد خرید از جلسه بازیابی میشود – خط ۴. در اینجا بررسی نمیکنیم که آیا واقعاً چیزی بازیابی شده است یا خیر. باید این کار را انجام دهیم، زیرا ممکن است جلسه منقضی شده باشد.
- اگر سبد خرید خالی باشد، نما [PANIERVIDE] ارسال میشود – خطوط ۶–۱۰
- در غیر این صورت، نما [PANIER] بازگردانده میشود – خطوط ۱۱–۱۴
1.5.7.8. پردازش اقدام [retirerachat]
مشتری میخواهد یک کالا را از سبد خرید خود حذف کند:

کد به شرح زیر است:
توضیحات:
- سبد خرید از جلسه بازیابی میشود – خط ۴. در اینجا بررسی نمیکنیم که آیا واقعاً چیزی بازیابی شده است یا خیر. باید این کار را انجام دهیم، زیرا ممکن است جلسه منقضی شده باشد.
- شناسه [id] آیتمی که باید حذف شود از درخواست دریافت میشود – خط ۸.
- خرید متناظر از سبد خرید حذف میشود – خط ۱۰
- اعتبار شناسهی کالای خریداریشده در اینجا بررسی نشده است. اگر از نوع نامعتبر باشد، یک استثنا رخ خواهد داد و در خطوط ۱۱–۱۳ رسیدگی میشود. اگر معتبر باشد اما وجود نداشته باشد، متد [panier.enlever] – خط ۱۰ – هیچ کاری انجام نمیدهد.
- سبد جدید نمایش داده میشود – خط 16
1.5.7.9. پردازش اقدام [validerpanier]
مشتری میخواهد سبد خرید خود را تأیید کند:

کد به شرح زیر است:
توضیحات:
- سبد خرید از جلسه بازیابی میشود – خط ۶. در اینجا بررسی نمیکنیم که آیا واقعاً چیزی بازیابی شده است یا خیر. باید این کار را انجام دهیم، زیرا ممکن است جلسه منقضی شده باشد.
- اگر جلسه منقضی شده باشد، ما یک اشارهگر [nothing] برای سبد خرید خواهیم داشت، و متد [acheter] – خط ۹ – یک استثنا پرتاب خواهد کرد و نما [ERREURS] بازگردانده خواهد شد. با این حال، پیام خطا برای کاربر چندان مبهم خواهد بود.
- خطوط ۸–۱۶: ما سعی میکنیم سبد خرید بازیابیشده از جلسه را اعتبارسنجی کنیم. برخی خریدها ممکن است اعتبارسنجی نشوند اگر مقدار درخواستی از موجودی کالای موردنظر بیشتر باشد. این موارد توسط متد [acheter] در یک لیست خطا ثبت میشوند که در خط ۱۱ بازیابی میشود.
- اگر خطایی وجود داشته باشد، نما [ERREURS] ارسال میشود – خطوط ۱۸–۲۳
- در غیر این صورت، نما [LISTE] ارسال میشود – خطوط ۲۵–۲۶
1.6. Conclusion
در اینجا ما یک برنامه کاربردی مبتنی بر مدل MVC توسعه دادهایم. تا آوریل ۲۰۰۵، به نظر نمیرسد که هیچ چارچوب (framework) حرفهای توسعه MVC در ASP.NET وجود داشته باشد، مانند آنهایی که در جاوا وجود دارند (Struts, Spring, ...). انتظار میرود پروژه [Spring.net] بهزودی یکی از این چارچوبها را ارائه دهد. تا زمان این توسعه، روش فوق امکان توسعهٔ قابلقبول MVC را برای برنامههای متوسط فراهم میکند.































