Skip to content

1. Bölüm 1

Belgenin PDF dosyası, |BURADA| adresinde mevcuttur.

Belgedeki örnekler |BURADA| adresinde mevcuttur.

1.1. Introduction

Makalenin amaçları:

  • 3 katmanlı bir web uygulaması yazmak [interface utilisateur, métier, accès aux données]
  • uygulamayı Spring ile yapılandırmak IOC
  • üç katmandan birinin veya birkaçının uygulamasını değiştirerek farklı sürümler yazmak.

Kullanılan araçlar:

  • Geliştirme için Visual Studio.net - ekteki 3.1 numaralı paragrafa bakınız;
  • Çalıştırma için Cassini web sunucusu - ekteki 3.2 numaralı paragrafa bakınız;
  • Birim testleri için Nunit – bkz. ek, paragraf 3.4;
  • Web uygulamasının katmanlarının entegrasyonu ve yapılandırması için Spring – bkz. ek, paragraf 3.3;

Başlangıç-orta-ileri düzey ölçeğinde, bu belge [intermédiaire-avancé] bölümünde yer almaktadır. Belgeyi anlamak için çeşitli ön koşullar gereklidir. Bunlardan bazıları, benim yazdığım belgelerde ele alınmıştır. Bu durumda, söz konusu belgeleri kaynak olarak belirtirim. Elbette bu sadece bir öneridir ve okuyucu kendi tercih ettiği belgeleri kullanabilir.

Bu belge, Java [Struts, Spring ve Java kullanılarak üç katmanlı mimariler ve MVC mimarileri (2005)] için yazılmış bir belgenin ana hatlarını ele almaktadır. VB.NET'te, Java ile yazılmış üç katmanlı MVC web uygulamasını geliştiriyoruz. Burada vurgulamak istediğimiz nokta, Java ve .NET geliştirme platformlarının birbirine yeterince yakın olması nedeniyle, bu iki alandan birinde edinilen becerilerin diğerinde de yeniden kullanılabileceğidir.

MVC ASP.NET geliştirme alanında yaygın olarak kabul görmüş bir çözüm bulunmuyor gibi görünüyor. Aşağıdaki çözüm, [ASP.NET 1.1 ile Web Geliştirme (2004)] belgesinde tanıtılan yöntemi temel almaktadır. Bu yöntem, J2EE geliştirme alanında yaygın olarak kullanılan kavramları kullanma avantajına sahip olsa da, yalnızca olduğu gibi, yani c.a.d geliştirme yöntemlerinden biri olarak değerlendirilmelidir. MVC'ten ASP.NET'e bir geliştirme yöntemi yaygın olarak kabul gördüğü anda, o zaman bu yöntem benimsenmelidir. Geliştirme aşamasında olan Spring'in .NET sürümü, ilk çözüm olabilir.

1.2. webarticles uygulaması

Burada, basitleştirilmiş bir e-ticaret web uygulamasının bileşenlerini sunuyoruz. Bu uygulama, web kullanıcılarına şunları sağlayacaktır:

  • bir veritabanından gelen ürün listesini görüntülemek
  • bazı ürünleri elektronik sepetlerine ekleyebilme
  • sepeti onaylayabilmelerini sağlayacaktır. Bu onay işleminin tek etkisi, satın alınan ürünlerin stok bilgilerinin veritabanında güncellenmesidir.

Kullanıcıya sunulan farklı görünümler şunlar olacaktır:

- Satışta olan ürünlerin listesini gösteren "LISTE" görünümü
- Bir ürün hakkında ek bilgiler veren "[INFOS]" görünümü:
  • Müşterinin sepetinin içeriğini gösteren [PANIER] ve [PANIERVIDE] görünümleri
  • Uygulamadaki tüm hataları bildiren [ERREURS] görünümü

Image

1.3. Uygulamanın genel mimarisi

Aşağıdaki üç katmanlı yapıya sahip bir uygulama geliştirmek istiyoruz:

  • Arayüzlerin kullanılması sayesinde üç katman birbirinden bağımsız hale getirilmiştir
  • Farklı katmanların entegrasyonu Spring ile gerçekleştirilir
  • Her katman ayrı ad alanlarına sahiptir: web (UI katmanı), domain (iş katmanı) ve dao (veri erişim katmanı).

Uygulama, MVC mimarisine (Model - Görünüm - Denetleyici) uygun olacaktır. Yukarıdaki katman şemasını ele alırsak, MVC mimarisi bu şemaya şu şekilde entegre edilir:

Bir istemciden gelen isteğin işlenmesi aşağıdaki adımlara göre gerçekleşir:

  1. müşteri, denetleyiciye bir istek gönderir. Bu denetleyici, burada özel bir rol üstlenecek bir .aspx sayfası olacaktır. Müşterilerin tüm isteklerini bu sayfa üzerinden alır. Bu, uygulamanın giriş kapısıdır. MVC'teki C harfidir.
  1. Denetleyici bu talebi işler. Bunu yapmak için iş katmanının yardımına ihtiyaç duyabilir; bu, MVC yapısında M modeli olarak adlandırılır.
  2. Denetleyici, iş katmanından bir yanıt alır. Müşterinin talebi işlenmiştir. Bu, birkaç farklı yanıtı içerebilir. Klasik bir örnek,
    • isteğin düzgün bir şekilde işlenememesi durumunda bir hata sayfası
    • aksi takdirde bir onay sayfası
  3. denetleyici, müşteriye gönderilecek yanıtı (= görünüm) seçer. Bu, çoğunlukla dinamik öğeler içeren bir sayfadır. Denetleyici, bu öğeleri görünüme sağlar.
  4. Görünüm, müşteriye gönderilir. Bu, MVC'teki V'dir.

1.4. Model

Burada MVC'teki M'yi inceliyoruz. Model burada aşağıdaki öğelerden oluşur:

  1. iş sınıfları
  2. veri erişim sınıfları
  3. veritabanı

1.4.1. Veritabanı

Veritabanı, yalnızca ARTICLES adlı bir tablo içermektedir. Bu tablo, aşağıdaki SQL komutlarıyla oluşturulmuştur:

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
);
/* kısıtlamalar */
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);
/* birincil anahtar */
ALTER TABLE ARTICLES ADD CONSTRAINT PK_ARTICLES PRIMARY KEY (ID);
id
bir ürünü benzersiz bir şekilde tanımlayan birincil anahtar
nom
ürün adı
prix
ürünün fiyatı
stockactuel
mevcut stok durumu
stockminimum
yeniden tedarik siparişinin verilmesi gereken stok seviyesi

1.4.2. Modelin ad alanları

M modeli burada iki ad alanı şeklinde sunulmaktadır:

  • istia.st.articles.dao: [dao] katmanının veri erişim sınıflarını içerir
  • istia.st.articles.domain: [domain] katmanının iş sınıflarını içerir

Bu ad alanlarının her biri, kendisine ait bir "assembly" dosyası içinde oluşturulacaktır:

assembly
contenu
rôle
webarticles-dao
- [IArticlesDao]: [dao] katmanına erişim arayüzü.
[domain] katmanı yalnızca bu arayüzü görür. Başka bir arayüz görmez.
- [Article]: bir ürünü tanımlayan sınıf
- [ArticlesDaoArrayList]:
[IArticlesDao] arayüzünü, [ArrayList]
veri erişim katmanı
- tamamen
[dao] katmanında yer alır
web uygulamasının
webarticles-domain
- [IArticlesDomain]: [domain] katmanına erişim arayüzüdür. Web katmanının gördüğü tek arayüzdür. Başka bir arayüz görmez.
- [AchatsArticles]: [IArticlesDomain]'i uygulayan bir sınıf
- [Achat]: Bir müşterinin satın alma işlemini temsil eden sınıf
- [Panier]: bir müşterinin tüm satın alımlarını temsil eden sınıf
web üzerindeki satın alma modelini temsil eder
web'deki satın alma modelini temsil eder - tamamen
web uygulamasının
web uygulamasının 3-katmanlı mimarisinin

1.4.3. [dao] katmanı

[dao] katmanı aşağıdaki öğeleri içerir:

  • [IArticlesDao]: [dao] katmanına erişim arayüzü

  • [Article]: bir ürünü tanımlayan sınıf

  • [ArticlesDaoArrayList]: [IArticlesDao] arayüzünün, [ArrayList] sınıfı ile gerçekleştirilmesini sağlayan sınıf

[dao] katmanındaki [Visual Studio] projesinin yapısı şöyledir:

Image

Açıklamalar:

  • [dao] projesi, [bibliothèque de classes] türündedir
  • Sınıflar, [istia] klasörünü kök olarak alan bir dizin yapısına yerleştirilmiştir. Hepsi [istia.st.articles.dao] ad alanında yer almaktadır.

1.4.3.1. [Article] sınıfı

Bir öğeyi tanımlayan sınıf şöyledir:

Imports System

Namespace istia.st.articles.dao

    Public Class Article

         ' özel alanlar
        Private _id As Integer
        Private _nom As String
        Private _prix As Double
        Private _stockactuel As Integer
        Private _stockminimum As Integer

         ' ürün kimliği
        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

         ' ürün adı
        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

         ' ürün fiyatı
        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

         ' ürünün mevcut stoğu
        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

         ' ürün minimum stoğu
        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

         ' varsayılan üretici
        Public Sub New()
        End Sub

         ' özelliklere sahip üretici
        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

         ' ürün tanımlama yöntemi
        Public Overrides Function ToString() As String
            Return "[" + id.ToString + "," + nom + "," + prix.ToString + "," + stockactuel.ToString + "," + stockminimum.ToString + "]"
        End Function
    End Class
End Namespace

Bu sınıf şunları sunar:

  1. bir öğenin 5 bilgisini belirlemeye yarayan bir oluşturucu: [id, nom, prix, stockactuel, stockminimum]
  2. bu 5 bilgiyi okumak ve yazmak için kullanılan genel özellikler.
  3. ürüne girilen verilerin doğrulanması. Verilerde hata olması durumunda bir istisna atılır.
  4. bir makalenin değerini karakter dizisi biçiminde almayı sağlayan toString yöntemi. Bu, genellikle bir uygulamanın hata ayıklamasında kullanışlıdır.

1.4.3.2. [IArticlesDao] arayüzü

[IArticlesDao] arayüzü şu şekilde tanımlanmıştır:

Imports System
Imports System.Collections

Namespace istia.st.articles.dao

    Public Interface IArticlesDao
         ' tüm ürünlerin listesi
        Function getAllArticles() As IList
         ' ürün ekler
        Function ajouteArticle(ByVal unArticle As Article) As Integer
         ' ürünü sil
        Function supprimeArticle(ByVal idArticle As Integer) As Integer
         ' ürünü düzenler
        Function modifieArticle(ByVal unArticle As Article) As Integer
         ' ürün arar
        Function getArticleById(ByVal idArticle As Integer) As Article
         ' tüm ürünleri sil
        Sub clearAllArticles()
         ' bir ürünün stokunu değiştirir
        Function changerStockArticle(ByVal idArticle As Integer, ByVal mouvement As Integer) As Integer
    End Interface
End Namespace

Arayüzdeki farklı yöntemlerin işlevleri şunlardır:

getAllArticles
veri kaynağındaki tüm makaleleri döndürür
clearAllArticles
veri kaynağını boşaltır
getArticleById
birincil anahtarıyla tanımlanan [Article] nesnesini döndürür
ajouteArticle
veri kaynağına bir öğe eklemeye izin verir
modifieArticle
veri kaynağındaki bir öğeyi değiştirmeye olanak tanır
supprimerArticle
veri kaynağından bir öğeyi silmeye olanak tanır
changerStockArticle
veri kaynağındaki bir ürünün stokunu değiştirmeye olanak tanır

Arayüz, istemci programlarına yalnızca imzalarıyla tanımlanan bir dizi yöntem sunar. Bu yöntemlerin gerçekte nasıl uygulanacağıyla ilgilenmez. Bu, uygulamaya esneklik kazandırır. İstemci programı, arayüzün belirli bir uygulamasına değil, arayüze çağrı yapar.

Belirli bir uygulamanın seçimi, bir Spring yapılandırma dosyası aracılığıyla yapılacaktır. Web uygulamasını test etmek için yalnızca veri erişim arayüzünün önemli olduğunu, uygulama sınıfının ise önemli olmadığını göstermek amacıyla, öncelikle veri kaynağını basit bir [ArrayList] nesnesi ile uygulayacağız. Daha sonra, SGBD tabanlı bir çözüm sunacağız.

1.4.3.3. [ArticlesDaoArrayList] uygulama sınıfı

[ArticlesDaoArrayList] uygulama sınıfı şu şekilde tanımlanmıştır:

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

         ' varsayılan üretici
        Public Sub New()
             ' bazı ürünleri üretir
            For i As Integer = 1 To nbArticles
                articles.Add(New Article(i, "article" + i.ToString, i * 10, i * 10, i * 10))
            Next
        End Sub

         ' tüm ürünlerin listesi
        Public Function getAllArticles() As IList Implements IArticlesDao.getAllArticles
             ' ürün listesini döndürür
            SyncLock Me
                Return articles
            End SyncLock
        End Function

         ' tüm ürünlerin silinmesi
        Public Sub clearAllArticles() Implements IArticlesDao.clearAllArticles
             ' ürün listesini boşaltma
            SyncLock Me
                articles.Clear()
            End SyncLock
        End Sub

         ' anahtarıyla tanımlanan bir öğeyi alma
        Public Function getArticleById(ByVal idArticle As Integer) As Article Implements IArticlesDao.getArticleById
             ' listeden ürünü arar
            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

         ' ürün listesine bir ürün ekle
        Public Function ajouteArticle(ByVal unArticle As Article) As Integer Implements IArticlesDao.ajouteArticle
             ' ürünü ürün listesine ekleniyor
            SyncLock Me
                 ' ürünün daha önce mevcut olup olmadığı kontrol ediliyor
                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
                 ' ürün ekleniyor
                articles.Add(unArticle)
                 ' sonuç döndürülür
                Return 1
            End SyncLock
        End Function

         ' bir ürünü düzenlemek
        Public Function modifieArticle(ByVal articleNouveau As Article) As Integer Implements IArticlesDao.modifieArticle
             ' bir ürünü düzenliyoruz
            SyncLock Me
                 ' var olup olmadığı kontrol edilir
                Dim ipos As Integer = posArticle(articles, articleNouveau.id)
                 ' eğer yoksa
                If ipos = -1 Then Return 0
                 ' mevcut ise - makaleyi düzenliyoruz
                articles(ipos) = articleNouveau
                 ' sonuç verilir
                Return 1
            End SyncLock
        End Function

         ' anahtarıyla tanımlanan bir makaleyi silmek
        Public Function supprimeArticle(ByVal idArticle As Integer) As Integer Implements IArticlesDao.supprimeArticle
             ' bir ürünün silinmesi
            SyncLock Me
                 ' var olup olmadığı kontrol edilir
                Dim ipos As Integer = posArticle(articles, idArticle)
                 ' mevcut değilse
                If ipos = -1 Then Return 0
                 ' mevcutsa - silinir
                articles.RemoveAt(ipos)
                 ' sonuç döndürülür
                Return 1
            End SyncLock
        End Function

         ' anahtarıyla tanımlanan bir ürünün stokunu değiştir
        Public Function changerStockArticle(ByVal idArticle As Integer, ByVal mouvement As Integer) As Integer Implements IArticlesDao.changerStockArticle
             ' bir ürünün stokunu değiştir
            SyncLock Me
                 ' var olup olmadığını kontrol edelim
                Dim ipos As Integer = posArticle(articles, idArticle)
                 ' mevcut değilse
                If ipos = -1 Then Return 0
                 ' ürün varsa - mümkünse stokunu değiştir
                Dim unArticle As Article = CType(articles(ipos), Article)
                 ' stok yeterli ise değiştirilir
                If unArticle.stockactuel + mouvement >= 0 Then
                    unArticle.stockactuel += mouvement
                    Return 1
                Else
                    Return 0
                End If
            End SyncLock
        End Function

         ' anahtarıyla tanımlanan bir ürünü aranır
        Private Function posArticle(ByVal listArticles As ArrayList, ByVal idArticle As Integer) As Integer
             ' [idArticle] ürününün listedeki konumunu döndürür veya bulunmazsa -1'i döndürür
            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
             ' bulunamadı
            Return -1
        End Function
    End Class

End Namespace

Açıklamalar:

  • Veri kaynağı, [ArrayList] türündeki özel alan [articles] ile simüle edilir
  • Sınıf oluşturucu, varsayılan olarak veri kaynağında 4 madde oluşturur.
  • Veri kaynağına eşzamanlı erişim sorunlarını önlemek için tüm veri erişim yöntemleri senkronize edilmiştir. Herhangi bir anda, belirli bir yönteme yalnızca tek bir iş parçacığı erişebilir.
  • [posArticle] yöntemi, numarasıyla tanımlanan bir öğenin [ArrayList] kaynağındaki [0..N] konumunu öğrenmeyi sağlar. Makale mevcut değilse, yöntem -1 konumunu döndürür. Bu yöntem, diğer yöntemler tarafından tekrar tekrar kullanılır.
  • [ajouteArticle] yöntemi, ürün listesine bir ürün eklemeye olanak tanır. Eklenen ürün sayısını 1 olarak döndürür. Ürün zaten mevcutsa, bir istisna atılır.
  • [modifieArticle] yöntemi, mevcut bir ürünü düzenlemeye olanak tanır. Bu yöntem, ürün varsa değiştirilen ürün sayısını 1 olarak, yoksa 0 olarak döndürür.
  • [supprimeArticle] yöntemi, mevcut bir ürünü silmeye yarar. Bu yöntem, ürün silindiğinde ürün sayısını 1 olarak, yoksa 0 olarak döndürür.
  • [getAllArticles] yöntemi, tüm makalelerin listesini verir.
  • [getArticleById] yöntemi, numarasıyla tanımlanan bir ürünü almayı sağlar. Ürün mevcut değilse [nothing] değeri döndürülür.
  • Kodda gerçek anlamda bir zorluk yoktur. Okuyucunun kodu inceleyip anlamasına bırakıyoruz.

1.4.3.4. [dao] katmanının derlemesinin oluşturulması

Visual Studio projesi, [webarticles-dao.dll] derlemesini oluşturacak şekilde yapılandırılmıştır. Bu derleme, projenin [bin] klasöründe oluşturulur:

1.4.3.5. [dao] katmanının NUnit testleri

Java'da sınıflar, [Junit] çerçeve yapısı ile test edilir. .NET'te ise Nunit çerçeve yapısı aynı birim test olanaklarını sunar:

Image

Test için Visual Studio projesinin yapısı şu şekildedir:

Image

Açıklamalar:

  • [tests] projesi, [bibliothèque de classes] türündedir
  • [NUnit] testleri, [nunit.framework.dll] derlemesine bir referans gerektirir
  • [NUnit] test sınıfı, Spring aracılığıyla test edilecek nesnenin bir örneğini alır. Ayrıca
    • [bin] klasöründe, Spring sınıf dosyaları
    • [References] içinde, [bin] klasöründeki [Spring-Core.dll] derlemesine bir referans bulunur
    • [bin] klasöründe bir yapı,
  • Test sınıfı, [dao] katmanındaki [webarticles-dao.dll] derlemesine ihtiyaç duyar. Bu derleme, [bin] klasörüne yerleştirilmiş ve referansı proje referanslarına eklenmiştir.

[NUnit] test sınıfı, [NUnit.Framework] ad alanındaki sınıflara erişim gerektirir. Bu nedenle, burada şu içe aktarma komutu bulunur:

Imports NUnit.Framework

[NUnit.Framework] ad alanı, projenin referanslarına eklenmesi gereken [nunit.framework.dll] "derlemesinde" bulunur:

[Nunit] kurulumu yapılmışsa, [nunit.framework.dll] derlemesi önerilen listede yer almalıdır. Derlemeyi projeye eklemek için üzerine çift tıklamanız yeterlidir:

Image

[dao] katmanına ait [NUnit] test sınıfı şu şekilde olabilir:

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
         ' test edilecek nesne
        Private articlesDao As IArticlesDao

        <SetUp()> _
        Public Sub init()
             ' Spring nesne oluşturucusunun bir örneğini alır
            Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config.xml", FileMode.Open))
             ' articlesdao nesnesinin örneklenmesi istenir
            articlesDao = CType(factory.GetObject("articlesdao"), IArticlesDao)
        End Sub

        <Test()> _
        Public Sub testGetAllArticles()
             ' görsel kontrol
            listArticles()
        End Sub

        <Test()> _
        Public Sub testClearAllArticles()
             ' tüm makaleler siliniyor
            articlesDao.clearAllArticles()
             ' tüm makaleler isteniyor
            Dim articles As IList = articlesDao.getAllArticles
             ' kontrol: sayı 0 olmalıdır
            Assert.AreEqual(0, articles.Count)
        End Sub

        <Test()> _
        Public Sub testAjouteArticle()
             ' tüm ürünlerin silinmesi
            articlesDao.clearAllArticles()
             ' doğrulama: ürün tablosu boş olmalı
            Dim articles As IList = articlesDao.getAllArticles
            Assert.AreEqual(0, articles.Count)
             ' iki ürün ekleniyor
            articlesDao.ajouteArticle(New Article(3, "article3", 30, 30, 3))
            articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
             ' doğrulama: iki ürün olmalı
            articles = articlesDao.getAllArticles
            Assert.AreEqual(2, articles.Count)
             ' görsel kontrol
            listArticles()
        End Sub

        <Test()> _
        Public Sub testSupprimeArticle()
             ' tüm ürünlerin silinmesi
            articlesDao.clearAllArticles()
             ' doğrulama: ürün tablosu boş olmalıdır
            Dim articles As IList = articlesDao.getAllArticles
            Assert.AreEqual(0, articles.Count)
             ' iki ürün ekleniyor
            articlesDao.ajouteArticle(New Article(3, "article3", 30, 30, 3))
            articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
             ' kontrol: 2 ürün bulunmalıdır
            articles = articlesDao.getAllArticles
            Assert.AreEqual(2, articles.Count)
             ' 4 numaralı ürün siliniyor
            articlesDao.supprimeArticle(4)
             ' kontrol: 1 ürün kalmalıdır
            articles = articlesDao.getAllArticles
            Assert.AreEqual(1, articles.Count)
             ' gözle kontrol
            listArticles()
        End Sub

        <Test()> _
        Public Sub testModifieArticle()
             ' tüm maddelerin silinmesi
            articlesDao.clearAllArticles()
             ' kontrol
            Dim articles As IList = articlesDao.getAllArticles
            Assert.AreEqual(0, articles.Count)
             ' 2 ürünün eklenmesi
            articlesDao.ajouteArticle(New Article(3, "article3", 30, 30, 3))
            articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
             ' doğrulama
            articles = articlesDao.getAllArticles
            Assert.AreEqual(2, articles.Count)
             ' 3 numaralı ürünün aranması
            Dim unArticle As Article = articlesDao.getArticleById(3)
             ' doğrulama
            Assert.AreEqual(unArticle.nom, "article3")
             ' 4. maddenin aranması
            unArticle = articlesDao.getArticleById(4)
             ' doğrulama
            Assert.AreEqual(unArticle.nom, "article4")
             ' 4. maddenin değiştirilmesi
            articlesDao.modifieArticle(New Article(4, "article4", 44, 44, 44))
             ' doğrulama
            unArticle = articlesDao.getArticleById(4)
            Assert.AreEqual(unArticle.prix, 44, 0.000001)
             ' görsel kontrol
            listArticles()
        End Sub

        <Test()> _
        Public Sub testGetArticleById()
             ' madde silme
            articlesDao.clearAllArticles()
             ' doğrulama
            Dim articles As IList = articlesDao.getAllArticles
            Assert.AreEqual(0, articles.Count)
             ' 2 maddenin eklenmesi
            articlesDao.ajouteArticle(New Article(3, "article3", 30, 30, 3))
            articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
             ' doğrulama
            articles = articlesDao.getAllArticles
            Assert.AreEqual(2, articles.Count)
             ' 3. maddenin aranması
            Dim unArticle As Article = articlesDao.getArticleById(3)
             ' doğrulama
            Assert.AreEqual(unArticle.nom, "article3")
             ' 4. maddenin aranması
            unArticle = articlesDao.getArticleById(4)
             ' doğrulama
            Assert.AreEqual(unArticle.nom, "article4")
        End Sub

         ' ekran listesi
        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()
             ' tüm ürünlerin silinmesi
            articlesDao.clearAllArticles()
             ' 1. madde arama
            Dim article As article = articlesDao.getArticleById(1)
             ' doğrulama
            Assert.IsNull(article)
             ' mevcut olmayan bir ürünün düzenlenmesi
            Dim i As Integer = articlesDao.modifieArticle(New article(1, "1", 1, 1, 1))
             ' hiçbir satır değiştirilmedi
            Assert.AreEqual(i, 0)
             ' mevcut olmayan bir maddenin silinmesi
            i = articlesDao.supprimeArticle(1)
             ' hiçbir satır silinmedi
            Assert.AreEqual(0, i)
        End Sub

        <Test()> _
        Public Sub testChangerStockArticle()
             ' tüm makalelerin silinmesi
            articlesDao.clearAllArticles()
             ' bir makale eklendi
            Dim nbArticles As Integer = articlesDao.ajouteArticle(New Article(3, "article3", 30, 101, 3))
            Assert.AreEqual(nbArticles, 1)
             ' bir makale eklendi
            nbArticles = articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
            Assert.AreEqual(nbArticles, 1)
             ' 100 konu oluşturuldu
            Dim taches(99) As Thread
            For i As Integer = 0 To taches.Length - 1
                 ' i başlığı oluşturuluyor
                taches(i) = New Thread(New ThreadStart(AddressOf décrémente))
                 ' iş parçacığının adı belirleniyor
                taches(i).Name = "tache_" & i
                 ' i konulu başlığın yürütülmesi başlatılıyor
                taches(i).Start()
            Next
             ' tüm iş parçacıklarının bitmesini bekleme
            For i As Integer = 0 To taches.Length - 1
                taches(i).Join()
            Next
             ' kontroller - 3 numaralı ürünün stokunda 1 adet olması gerekir
            Dim unArticle As Article = articlesDao.getArticleById(3)
            Assert.AreEqual(unArticle.nom, "article3")
            Assert.AreEqual(1, unArticle.stockactuel)
             ' 4 numaralı ürünün stoğu azaltılır
            Dim erreur As Boolean = False
            Dim nbLignes As Integer = articlesDao.changerStockArticle(4, -100)
             ' kontrol: stokunda değişiklik olmamış olmalı
            Assert.AreEqual(0, nbLignes)
             ' gözle kontrol
            listArticles()
        End Sub

        Public Sub décrémente()
             ' iş parçacığı başlatıldı
            System.Console.Out.WriteLine(Thread.CurrentThread.Name + " lancé")
             ' iş parçacığı stok miktarını azaltıyor
            articlesDao.changerStockArticle(3, -1)
             ' iş parçacığı tamamlandı
            System.Console.Out.WriteLine(Thread.CurrentThread.Name + " terminé")
        End Sub

    End Class
End Namespace

Açıklamalar:

  • [IArticlesDao] arayüzünü, bu arayüzün uygulama sınıfından bağımsız olarak test edecek bir program yazmak istedik. Bu nedenle, test programından uygulama sınıfının adını gizlemek için Spring'i kullandık.
  • <Setup()> öznitelik yöntemi, Spring'den test edilecek [articlesdao] nesnesine ilişkin bir referans alır. Bu nesne, aşağıdaki [spring-config.xml] dosyasında tanımlanmıştır:
<?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>

Bu dosya, [IArticlesDao] arayüzünün [istia.st.articles.dao.ArticlesDaoArrayList] uygulama sınıfının adını ve [ webarticles-dao.dll]'te nerede bulunabileceğini belirtir. Örnekleme için parametre gerekmediğinden, burada herhangi bir parametre tanımlanmamıştır.

  • Testlerin çoğu anlaşılması kolaydır. Okuyucunun yorumları okuması tavsiye edilir.
  • [testChangerStockArticle] yöntemi ise biraz açıklama gerektirir. Bu yöntem, belirli bir ürünün stok miktarını azaltmakla görevli 100 iş parçacığı oluşturur.
        <Test()> _
        Public Sub testChangerStockArticle()
             ' tüm ürünlerin silinmesi
            articlesDao.clearAllArticles()
             ' ürün ekleniyor
            Dim nbArticles As Integer = articlesDao.ajouteArticle(New Article(3, "article3", 30, 101, 3))
            Assert.AreEqual(nbArticles, 1)
             ' bir ürün eklendi
            nbArticles = articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
            Assert.AreEqual(nbArticles, 1)
             ' 100 iş parçacığı oluşturuldu
            Dim taches(99) As Thread
            For i As Integer = 0 To taches.Length - 1
                 ' i başlığı oluşturuluyor
                taches(i) = New Thread(New ThreadStart(AddressOf décrémente))
                 ' iş parçacığının adı belirleniyor
                taches(i).Name = "tache_" & i
                 ' i konulu başlığın yürütülmesi başlatılıyor
                taches(i).Start()
            Next
             ' tüm iş parçacıklarının bitmesini bekleme
            For i As Integer = 0 To taches.Length - 1
                taches(i).Join()
            Next
             ' kontroller - 3 numaralı ürünün stokta 1 adet olması gerekir
            Dim unArticle As Article = articlesDao.getArticleById(3)
            Assert.AreEqual(unArticle.nom, "article3")
            Assert.AreEqual(1, unArticle.stockactuel)
             ' 4 numaralı ürünün stoğu azaltılıyor
            Dim erreur As Boolean = False
            Dim nbLignes As Integer = articlesDao.changerStockArticle(4, -100)
             ' kontrol: stokunda bir değişiklik olmamış olmalı
            Assert.AreEqual(0, nbLignes)
             ' gözle kontrol
            listArticles()
        End Sub

Burada veri kaynağına eşzamanlı erişimlerin test edilmesi amaçlanmaktadır. Stok güncellemesinden sorumlu yöntem şöyledir:

        Public Sub décrémente()
             ' iş parçacığı başlatıldı
            System.Console.Out.WriteLine(Thread.CurrentThread.Name + " lancé")
             ' iş parçacığı stok miktarını azaltıyor
            articlesDao.changerStockArticle(3, -1)
             ' iş parçacığı tamamlandı
            System.Console.Out.WriteLine(Thread.CurrentThread.Name + " terminé")
        End Sub

3 numaralı ürünün stokundan bir birim düşer. [testChangerStockArticle] yöntem koduna bakıldığında şunu görürüz:

  • 3 numaralı ürünün stoğu 101 olarak başlatılır
  • 100 iş parçacığı bu stoğu birer birer azaltacaktır
  • bu nedenle, tüm iş parçacıklarının yürütülmesi tamamlandığında stok 1 olmalıdır

Ayrıca, yine bu yöntem içinde, 4 numaralı ürünün stokunu negatif bir değere getirmeye çalışıyoruz. Bu işlem başarısız olmalıdır.

[dao] katmanını test etmek için, [tests] projesinin [bin] klasöründe DLL ve [tests-webarticles-dao.dll] dosyalarını oluşturuyoruz:

Ardından, [Nunit-Gui] uygulamasını kullanarak bu DLL dosyasını yükleyip testleri gerçekleştiriyoruz:

Image

Soldaki pencerede, test edilen yöntemlerin listesi görülmektedir. Her yöntemin adının önündeki noktanın rengi, yöntemin başarılı (yeşil) veya başarısız (kırmızı) olduğunu gösterir. Bu belgeyi ekranda görüntüleyen okuyucu, tüm testlerin başarılı olduğunu görebilir. Bundan sonra, [dao] katmanının çalışır durumda olduğunu varsayacağız.

1.4.4. [domain] katmanı

[domain] katmanı aşağıdaki öğeleri içerir:

  • [IArticlesDomain]: [domain] katmanına erişim arayüzü

  • [Achat]: bir satın alma işlemini tanımlayan sınıf

  • [Panier]: Alışveriş sepetini tanımlayan sınıf

  • [AchatsArticles]: [IArticlesDomain] arayüzünün uygulama sınıfı

[domain] katmanındaki [Visual Studio] çözümünün yapısı şöyledir:

Image

Açıklamalar:

  • [domain] projesi, [bibliothèque de classes] türündedir
  • Sınıflar, [istia] klasörünü kök olarak alan bir dizin yapısına yerleştirilmiştir. Hepsi [istia.st.articles.domain] ad alanında yer almaktadır.
  • [dao] katmanına ait DLL, yeni projenin [bin] klasörüne yerleştirilmiştir. Ayrıca, bu DLL, projeye referans olarak eklenmiştir.

1.4.4.1. [IArticlesDomain] arayüzü

[IArticlesDomain] arayüzü, [métier] katmanını [web] katmanından ayırır. [web] katmanı, bu arayüz aracılığıyla [métier/domain] katmanına erişir ve bunu gerçekleştiren sınıfla ilgilenmez. Arayüz, iş katmanına erişim için aşağıdaki eylemleri tanımlar:

Imports Article = istia.st.articles.dao.Article

Namespace istia.st.articles.domain
    Public Interface IArticlesDomain
         ' yöntemler
        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
Function getAllArticles() As IList
ilişkili veri kaynağındaki [Article] nesne listesini döndürür
Function getArticleById(ByVal idArticle As Integer) As Article
[idArticle] ile tanımlanan [Article] nesnesini döndürür
acheter(ByVal panier As Panier)
müşterinin sepetini, satın alınan ürünlerin stoklarından satın alınan miktarı düşerek onaylar - stok yetersizse başarısız olabilir
ReadOnly Property erreurs() As ArrayList
meydana gelen hataların listesini döndürür - hata yoksa boş

1.4.4.2. [Achat] sınıfı

[Achat] sınıfı, müşterinin bir satın alma işlemini temsil eder:

Imports istia.st.articles.dao

Namespace istia.st.articles.domain

    Public Class Achat

         ' özel alanlar
        Private _article As article
        Private _qte As Integer

         ' varsayılan oluşturucu
        Public Sub New()
        End Sub

         ' parametreli oluşturucu
        Public Sub New(ByVal unArticle As article, ByVal qte As Integer)
             ' özellikler aracılığıyla
            Me.article = unArticle
            Me.qte = qte
        End Sub

         ' satın alınan ürün
        Public Property article() As article
            Get
                Return _article
            End Get
            Set(ByVal Value As article)
                _article = Value
            End Set
        End Property

         ' satın alınan miktar
        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

         ' toplam satın alma tutarı
        Public ReadOnly Property totalAchat() As Double
            Get
                Return _qte * _article.prix
            End Get
        End Property

         ' kimlik
        Public Overrides Function ToString() As String
            Return "[" + _article.ToString + "," + _qte.ToString + "]"
        End Function
    End Class

End Namespace

Açıklamalar:

  • [Achat] sınıfı aşağıdaki özelliklere ve yöntemlere sahiptir:
Public Property article() As article
satın alınan ürün
Public Property qte() As Integer
satın alınan miktar
Public ReadOnly Property totalAchat() As Double
satın alma tutarı
Public Overrides Function ToString() As String
nesnenin kimlik dizesi
  • Bir satın alma işlemini tanımlayan [article, qte] özelliklerini başlatmaya yarayan bir oluşturucuya sahiptir.

1.4.4.3. [Panier] sınıfı

[Panier] sınıfı, müşterinin tüm satın alımlarını temsil eder:

Namespace istia.st.articles.domain

Public Class Panier

     ' özel alanlar
    Private _achats As New ArrayList
        Private _totalPanier As Double = 0

     ' varsayılan üretici
    Public Sub New()
    End Sub

     ' satın alma listesi
    Public ReadOnly Property achats() As ArrayList
        Get
            Return _achats
        End Get
    End Property

     ' toplam satın alma tutarı
    Public ReadOnly Property totalPanier() As Double
        Get
            Return _totalPanier
        End Get
    End Property

     ' yöntemler
    Public Sub ajouter(ByVal unAchat As Achat)
         ' satın alma işleminin daha önce var olup olmadığı kontrol edilir
        Dim iAchat As Integer = posAchat(unAchat.article.id)
        If iAchat <> -1 Then
             ' bulundu
                Dim achatCourant As Achat = CType(_achats(iAchat), Achat)
            achatCourant.qte += unAchat.qte
        Else
             ' bulunamadı
            _achats.Add(unAchat)
        End If
         ' sepet toplamı artırılıyor
        _totalPanier += unAchat.totalAchat
    End Sub

     ' bir ürünü sepetten çıkar
    Public Sub enlever(ByVal idAchat As Integer)
         ' ürün aranıyor
            Dim iachat As Integer = posAchat(idAchat)
         ' bulunduysa, kaldırılıyor
        If iachat <> -1 Then
                Dim achatCourant As Achat = CType(_achats(iachat), Achat)
             ' sepetten çıkarılır
            _achats.RemoveAt(iachat)
             ' sepet toplamını azalt
            _totalPanier -= achatCourant.totalAchat
        End If
    End Sub

    Private Function posAchat(ByVal idArticle As Integer) As Integer
         ' satın alma listesinde bir satın alma arar
         ' listede bulunduğu konumu döndürür veya bulunmazsa -1 döndürür
        Dim achatCourant As Achat
        Dim trouvé As Boolean = False
        Dim i As Integer = 0
            While Not trouvé AndAlso i < _achats.Count
                 ' mevcut satın alma
                achatCourant = CType(_achats(i), Achat)
                 ' aranan ürünle karşılaştırma
                If achatCourant.article.id = idArticle Then
                    Return i
                End If
                 'bir sonraki satın alma
                i += 1
            End While
             ' bulunamadı
            Return -1
    End Function

     ' kimlik işlevi
    Public Overrides Function ToString() As String
        Return _achats.ToString
    End Function
End Class

End Namespace

Açıklamalar:

  • [Panier] sınıfı aşağıdaki özelliklere ve yöntemlere sahiptir:
ReadOnly Property achats() As ArrayList
Müşterinin satın alma listesi - [Achat] türündeki nesnelerin listesi
ajouter(ByVal unAchat As Achat)
alışveriş listesine bir satın alma ekler
enlever(ByVal idAchat As Integer)
idAchat ürününü alışveriş listesinden çıkar
ReadOnly Property totalPanier() As Double
sepet içindeki alışverişlerin toplam tutarı
Function ToString() As String
sepetin kimlik dizesini döndürür
  • [posAchat] yöntemi, satın alınan ürünün numarasıyla tanımlanan bir satın alma işleminin satın alma listesindeki konumunu elde etmeyi sağlayan bir yardımcı yöntemdir. Alışveriş listesi, bir ürünün birden fazla kez satın alınması durumunda listede yalnızca bir sıra işgal edeceği şekilde yönetilir. Böylece bir satın alma işlemi, satın alınan ürünün numarasıyla tanımlanabilir. [posAchat] yöntemi, aranan satın alma işlemi mevcut değilse -1 değerini döndürür.
  • [ajouter] yöntemi, satın alma listesine yeni bir satın alma işlemi ekler. Bu, satın alınan ürün listede henüz mevcut değilse listeye yeni bir giriş eklemek, halihazırda mevcutsa satın alınan miktarı artırmak anlamına gelir.
  • [enlever] yöntemi, satın alma listesinden bir numara ile tanımlanan bir satın alma işlemini kaldırmaya yarar. Satın alma işlemi mevcut değilse, yöntem hiçbir hata mesajı vermez ve hiçbir işlem yapmaz.
  • [totalPanier] satın alma tutarı, satın alma işlemlerinin eklenmesi ve çıkarılması sırasında korunur.

1.4.4.4. [AchatsArticles] sınıfı

[IArticlesDomain] arayüzü, aşağıdaki [AchatsArticles] sınıfı tarafından uygulanacaktır:

Imports istia.st.articles.dao

Namespace istia.st.articles.domain
    Public Class AchatsArticles
        Implements IArticlesDomain

         'özel alanlar
        Private _articlesDao As IArticlesDao
        Private _erreurs As ArrayList

         ' yapıcı
        Public Sub New(ByVal articlesDao As IArticlesDao)
            _articlesDao = articlesDao
        End Sub

         ' hata listesi
        Public ReadOnly Property erreurs() As ArrayList Implements IArticlesDomain.erreurs
            Get
                Return _erreurs
            End Get
        End Property

         ' makaleler listesi
        Public Function getAllArticles() As IList Implements IArticlesDomain.getAllArticles
             ' tüm ürünlerin listesi
            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

         ' numarasına göre bir ürünü bul
        Public Function getArticleById(ByVal idArticle As Integer) As Article Implements IArticlesDomain.getArticleById
             ' belirli bir ürün
            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


         ' sepet satın alma
        Public Sub acheter(ByVal panier As Panier) Implements IArticlesDomain.acheter
             ' sepet satın alma - satın alınan ürünlerin stoklarından düşülmesi gerekir
            _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 numaralı ürünün stokundan düşme
                achat = CType(achats(i), achat)
                Try
                    If _articlesDao.changerStockArticle(achat.article.id, -achat.qte) = 0 Then
                         ' işlem gerçekleştirilemedi
                        _erreurs.Add("L'achat " + achat.ToString + " n'a pu se faire - Vérifiez les stocks")
                    Else
                         ' işlem gerçekleştirildi - satın alma sepetten kaldırıldı
                        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

Açıklamalar:

  • Bu sınıf, [IArticlesDomain] arayüzünün dört yöntemini uygular. İki özel alanı vardır:
_articlesDao As IArticlesDao
veri erişim nesnesi
_erreurs As ArrayList
olası hataların listesi. Bu sınıfa, [erreurs] adlı genel özellik aracılığıyla erişilebilir
  • Sınıfın bir örneğini oluşturmak için, verilere erişim sağlayan nesneyi belirtmek gerekir:
Sub New(ByVal articlesDao As IArticlesDao)
  • [getAllArticles] ve [getArticleById] yöntemleri, [dao] katmanındaki aynı isimli yöntemlere dayanır
  • [acheter] yöntemi, sepetin satın alınmasını onaylar. Bu onay işlemi, satın alınan ürünlerin stoklarından sayısını azaltmaktan ibarettir. Bir ürünün satın alınması, ancak stok durumu elverdiği takdirde mümkündür. Aksi takdirde satın alma reddedilir: ürün sepetinde kalır ve [erreurs] listesinde bir hata bildirilir. Onaylanan bir satın alma işlemi sepetten çıkarılır ve ilgili ürünün stokundan satın alınan miktar düşülür.

1.4.4.5. [domain] katmanının derlemesinin oluşturulması

Visual Studio projesi, [webarticles-domain.dll] derlemesini oluşturacak şekilde yapılandırılmıştır. Bu derleme, projenin [bin] klasöründe oluşturulur:

1.4.4.6. NUnit katmanının [domain] testleri

Test amaçlı Visual Studio projesinin yapısı şu şekildedir:

Image

Açıklamalar:

  • [tests] projesi, [bibliothèque de classes] türündedir
  • [NUnit] testleri, [nunit.framework.dll] derlemesine bir referans gerektirir
  • [NUnit] test sınıfı, Spring aracılığıyla test edilecek nesnenin bir örneğini alır. Ayrıca
  • [bin] klasöründe, Spring sınıf dosyaları
  • [References] içinde, [bin] klasöründeki [Spring-Core.dll] derlemesine bir referans
  • [bin] klasöründe bir yapılandırma dosyası bulunur
  • Test sınıfı, [dao] katmanındaki [webarticles-dao.dll] derlemesine ve [domain] katmanındaki [webarticles-domain.dll] derlemesine ihtiyaç duyar. Bunlar [bin] klasörüne yerleştirilmiş ve referansları proje referanslarına eklenmiştir.

[domain] katmanındaki NUnit test sınıfı şu şekilde olabilir:

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

         ' test edilecek nesne
        Private articlesDomain As IArticlesDomain
        Private articlesDao As IArticlesDao

        <SetUp()> _
        Public Sub init()
             ' Spring nesne oluşturucusunun bir örneği alınır
            Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config.xml", FileMode.Open))
             ' articles DAO nesnesinin örneklenmesi isteniyor
            articlesDao = CType(factory.GetObject("articlesdao"), IArticlesDao)
             ' ardından articlesdomain nesnesinin örneğini oluşturulur
            articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDomain)
        End Sub

        <Test()> _
        Public Sub getAllArticles()
             ' görsel kontrol
            listArticles()
        End Sub

        <Test()> _
        Public Sub getArticleById()
             ' makalelerin silinmesi
            articlesDao.clearAllArticles()
             ' kontrol
            Dim articles As IList = articlesDomain.getAllArticles
            Assert.AreEqual(0, articles.Count)
             ' 2 ürünün eklenmesi
            articlesDao.ajouteArticle(New Article(3, "article3", 30, 30, 3))
            articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
             ' kontrol
            articles = articlesDomain.getAllArticles
            Assert.AreEqual(2, articles.Count)
             ' 3. maddenin aranması
            Dim unArticle As Article = articlesDomain.getArticleById(3)
             ' doğrulama
            Assert.AreEqual(unArticle.nom, "article3")
             ' 4. maddenin aranması
            unArticle = articlesDao.getArticleById(4)
             ' doğrulama
            Assert.AreEqual(unArticle.nom, "article4")
        End Sub

        <Test()> _
        Public Sub acheterPanier()
             ' ürünlerin silinmesi
            articlesDao.clearAllArticles()
             ' doğrulama
            Dim articles As IList = articlesDomain.getAllArticles
            Assert.AreEqual(0, articles.Count)
             ' 2 ürünün eklenmesi
            articlesDao.ajouteArticle(New Article(3, "article3", 30, 30, 3))
            articlesDao.ajouteArticle(New Article(4, "article4", 40, 40, 4))
             ' doğrulama
            articles = articlesDomain.getAllArticles
            Assert.AreEqual(2, articles.Count)
             ' iki ürün içeren bir sepet oluşturma
            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))
             ' doğrulamalar
            Assert.AreEqual(700, panier.totalPanier, 0.000001)
            Assert.AreEqual(2, panier.achats.Count)
             ' sepetin onaylanması
            articlesDomain.acheter(panier)
             ' doğrulamalar
            Assert.AreEqual(0, articlesDomain.erreurs.Count)
            Assert.AreEqual(0, panier.achats.Count)
             ' 3. ürün arama
            Dim unArticle As Article = articlesDomain.getArticleById(3)
             ' doğrulama
            Assert.AreEqual(unArticle.stockactuel, 20)
             ' ürün arama 4
            unArticle = articlesDao.getArticleById(4)
             ' doğrulama
            Assert.AreEqual(unArticle.stockactuel, 30)
             ' yeni sepet
            panier.ajouter(New Achat(New Article(3, "article3", 30, 30, 3), 100))
             ' sepeti onayla
            articlesDomain.acheter(panier)
             ' doğrulamalar
            Assert.AreEqual(1, articlesDomain.erreurs.Count)
             ' ürün arama 3
            unArticle = articlesDomain.getArticleById(3)
             ' doğrulama
            Assert.AreEqual(unArticle.stockactuel, 20)
        End Sub

        <Test()> _
        Public Sub testRetirerAchats()
             ' ARTICLES içeriğinin silinmesi
            articlesDao.clearAllArticles()
             ' ARTICLES tablosunu okur
            Dim articles As IList = articlesDao.getAllArticles()
            Assert.AreEqual(0, articles.Count)
             ' ekleme
            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 tablosunu okur
            articles = articlesDomain.getAllArticles()
            Assert.AreEqual(2, articles.Count)
             ' iki ürün içeren bir sepet oluşturuluyor
            Dim monPanier As New Panier
            monPanier.ajouter(New Achat(article3, 10))
            monPanier.ajouter(New Achat(article4, 10))
             ' kontroller
            Assert.AreEqual(700.0, monPanier.totalPanier, 0.000001)
            Assert.AreEqual(2, monPanier.achats.Count)
             ' daha önce satın alınmış bir ürünü ekleme
            monPanier.ajouter(New Achat(article3, 10))
             ' doğrulamalar
             ' toplam 1000'e çıkarılmalıdır
            Assert.AreEqual(1000.0, monPanier.totalPanier, 0.000001)
             ' sepette hala 2 ürün var
            Assert.AreEqual(2, monPanier.achats.Count)
             ' 3 numaralı ürünün adedi 20'ye değiştirilmelidir
            Dim unAchat As Achat = CType(monPanier.achats(0), Achat)
            Assert.AreEqual(20, unAchat.qte)
             ' 3 numaralı ürün sepetten çıkarılsın
            monPanier.enlever(3)
             ' kontroller
             ' toplam tutar 400'e ayarlanmalı
            Assert.AreEqual(400.0, monPanier.totalPanier, 0.000001)
             ' Sepette sadece 1 ürün olmalı
            Assert.AreEqual(1, monPanier.achats.Count)
             ' Bu, 4 numaralı ürün olmalı
            Assert.AreEqual(4, CType(monPanier.achats(0), Achat).article.id)
        End Sub

         ' ekran listesi
        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

Yorumlar:

  • [IArticlesDomain] arayüzünü, bu arayüzün uygulama sınıfından bağımsız olarak test edecek bir program yazmak istedik. Bu nedenle, test programından uygulama sınıfının adını gizlemek için Spring'i kullandık.
  • <Setup()> öznitelik yöntemi, Spring'den test edilecek [articlesdomain] ve [articlesdao] nesnelerine ilişkin bir referans alır. Bu nesneler, aşağıdaki [spring-config.xml] dosyasında tanımlanmıştır:
<?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>

Bu dosyada şunlar belirtilmiştir:

  • (devamı)
    • [articlesdao] tekil nesnesi için, [istia.st.articles.dao.ArticlesDaoArrayList] uygulama sınıfının adı ve [ webarticles-dao.dll]'te bulunabileceği yer belirtilmiştir. Nesne oluşturma işlemi parametre gerektirmediğinden, burada herhangi bir parametre tanımlanmamıştır.
    • [articlesdomain] singleton'u için, [istia.st.articles.domain.AchatsArticles] uygulama sınıfının adı ve bunun bulunduğu yer [ webarticles-domain.dll]'tir. [AchatsArticles] sınıfı, tek parametreli bir oluşturucuya sahiptir: [dao] katmanına erişimi yöneten singleton. Burada bu singleton, daha önce tanımlanan [articlesdao] singletonu olarak tanımlanmıştır.
  • Test sınıfı, test edilecek [articlesdomain] sınıfının bir örneğini ve veri erişim sınıfı [articlesdao]'in bir örneğini alır. Bu son nokta tartışmalıdır. Teorik olarak, test sınıfının, bilmesi bile gerekmeyen [dao] katmanına erişime ihtiyacı olmamalıdır. Burada, bu "etik" kuralı göz ardı ettik; bu kurala uymak için [IArticlesDomain] arayüzümüzde yeni yöntemler oluşturmamız gerekirdi.

[domain] katmanını test etmek için, [tests] projesinin [bin] klasöründe DLL ve [tests-webarticles-domain.dll] dosyalarını oluşturuyoruz:

Ardından, [Nunit-Gui] uygulamasını kullanarak bu DLL dosyasını yükleyip testleri gerçekleştiriyoruz:

Image

Bu belgeyi ekranda görüntüleyen okuyucu, tüm testlerin başarılı olduğunu görebilir. Bundan sonra, [domain] katmanının çalışır durumda olduğunu varsayacağız.

1.4.5. Sonuç

Şu üç katmanlı web uygulamasını oluşturmak istediğimizi hatırlayalım:

Uygulamamızın M modeli MVC artık yazılmış ve test edilmiştir. Bu model bize iki dosyada sunulmaktadır: DLL ve [webarticles-dao.dll, webarticles-domain.dll]. Artık son katmana, yani C denetleyicisini ve V görünümlerini içeren [web] katmanına geçebiliriz. Öncelikle, [Développement WEB avec ASP.NET 1.1 ] belgesinde sunulan bir yöntemi ele alacağız

  • C denetleyicisi, iki dosya tarafından sağlanır: [global.asax, main.aspx]
  • V görünümleri ise aspx sayfaları tarafından sağlanmaktadır

1.5. [web] katmanı

Web uygulamasının MVC mimarisi şu şekilde olacaktır:

M=modèle
[domain] iş sınıfları, [dao] veri erişim sınıfları ve veri kaynağı
V=vues
ASPX sayfaları
C=contrôleur
tüm HTTP istemci istekleri aşağıdaki iki denetleyiciden geçer:
global.asax: uygulamanın ilk başlatılmasıyla ilgili olayları yönetir
main.aspx: her bir müşterinin isteğini ayrı ayrı işler

1.5.1. Görünümler

Görseller, belgenin başında sunulanlarla aynıdır:

LISTE
liste.aspx
Görünümler, uygulamanın [vues] klasöründe toplanmıştır
INFOS
infos.aspx
PANIER
panier.aspx
PANIERVIDE
paniervide.aspx
ERREURS
erreurs.aspx

1.5.2. Denetleyiciler

Daha önce belirtildiği gibi, denetleyici iki unsurdan oluşacaktır:

  1. [global.asax,global.asax.vb]: esas olarak uygulamayı başlatmak ve farklı istemciler arasında paylaşılacak tüm verileri uygulamanın bağlamına yerleştirmek için kullanılır
  2. [main.aspx, main.aspx.vb]: Asıl denetleyici; istemcilerin HTTP isteklerini işleyen bileşendir.

Müşterilerin farklı istekleri [main.aspx] denetleyicisine yönlendirilecek ve müşterinin talep ettiği eylemi belirten [action] adlı bir parametre içerecektir:

istek
anlam
denetleyicinin eylemi
olası yanıtlar
action=liste
müşteri şunların listesini istiyor
ürünlerin listesini
- iş katmanından ürün listesini talep ediyor
katmanından
katmanından ürün listesini talep ediyor
- [ERREURS]
action=infos
Müşteri,
görünümde görüntülenen
görüntülenen ürünlerden biri hakkında
[LISTE]
- iş katmanından ürünü talep eder
- [INFOS]
- [ERREURS]
action=achat
müşteri bir ürün satın alır
- iş katmanından ürünü talep eder
ve ürünü müşterinin sepetine ekler
- [INFOS] (miktar hatası varsa)
- [LISTE] hata yoksa
action=retirerachat
müşteri sepetinden bir
sepetinden bir ürünü silmek istiyor
- oturumdaki sepeti alır
ve değiştirir
- [PANIER]
- [PANIERVIDE]
- [ERREURS]
action=panier
müşteri,
sepetini
- oturumdan alışveriş sepetini alır
- [PANIER]
- [PANIERVIDE]
- [ERREURS]
action=validationpanier
müşteri alışverişini tamamladı
ve ödeme aşamasına geçiyor
- satın alınan ürünlerin stok bilgilerini
satın alınan ürünlerin stokları güncellenir
- satın alımı onaylanan ürünlerin
silinir
- [LISTE]
- [ERREURS]

1.5.3. Uygulamanın yapılandırılması

Uygulamayı, aşağıdaki gibi değişikliklere karşı olabildiğince esnek olacak şekilde yapılandırmaya çalışacağız:

  1. farklı görünümlerin URL'lerinin değiştirilmesi
  2. [IArticlesDao] ve [IArticlesDomain] arayüzlerini uygulayan sınıfların değiştirilmesi
  3. SGBD, veritabanı ve ürün tablosundaki değişiklikler

1.5.3.1. URL değişiklikleri

URL görünümlerinin adları, diğer bazı parametrelerle birlikte [web.config] uygulama yapılandırma dosyasına eklenecektir:

<?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. Arayüzlerin uygulama sınıflarındaki değişiklik

Üç katmanlı mimarilerde, katmanlar birbirinden bağımsız olmalıdır. Bu bağımsızlık şu şekilde sağlanır:

  • katmanlar, somut sınıflar aracılığıyla değil, arayüzler aracılığıyla birbirleriyle iletişim kurar
  • bir katmanın kodu, kullanmak amacıyla asla başka bir katmanın sınıfını kendisi örneklendirmez. Sadece kullanmak istediği katmanın arayüzünün bir uygulama örneğini harici bir araçtan (burada Spring) ister. Bunun için, uygulama sınıfının adını bilmesine gerek olmadığını, sadece referansını almak istediği Spring singleton'unun adını bilmesi yeterli olduğunu biliyoruz.

Uygulamamızda Spring, web uygulamasının [web.config] dosyasında şu şekilde yapılandırılacaktır:

<?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] katmanına erişmek için, [web] katmanındaki bir sınıf, [articlesDomain] singletonunu talep edebilir. Spring, bu durumda [istia.st.articles.domain.AchatsArticles] türünde bir nesne oluşturacaktır. Bu örneklendirme için, [articlesDao] türünde bir nesneye, yani [istia.st.articles.dao.ArticlesDaoArrayList] türünde bir nesneye ihtiyaç duyar. Spring daha sonra böyle bir nesne oluşturacaktır. İşlemin sonunda, [articlesDomain] singletonunu talep eden [web] katmanı, kendisini veri kaynağına bağlayan tüm zincire sahip olacaktır:

1.5.3.3. SGBD veya veritabanıyla ilgili değişiklikler

SGBD'in bulunmadığı bir test uygulamasında olduğumuz için bu konu burada göz ardı edilecektir. İkinci aşamada, SGBD'e dayanan bir [dao] katmanının uygulanmasını ele alacağız.

1.5.4. <asp:> etiket kütüphanesi

Hata listesini görüntüleyen [ERREURS] görünümünü ele alalım:

Image

[ERREURS] görünümü, [main.aspx] denetleyicisinin istek bağlamına [context.Items("erreurs")] adıyla yerleştirdiği hata listesini görüntülemekle görevlidir. Böyle bir sayfayı yazmanın birkaç yolu vardır. Burada sadece hataların görüntülenmesi kısmıyla ilgileniyoruz.

Hatırlayalım ki, bir ASPX sayfası, bir HTML sunum bölümü ve sunum bölümünün görüntülemesi gereken verileri hazırlayan bir .NET kod bölümünden oluşur. Bu iki bölüm, aynı [aspx] dosyasında (WebMatrix çözümü) veya iki ayrı dosyada bulunabilir: sunum için [aspx], kod için [aspx.vb]. İkinci çözüm, Visual Studio’da kullanılan çözümdür. İşleri daha da karmaşık hale getiren bir diğer husus ise, HTML sunum bölümünün de .NET kodunu içerebilmesidir; bu durum, [contrôleur] ve [présentation] arasındaki ayrımı bulanıklaştırma eğilimindedir. Bu çözüm genellikle kesinlikle tavsiye edilmez. [présentation] bölümündeki tüm kodu kaldırmak için etiket kütüphaneleri oluşturulması gerekmiştir. Bu kütüphaneler, kodu HTML etiketlerine benzer etiketler şeklinde “gizler”. [ERREURS] sayfası için iki olası çözüm sunuyoruz.

İlk çözümümüzde, sayfanın [présentation] bölümünde .NET kodu kullanılmaktadır. ASPX sayfası, [erreurs.aspx.vb] denetleyici bölümünde istek içindeki hata listesini alır:

        Protected erreurs As ArrayList

        Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
...
             ' hatalar alınır
            erreurs = CType(context.Items("erreurs"), ArrayList)
        End Sub

ve ardından [présentation, erreurs.aspx] bölümünde görüntüler:

                <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>

İkinci çözüm, ASP.NET'in <asp:> etiket kütüphanesindeki <asp:repeater> etiketini kullanır. ASPX sayfasını grafiksel olarak oluşturursak, bu etiket tasarım formuna sürüklenebilen bir sunucu bileşeni olarak kullanılabilir. ASPX kodunu elle yazarsak, buna etiket kütüphanesi denebilir.

<asp:> etiket kütüphanesi kullanıldığında, önceki [ERREURS] görünümündeki ASPX kodu şu şekilde olur:

        <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>

Etiket

        <asp:Repeater id="rptErreurs" runat="server">

etiketi, bir veri kaynağındaki farklı öğeler üzerinde HTML desenini tekrarlamak için kullanılır. Etiketin farklı öğeleri şunlardır:

HeaderTemplate
veri kaynağındaki öğeler görüntülenmeden önce gösterilecek HTML deseni
ItemTemplate
veri kaynağındaki her bir öğe için tekrarlanacak HTML deseni. [<%# Container.DataItem %>] ifadesi, veri kaynağındaki geçerli öğenin değerini görüntülemek için kullanılır
FooterTemplate
HTML kalıbı, veri kaynağındaki öğeler görüntülendikten sonra görüntülenmelidir

Veri kaynağı genellikle sayfanın [contrôleur] bölümünde etiketle ilişkilendirilir:

        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
..
             ' hataları rptErreurs ile ilişkilendiriliyor
            With rptErreurs
                .DataSource = context.Items("erreurs")
                .DataBind()
            End With
        End Sub

Veri kaynağı önceden biliniyorsa (örneğin mevcut bir veritabanı), bu bağlantı sayfa tasarımı aşamasında da kurulabilir.

Görünümlerimizde, bir veri kaynağını tablo biçiminde görüntülemeye olanak tanıyan başka bir etiket kullanacağız: <asp:datagrid>.

1.5.5. [webarticles] uygulamasının Visual Studio çözüm yapısı

Bir web uygulaması, çok sayıda öğeden oluşan bir yapbozdur. Uygulamaya bir mimari kazandırmak genellikle bu öğelerin sayısını artırır. MVC altında yer alan [webarticles] uygulamasının yapısı şu şekildedir:

  

Açıklamalar:

  • [web] projesi, mantıken beklenebileceği gibi [Application web ASP.NET] türü değil, [bibliothèque de classes] türündedir. [Application web ASP.NET] türü, geliştirme makinesinde veya uzak bir makinede IIS web sunucusunun bulunmasını gerektirir. IIS sunucusu, Windows XP Aile Sürümü makinelerde standart olarak bulunmaz. Oysa birçok PC, bu sürümle birlikte satılmaktadır. Windows XP kullanan okuyucuların incelenen uygulamayı çalıştırabilmelerini sağlamak amacıyla, Microsoft'tan ücretsiz olarak temin edilebilen Cassini Web sunucusunu (bkz. ek) kullanacağız ve [Application web ASP.NET] projesini bir [bibliothèque de classes] projesiyle değiştireceğiz. Bu durum, eklerde açıklanan bazı dezavantajlara yol açmaktadır.
  • Uygulama tarafından kullanılan DLL dosyaları şunlardır:
webarticles-dao.dll
veri erişim katmanındaki sınıfları bir araya getirir
webarticles-domain.dll
iş mantığı katmanındaki sınıfları bir araya getirir
Spring.Core.dll
web, domain ve DAO katmanlarını entegre etmemizi sağlayan Spring sınıflarını içerir
log4net.dll
günlük sınıfları - Spring tarafından kullanılır

Bu DLL dosyaları, [bin] klasörüne yerleştirilir ve proje referanslarına eklenir.

1.5.6. ASPX görünümleri

Daha önce önerildiği gibi, ASPX görünümlerimizde <asp:> etiket kütüphanesini kullanacağız.

1.5.6.1. [entete.ascx] kullanıcı bileşeni

Farklı görünümler arasında bir tutarlılık sağlamak amacıyla, bu görünümler uygulama adını ve menüyü gösteren aynı başlığı paylaşacaktır:

Menü dinamiktir ve denetleyici tarafından belirlenir. Denetleyici, ASPX sayfasına iletilen isteğe, değeri Hashtable() türünde bir dizi olan "actions" anahtar özniteliğini ekler. Bu dizinin her bir elemanı, başlıktaki menü seçeneklerinden birini oluşturmaya yarayan bir sözlüktür. Her sözlük iki anahtara sahiptir:

  • href: menü seçeneğiyle ilişkili URL
  • link: menü metni

Başlığı bir kullanıcı denetimi haline getireceğiz. Bir kullanıcı denetimi, sayfanın bir bölümünü (görünüm ve ilgili kod) daha sonra diğer sayfalarda yeniden kullanılabilen bir bileşene sığdırır. Burada, [entete] bileşenini uygulamanın diğer görünümlerinde yeniden kullanmak istiyoruz. Görünüm kodu [entete.ascx]'te, ilgili kontrol kodu ise [entete.ascx.vb]'te yer alacaktır. Görünüm kodu, menü seçenekleri tablosunu görüntülemek için bir <asp:repeater> bileşeni kullanacaktır:

type
nom
rôle
1
tekrarlayıcı
rptMenu
veri kaynağı: iki anahtarlı bir sözlük tablosu
iki anahtarlı: href, bağlantı
menü seçeneklerini görüntüle

Sayfanın görüntüleme kodu şu şekilde olacaktır:

<%@ Control codebehind="entete.ascx.vb" Language="vb" autoeventwireup="false" inherits="istia.st.articles.web.EnteteWebArticles" %>
        <table>
            <tr>
                <td>
                    <h2>Magasin virtuel</h2></td>
                <asp:Repeater id="rptMenu" runat="server">
                    <ItemTemplate>
                        <td>
                            |<a href='<%# Container.DataItem("href") %>'>
                                <%# Container.DataItem("bağlantı") %>
                            </a>
                        </td>
                    </ItemTemplate>
                </asp:Repeater>
            </tr>
        </table>
        <hr>

Yorumlar:

  • [repeater] bileşeni 6-14. satırlarda tanımlanmıştır
  • tekrarlayıcıyla ilişkili veri kaynağındaki her bir öğe, iki anahtarlı bir sözlükten oluşur: href - 9. satır ve link - 10. satır

İlgili kontrol kodu şu şekilde olacaktır:

Namespace istia.st.articles.web
    Public Class EnteteWebArticles
        Inherits System.Web.UI.UserControl

        Protected WithEvents rptMenu As System.Web.UI.WebControls.Repeater

        Public WriteOnly Property actions() As Hashtable()
            Set(ByVal Value As Hashtable())
                ' eylem tablosu, ilgili bileşene atanır
                With rptMenu
                    .DataSource = Value
                    .DataBind()
                End With
            End Set
        End Property
    End Class
End Namespace

Açıklamalar:

  • [EnteteWebArticles] türündeki bileşen, 7. satırda yer alan, yazma erişimi olan [actions] adlı bir genel özelliğe sahiptir
  • Bu özellik, [rptMenu] adlı <asp:repeater> bileşenine (satır 10) uygulama denetleyicisi tarafından hesaplanan seçenekler tablosunu (satır 11-12) atamaya olanak tanır.

Uygulamanın diğer görünümleri, [entete.ascx] tarafından tanımlanan başlığı kullanacaktır. Örneğin, [erreurs.aspx] sayfası, aşağıdaki kod yardımıyla bu başlığı dahil edecektir:

<%@ Register TagPrefix="WA" TagName="entete" Src="entete.ascx" %>
<%@ Page inherits="istia.st.articles.web.ErreursWebarticles" autoeventwireup="false" Language="vb" %>
<HTML>
    <HEAD>
        <TITLE>webarticles</TITLE>
        <META http-equiv="Content-Type" content="text/html; charset=windows-1252">
    </HEAD>
    <body>
        <WA:entete id="entete" runat="server"></WA:entete>
        <h3>Les erreurs suivantes se sont produites :
        </h3>    

Açıklamalar:

  • 1. satır, <WA:entete> etiketinin [entete.ascx] dosyası ile tanımlanan bileşene eşleştirilmesi gerektiğini belirtir. [TagPrefix] ve [TagName] öznitelikleri serbesttir.
  • Bu işlem tamamlandıktan sonra, bileşenin sayfanın sunum koduna eklenmesi 9. satırla gerçekleştirilir. Çalıştırma sırasında bu etiket, onu içeren ASPX sayfasının koduna, [entete.ascx] sayfasının kodunu dahil edecektir. [erreurs.aspx.vb] kontrol kodu, bu bileşeni başlatacaktır. Bunu şu şekilde yapabilir:
    Public Class ErreursWebarticles
        Inherits System.Web.UI.Page

         ' sayfanın bileşenleri
...
        Protected WithEvents entete As New EnteteWebArticles

        Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
...
             ' menü seçenekleri rptmenu ile ilişkilendirilir
            entete.actions = CType(context.Items("options"), Hashtable())
...
        End Sub
    End Class

Açıklamalar:

  • 6. satır, oluşturulan bileşenin türü olan [EnteteWebArticles] türünde bir nesne oluşturur
  • 11. satır, bu nesnenin [actions] özelliğini başlatır

1.5.6.2. [liste.aspx] görünümü

1.5.6.2.1. Introduction

Bu görünüm, satışa sunulan ürünlerin listesini gösterir:

Bu görünüm, /main?action=liste veya /main?action=validationpanier sorgusunun ardından görüntülenir. Denetleyicinin sorgu öğeleri şunlardır:

actions
Hashtable() nesnesi - menü seçenekleri tablosu
listarticles
ArrayList [Article] türündeki nesneler
message
String nesnesi - sayfanın altında görüntülenecek mesaj

Makaleler tablosundaki (HTML) her bir bağlantı ([Infos]), URL biçiminde bir [?action=infos&id=ID] değerine sahiptir; burada ID, görüntülenen makalenin id alanıdır.

1.5.6.2.2. Sayfanın bileşenleri
type
nom
rôle
1
kullanıcı bileşeni
başlık
başlığı göster
2
DataGrid
DataGridArticles
3 - ilgili sütun: başlık: Ad, alan: ad
4 - ilgili sütun: başlık: Fiyat, alan: fiyat
5 - köprü sütunu: metin: Bilgiler, URL alanı: id,
URL biçimi: /webarticles/main.aspx?action=infos&id={0}
satıştaki ürünleri göster
6
etiket
lblMessage
mesajı görüntüle

Bu özellikleri tanımlamak için izlenecek adımları hatırlayalım:

  • Visual Studio'da, [DataGrid] öğesini seçerek özellikler sayfasına erişin:

Image

  • Yukarıdaki [Mise en forme automatique] bağlantısını kullanarak görüntülenen tablonun biçimini yönetebiliriz
  • ve içeriğini yönetmek için [Générateur de propriétés] bağlantısını kullanın
1.5.6.2.3. Görselleştirme kodu [liste.aspx]
<%@ Page codebehind="liste.aspx.vb" inherits="istia.st.articles.web.ListeWebarticles" autoeventwireup="false" Language="vb" %>
<%@ Register TagPrefix="WA" TagName="entete" Src="entete.ascx"%>
<HTML>
    <HEAD>
        <TITLE>webarticles</TITLE>
        <META http-equiv="Content-Type" content="text/html; charset=windows-1252">
    </HEAD>
    <body>
        <WA:entete id="entete" runat="server"></WA:entete>
        <h2>Liste des articles</h2>
        <P>
            <asp:DataGrid id="DataGridArticles" runat="server" ForeColor="Black" BackColor="LightGoldenrodYellow"
                BorderColor="Tan" CellPadding="2" BorderWidth="1px" GridLines="None" AutoGenerateColumns="False">
                <SelectedItemStyle ForeColor="GhostWhite" BackColor="DarkSlateBlue"></SelectedItemStyle>
                <AlternatingItemStyle BackColor="PaleGoldenrod"></AlternatingItemStyle>
                <HeaderStyle Font-Bold="True" BackColor="Tan"></HeaderStyle>
                <FooterStyle BackColor="Tan"></FooterStyle>
                <Columns>
                    <asp:BoundColumn DataField="nom" HeaderText="Nom"></asp:BoundColumn>
                    <asp:BoundColumn DataField="prix" HeaderText="Prix" DataFormatString="{0:C}"></asp:BoundColumn>
                    <asp:HyperLinkColumn Text="Infos" DataNavigateUrlField="id" DataNavigateUrlFormatString="/webarticles/main.aspx?action=infos&amp;id={0}"></asp:HyperLinkColumn>
                </Columns>
                <PagerStyle HorizontalAlign="Center" ForeColor="DarkSlateBlue" BackColor="PaleGoldenrod"></PagerStyle>
            </asp:DataGrid></P>
        <P>
            <asp:Label id="lblMessage" runat="server" BackColor="#FFC080"></asp:Label></P>
    </body>
</HTML>

Açıklamalar:

  • 9. satır sayfanın başlığını tanımlar
  • 12-24. satırlar, [DataGrid]'in özelliklerini tanımlar
  • 26. satır, [lblMessage] etiketini tanımlar
1.5.6.2.4. Denetleyici kodu [liste.aspx.vb]
Imports System
Imports System.Collections
Imports System.Data
Imports istia.st.articles.dao

Namespace istia.st.articles.web

     ' ürün listesinin görüntülenme sayfasını yönetir
    Public Class ListeWebarticles
        Inherits System.Web.UI.Page

         ' sayfanın bileşenleri
        Protected WithEvents lblMessage As System.Web.UI.WebControls.Label
        Protected WithEvents DataGridArticles As System.Web.UI.WebControls.DataGrid
        Protected WithEvents entete As New EnteteWebArticles

        Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
             ' bağlam bilgilerine göre [liste] görünümünü hazırlar
             ' menü seçenekleri rptmenu ile ilişkilendirilir
            entete.actions = CType(context.Items("options"), Hashtable())
             ' makaleler bir veri tablosuna alınır
            Dim articles As ArrayList = CType(context.Items("articles"), ArrayList)
             ' bunlar sayfanın [DataGrid] bileşenine bağlanıyor
            With DataGridArticles
                .DataSource = articles
                .DataBind()
            End With
             ' mesaj görüntülenir
            lblMessage.Text = context.Items("message").ToString
        End Sub
    End Class
End Namespace

Açıklamalar:

  • Sayfanın bileşenleri 13-15. satırlarda yer almaktadır. Diğer bileşenlerde buna gerek kalmazken, burada [new] operatörü ile [EnteteWebArticles] nesnesini oluşturmamız gerektiği unutulmamalıdır. Bu nesne açıkça oluşturulmasaydı, [entete] nesnesinin hiçbir şeye referans vermediğini belirten bir yürütme hatası alınıyordu. Bu konunun daha ayrıntılı incelenmesi gerekirdi. Ancak incelenmemiştir.
  • sayfanın [entete] bileşenini başlatmak için başlık menüsünün seçenek tablosu bağlamdan alınır - 20. satır
  • ürün listesi, [entete] bileşenini başlatmak için bağlamdan alınır – satır 22
  • [DataGridArticles] bileşenini başlatmak için - satır 24-27
  • [lblMessage] bileşeni, bağlama yerleştirilen bir mesajla başlatılır - satır 29

1.5.6.3. [infos.aspx] görünümü

1.5.6.3.1. Introduction

Bu sayfa, bir ürünle ilgili bilgileri gösterir ve ürünün satın alınmasına da olanak tanır:

Image

Bu sayfa, /main?action=infos&id=ID isteği veya satın alınan miktar hatalı olduğunda /main?action=achat&id=ID isteği sonrasında görüntülenir. Denetleyicinin isteğindeki öğeler şunlardır:

actions
Hashtable() nesnesi - menü seçenekleri tablosu
article
[Article] türü nesne - görüntülenecek ürün
msg
String nesnesi - miktar hatası durumunda görüntülenecek mesaj
qte
String nesnesi - giriş alanında görüntülenecek değer [Qte]

[msg] ve [qte] alanları, miktarda giriş hatası olması durumunda kullanılır:

Image

Bu sayfa, [Acheter] düğmesi ile gönderilen bir form içerir. URL'in hedefi POST'tir; [?action=achat&id=ID] ise satın alınan ürünün kimliği olan ID'tir.

1.5.6.3.2. Sayfanın bileşenleri
type
nom
rôle
1
kullanıcı bileşeni
başlık
başlığı göster
2
sabit
litID
ürün numarasını göster
3 à 6
DataGrid
DataGridArticle
3 - ilgili sütun: başlık: Ad, alan: ad
4 - ilişkili sütun: başlık: Fiyat, alan: fiyat
5 - ilişkili sütun: başlık: Mevcut stok, alan: stockActuel
6 - ilişkili sütun: başlık: Minimum stok, alan: stockMinimum
bir ürünü görüntüle
7
HTML Gönder
 
formu gönder
8
HTML Giriş
runat=sunucu
txtQte
satın alınan miktarı girin
9
etiket
lblMsgQte
olası hata mesajı
1.5.6.3.3. Görüntüleme kodu [infos.aspx]
<%@ Register TagPrefix="WA" TagName="entete" Src="entete.ascx" %>
<%@ Page codebehind="infos.aspx.vb" inherits="istia.st.articles.web.InfosWebarticles" autoeventwireup="false" Language="vb" %>
<HTML>
    <HEAD>
        <TITLE>webarticles</TITLE>
        <META http-equiv="Content-Type" content="text/html; charset=windows-1252">
    </HEAD>
    <body>
        <WA:entete id="entete" runat="server"></WA:entete>
        <h2>Article d'id [<asp:Literal id="litId" runat="server"></asp:Literal>]</h2>
        <P>
            <asp:DataGrid id="DataGridArticle" runat="server" BackColor="White" BorderColor="#E7E7FF" CellPadding="3"
                BorderWidth="1px" BorderStyle="None" GridLines="Horizontal" AutoGenerateColumns="False">
                <SelectedItemStyle Font-Bold="True" ForeColor="#F7F7F7" BackColor="#738A9C"></SelectedItemStyle>
                <AlternatingItemStyle BackColor="#F7F7F7"></AlternatingItemStyle>
                <ItemStyle HorizontalAlign="Center" ForeColor="#4A3C8C" BackColor="#E7E7FF"></ItemStyle>
                <HeaderStyle Font-Bold="True" HorizontalAlign="Center" ForeColor="#F7F7F7" BackColor="#4A3C8C"></HeaderStyle>
                <FooterStyle ForeColor="#4A3C8C" BackColor="#B5C7DE"></FooterStyle>
                <Columns>
                    <asp:BoundColumn DataField="nom" HeaderText="Nom">
                        <HeaderStyle HorizontalAlign="Center"></HeaderStyle>
                    </asp:BoundColumn>
                    <asp:BoundColumn DataField="prix" HeaderText="Prix" DataFormatString="{0:C}">
                        <HeaderStyle HorizontalAlign="Center"></HeaderStyle>
                    </asp:BoundColumn>
                    <asp:BoundColumn DataField="stockactuel" HeaderText="Stock actuel">
                        <HeaderStyle HorizontalAlign="Center"></HeaderStyle>
                    </asp:BoundColumn>
                    <asp:BoundColumn DataField="stockminimum" HeaderText="Stock minimum">
                        <HeaderStyle HorizontalAlign="Center"></HeaderStyle>
                    </asp:BoundColumn>
                </Columns>
                <PagerStyle HorizontalAlign="Right" ForeColor="#4A3C8C" BackColor="#E7E7FF" Mode="NumericPages"></PagerStyle>
            </asp:DataGrid></P>
        <HR width="100%" SIZE="1">
        <form method="post" action="<%=strAction%>">
            <table>
                <tr>
                    <td><input type="submit" value="Acheter"></td>
                    <td>Qté</td>
                    <td><INPUT type="text" maxLength="3" size="3" id="txtQte" runat="server"></td>
                    <td><asp:Label id="lblMsgQte" runat="server" />
                    </td>
                </tr>
            </table>
        </form>
    </body>
</HTML>

Yorumlar:

  • başlık sayfaya dahil edilmiştir - 9. satır
  • [litId] sabiti 10. satırda tanımlanmıştır
  • DataGrid ve [DataGridArticles], 12-34. satırlarda tanımlanmıştır
  • form, 36-46. satırlarda tanımlanmıştır. Türü POST'tir.
  • POST'in hedefi, [strAction] değişkeni tarafından sağlanır - 36. satır. Bu değişken, denetleyici tarafından tanımlanmalıdır.
  • Satın alınan miktar giriş alanı 41. satırda tanımlanmıştır. Bu, bir HTML sunucu bileşenidir (runat=server). Kod tarafında, bu alana bir nesne aracılığıyla erişilir.
  • 42. satır, girilen miktarla ilgili olası bir hata mesajını içerecek olan [lblMsgQte] etiketini tanımlar
1.5.6.3.4. [infos.aspx.vb] kontrol kodu
Imports istia.st.articles.dao
Imports System
Imports System.Collections

Namespace istia.st.articles.web

     ' bir makaleye ait bilgi sayfasını yönetir
    Public Class InfosWebarticles
        Inherits System.Web.UI.Page
        Protected WithEvents lblMsgQte As System.Web.UI.WebControls.Label
        Protected WithEvents litId As System.Web.UI.WebControls.Literal
        Protected WithEvents txtQte As System.Web.UI.HtmlControls.HtmlInputText
        Protected WithEvents DataGridArticle As System.Web.UI.WebControls.DataGrid
        Protected WithEvents entete As New EnteteWebArticles

         ' formun gönderileceği URL sayfası
        Private _strAction As String
        Public Property strAction() As String
            Get
                Return _strAction
            End Get
            Set(ByVal Value As String)
                _strAction = Value
            End Set
        End Property

         ' sayfa görüntüleme
        Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
             ' istek bilgilerini alır
            Dim unArticle As Article = CType(Session.Item("article"), Article)
             ' menü seçeneklerini rptmenu'ye bağlama
            entete.actions = CType(context.Items("options"), Hashtable())
             ' makaleyi [DataGrid] ile ilişkilendirme
            Dim articles As New ArrayList
            articles.Add(unArticle)
            With DataGridArticle
                .DataSource = articles
                .DataBind()
            End With
             ' etiket kimliği
            litId.Text = unArticle.id.ToString
             ' hata mesajı
            lblMsgQte.Text = context.Items("msg").ToString
             ' önceki miktar
            txtQte.Value = context.Items("qte").ToString
             ' eylem
            strAction = "?action=achat&id=" + unArticle.id.ToString
        End Sub
End Namespace

Açıklamalar:

  • Sayfanın bileşenleri 10-14. satırlarda tanımlanmıştır
  • Sınıf, formdaki POST öğesinin hedefini tanımlamak için kullanılan [strAction] adlı bir genel özellik tanımlar - 17-25. satırlar
  • Görüntülenecek makale, uygulama bağlamından alınır - satır 30
  • başlık menüsünün seçenek tablosu, sayfanın [entete] bileşenini başlatmak için bağlamdan alınır - satır 32
  • 33-39. satırlar: [DataGridArticle] bileşeni, yalnızca 30. satırda alınan ürünü içeren [ArrayList] türündeki bir veri kaynağına bağlanır
  • [lblMsgQte, txtQte] bileşenleri, bağlamdan alınan bilgilerle başlatılır - satır 42-45
  • [straction] özelliği de bağlamdan alınan bir bilgiyle başlatılır – satır 47. Bu değişken, sayfada bulunan HTML formunun [action] özniteliğini oluşturmak için kullanılır:
        <form method="post" action="<%=strAction%>">
....
        </form>

1.5.6.4. [panier.aspx] görünümü

1.5.6.4.1. Introduction

Bu görünüm, sepetin içeriğini gösterir:

Image

Bu görünüm, /main?action=panier veya /main?action=retirerachat&id=ID isteği sonrasında görüntülenir. Denetleyicinin isteğindeki öğeler şunlardır:

actions
Hashtable() nesnesi - menü seçenekleri tablosu
panier
[Panier] türü nesne - görüntülenecek alışveriş sepeti

Sepetteki satın alma işlemlerinin HTML tablosundaki her bir [Retirer] bağlantısı, URL biçiminde bir [?action=retirerachat&id=ID]'e sahiptir; burada ID, sepetten çıkarılmak istenen ürünün [id] alanıdır.

1.5.6.4.2. Sayfanın bileşenleri
type
nom
rôle
1
kullanıcı bileşeni
başlık
başlığı göster
2
DataGrid
DataGridAchats
3- ilgili sütun - başlık: Ürün, alan: ad
4 - ilişkili sütun - başlık: Adet, alan: adet
5 - ilişkili sütun - başlık: Fiyat, alan: fiyat
6 - ilişkili sütun - başlık: Toplam, alan: toplam, biçimlendirme {0:C}
7 - köprü sütunu - Metin: İade, URL: id, URL biçimi: /webarticles/main.aspx?action=retirerachat&id={0}
satın alınan ürünlerin listesini göster
8
etiket
lblTotal
ödenecek tutarı göster
1.5.6.4.3. Görüntüleme kodu [panier.aspx]
<%@ Page codebehind="panier.aspx.vb" inherits="istia.st.articles.web.PanierWebarticles" autoeventwireup="false" Language="vb" %>
<%@ Register TagPrefix="WA" TagName="entete" Src="entete.ascx" %>
<HTML>
    <HEAD>
        <TITLE>webarticles</TITLE>
        <META http-equiv="Content-Type" content="text/html; charset=windows-1252">
    </HEAD>
    <body>
        <WA:entete id="entete" runat="server"></WA:entete>
        <h2>Contenu de votre panier</h2>
        <P>
            <asp:DataGrid id="DataGridAchats" runat="server" BorderWidth="1px" GridLines="Vertical" CellPadding="4"
                BackColor="White" BorderStyle="None" BorderColor="#DEDFDE" ForeColor="Black" AutoGenerateColumns="False">
                <SelectedItemStyle Font-Bold="True" ForeColor="White" BackColor="#CE5D5A"></SelectedItemStyle>
                <AlternatingItemStyle BackColor="White"></AlternatingItemStyle>
                <ItemStyle BackColor="#F7F7DE"></ItemStyle>
                <HeaderStyle Font-Bold="True" ForeColor="White" BackColor="#6B696B"></HeaderStyle>
                <FooterStyle BackColor="#CCCC99"></FooterStyle>
                <Columns>
                    <asp:BoundColumn DataField="nom" HeaderText="Article"></asp:BoundColumn>
                    <asp:BoundColumn DataField="qte" HeaderText="Qt&#233;"></asp:BoundColumn>
                    <asp:BoundColumn DataField="prix" HeaderText="Prix"></asp:BoundColumn>
                    <asp:BoundColumn DataField="totalAchat" HeaderText="Total" DataFormatString="{0:C}"></asp:BoundColumn>
                    <asp:HyperLinkColumn Text="Retirer" DataNavigateUrlField="id" DataNavigateUrlFormatString="/webarticles/main.aspx?action=retirerachat&amp;id={0}"></asp:HyperLinkColumn>
                </Columns>
                <PagerStyle HorizontalAlign="Right" ForeColor="Black" BackColor="#F7F7DE" Mode="NumericPages"></PagerStyle>
            </asp:DataGrid></P>
        <P>Total de la commande :
            <asp:Label id="lblTotal" runat="server"></asp:Label>&nbsp;euros</P>
    </body>
</HTML>

Açıklamalar

  • 9. satır başlığı içerir
  • 12-27. satırlarda, [DataGridAchats] bileşeni tanımlanmıştır
  • 29. satırda, [lblTotal] bileşeni tanımlanmıştır
1.5.6.4.4. [panier.aspx.vb] kontrol kodu
Imports System
Imports System.Collections
Imports System.Data
Imports istia.st.articles.dao
Imports istia.st.articles.domain

Namespace istia.st.articles.web
     ' sepet görüntüleme sayfasını yönetir
    Public Class PanierWebarticles
        Inherits System.Web.UI.Page
        Protected WithEvents DataGridAchats As System.Web.UI.WebControls.DataGrid
        Protected WithEvents lblTotal As System.Web.UI.WebControls.Label
        Protected WithEvents entete As New EnteteWebArticles

        Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
             ' menü seçeneklerini rptmenu'ye bağlar
            entete.actions = CType(context.Items("options"), Hashtable())
             ' sepeti alır
            Dim unPanier As Panier = CType(Session.Item("panier"), Panier)
             ' satın alımları bir satın alma satırları tablosuna aktarır
            Dim achats(unPanier.achats.Count - 1) As LigneAchat
             ' ArrayList öğelerinin türünü değiştirir
            For i As Integer = 0 To achats.Length - 1
                achats(i) = New LigneAchat(CType(unPanier.achats(i), Achat))
            Next
             ' verileri sayfanın [DataGrid] bileşenlerine bağlanıyor
            With DataGridAchats
                .DataSource = achats
                .DataBind()
            End With
             ' ödenecek toplam tutar görüntülenir
            lblTotal.Text = unPanier.totalPanier.ToString
        End Sub

         ' Satın Alma nesnesinden oluşturulan satın alma satırı
        Private Class LigneAchat
            Inherits Achat

             ' oluşturucu bir satın alma alır
            Public Sub New(ByVal unAchat As Achat)
                Me.article = unAchat.article
                Me.qte = unAchat.qte
            End Sub

             ' id: satın alınan ürünün kimliğini döndürür
            Public ReadOnly Property id() As Integer
                Get
                    Return article.id
                End Get
            End Property

             ' ad: satın alınan ürünün adı
            Public ReadOnly Property nom() As String
                Get
                    Return article.nom
                End Get
            End Property

             ' satın alınan ürünün fiyatı
            Public ReadOnly Property prix() As Double
                Get
                    Return article.prix
                End Get
            End Property

        End Class
    End Class
End Namespace

Açıklamalar:

  • Sayfanın bileşenleri 11-13. satırlarda tanımlanmıştır
  • [entete] bileşeninin başlatılması, daha önce incelenen sayfalardakiyle aynıdır - satır 17
  • Görüntülenecek alışveriş sepeti oturumdan alınır - 19. satır
  • [DataGridAchats] bileşeni kullanılarak bu sepetin görüntülenmesi sorunlara yol açmaktadır. Sorun, bileşenin başlatılmasından kaynaklanmaktadır. Bileşenin sütunlarını hatırlayalım:
    • [Article] sütunu, veri kaynağındaki [nom] alanıyla ilişkilidir
    • [Qté] sütunu, veri kaynağındaki [qte] alanıyla ilişkilidir
    • [Prix] sütunu, veri kaynağındaki [prix] alanıyla ilişkilidir
    • veri kaynağındaki [total] alanıyla ilişkili [Total] sütunu

Elimizdeki veri kaynağı, alışveriş sepeti ve alışveriş listesidir. Alışveriş listesi, [DataGrid]'in veri kaynağı olacaktır. Yalnızca [DataGrid]'in satırlarını dolduracak olan [Achat] nesneleri, [DataGrid] tarafından beklenen [nom, qte, prix, total] özelliklerine sahip değildir. Bu nedenle burada, özellikle [DataGrid] için, öğeleri [DataGrid] tarafından beklenen özelliklere sahip bir veri kaynağı oluşturulur. Bu öğeler, bu amaçla oluşturulan ve [Achat] sınıfından türetilen [LigneAchat] sınıfına ait olacaktır (satır 36-66)

  • [LigneAchat) sınıfı tanımlandıktan sonra, [DataGridAchats] veri kaynağı oturumda bulunan sepetten oluşturulur - satır 20-30
  • Alışveriş tutarı, [Panier] sınıfının [totalPanier] özelliği sayesinde görüntülenir - satır 32

1.5.6.5. [paniervide.aspx] görünümü

1.5.6.5.1. Introduction

Bu görünüm, sepetin boş olduğunu belirten bilgileri gösterir:

Image

Bu görünüm, /main?action=panier veya /main?action=retirerachat&id=ID sorgusunun ardından görüntülenir. Denetleyicinin sorgu öğeleri şunlardır:

actions
Hashtable() nesnesi - menü seçenekleri tablosu
1.5.6.5.2. Sayfanın bileşenleri
type
nom
rôle
1
kullanıcı bileşeni
başlık
başlığı göster
1.5.6.5.3. [paniervide.aspx] sunum kodu
<%@ Register TagPrefix="WA" TagName="entete" Src="entete.ascx"%>
<%@ Page codebehind="paniervide.aspx.vb" inherits="istia.st.articles.web.PaniervideWebarticles" autoeventwireup="false" Language="vb" %>
<HTML>
    <HEAD>
        <TITLE>webarticles</TITLE>
        <META http-equiv="Content-Type" content="text/html; charset=windows-1252">
    </HEAD>
    <body>
        <WA:entete id="entete" runat="server"></WA:entete>
        <h2>Contenu de votre panier</h2>
        <P>Votre panier est vide</P>
    </body>
</HTML>

Yorumlar:

  • Başlık 9. satıra eklenmiştir
1.5.6.5.4. Denetim kodu [paniervide.aspx.vb]
Namespace istia.st.articles.web
     ' boş sepet görüntüleme sayfasını yönetir
    Public Class PaniervideWebarticles
        Inherits System.Web.UI.Page
        Protected WithEvents entete As New EnteteWebArticles

        Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
             ' bağlam bilgilerini kullanarak [paniervide] görünümünü hazırlar
             ' menü seçenekleri rptmenu ile ilişkilendiriliyor
            entete.actions = CType(context.Items("options"), Hashtable())
        End Sub
    End Class
End Namespace

Yorumlar:

  • Sayfanın tek dinamik bileşenini başlatmakla yetiniyoruz - 10. satır

1.5.6.6. [erreurs.aspx] görünümü

1.5.6.6.1. Introduction

Bu görünüm, hata durumunda görüntülenir:

Image

Bu mesaj, hataya yol açan tüm isteklerin ardından görüntülenir; ancak yanlış miktarla yapılan satın alma işlemi hariçtir; bu işlem, [INFOS] görünümü tarafından işlenir. Denetleyicinin isteğindeki öğeler şunlardır:

actions
Hashtable() nesnesi - menü seçenekleri tablosu
erreurs
ArrayList nesnesi, görüntülenecek hata mesajlarını temsil eden [String] nesneleri
1.5.6.6.2. Sayfanın bileşenleri
type
nom
rôle
1
kullanıcı bileşeni
başlık
başlığı göster
2
tekrarlayıcı
rptErreurs
hata listesini göster
1.5.6.6.3. Görüntüleme kodu [erreurs.aspx]
<%@ Register TagPrefix="WA" TagName="entete" Src="entete.ascx" %>
<%@ Page codebehind="erreurs.aspx.vb" inherits="istia.st.articles.web.ErreursWebarticles" autoeventwireup="false" Language="vb" %>
<HTML>
    <HEAD>
        <TITLE>webarticles</TITLE>
        <META http-equiv="Content-Type" content="text/html; charset=windows-1252">
    </HEAD>
    <body>
        <WA:entete id="entete" runat="server"></WA:entete>
        <h3>Les erreurs suivantes se sont produites :
        </h3>
        <ul>
            <asp:Repeater id="rptErreurs" runat="server">
                <ItemTemplate>
                    <li>
                        <%# Container.DataItem %>
                    </li>
                </ItemTemplate>
            </asp:Repeater></ul>
    </body>
</HTML>

Yorumlar:

  • Başlık 9. satırda tanımlanmıştır
  • [rptErreurs] bileşeni 13-19. satırlarda tanımlanmıştır. İçeriği, [ArrayList] türündeki bir veri kaynağından ve [String] nesnelerinden alınmaktadır.
1.5.6.6.4. Denetim kodu [erreurs.aspx.vb]
Namespace istia.st.articles.web

     ' hata sayfasını yönetir
    Public Class ErreursWebarticles
        Inherits System.Web.UI.Page

         ' sayfa bileşenleri
        Protected WithEvents rptErreurs As System.Web.UI.WebControls.Repeater
        Protected WithEvents entete As New EnteteWebArticles

        Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
             ' bağlam bilgilerine göre [erreurs] görünümünü hazırlar
             ' menü seçenekleri rptmenu ile ilişkilendiriliyor
            entete.actions = CType(context.Items("options"), Hashtable())
             ' hatlar rptErreurs'e bağlanıyor
            With rptErreurs
                .DataSource = context.Items("erreurs")
                .DataBind()
            End With
        End Sub
    End Class

End Namespace

Açıklamalar:

  • [entete] bileşeni her zamanki gibi 9. ve 14. satırlarda başlatılır
  • [rptErreurs] bileşeni, bağlamda bulunan [ArrayList] türündeki hata listesiyle başlatılır - 16-19. satırlar

1.5.7. global.asax ve main.aspx denetleyicileri

Web uygulamamızın kalbini, yani denetleyiciyi yazmamız gerekiyor. Denetleyicinin görevi şunlardır:

  • istemciden gelen isteği almak,
  • işletme sınıflarını kullanarak müşterinin talep ettiği eylemi işlemek,
  • yanıt olarak uygun görünümü göndermek.

1.5.7.1. [global.asax.vb] denetleyicisi

Uygulama ilk isteğini aldığında, [global.asax.vb] dosyasındaki [Application_Start] prosedürü çalıştırılır. Bu, tek seferlik bir işlemdir. [Application_Start] prosedürünün amacı, web uygulaması için gerekli olan ve tüm istemci iş parçacıkları tarafından salt okunur olarak paylaşılacak nesneleri başlatmaktır. Bu paylaşılan nesneler iki yere yerleştirilebilir:

  • denetleyicinin özel alanları
  • uygulamanın yürütme bağlamı (Application)

[global.asax.vb] uygulamasının [Application_Start] yöntemi aşağıdaki işlemleri gerçekleştirecektir:

  • [web.config] dosyasında, uygulamanın düzgün çalışması için gerekli parametrelerin mevcut olup olmadığını kontrol edecektir. Bu parametreler 1.5.3. paragrafında açıklanmıştır.
  • Olası hata listesini bir [ArrayList erreurs] nesnesi biçiminde uygulamanın bağlamına ekleyecektir. Hata yoksa bu liste boş olacaktır, ancak yine de mevcut olacaktır.
  • Hata varsa, [Application_Start] yöntemi burada sonlanır. Aksi takdirde, denetleyicinin ihtiyaçları için kullanacağı iş nesnesi olacak [IArticlesDomain] türünde bir singleton'un referansını ister. 1.5.3.2 bölümünde açıklandığı gibi, denetleyici bu singleton'u Spring çerçevesinden talep edecektir. Bu örneklendirme işlemi çeşitli hatalara yol açabilir. Böyle bir durumda, hatalar yine uygulama bağlamındaki [erreurs] nesnesinde saklanacaktır.

[global.asax.vb] denetleyicisi, yeni bir müşteri geldiğinde her seferinde yürütülen [Session_Start] adlı bir prosedüre sahiptir. Bu prosedürde, müşteri için boş bir sepet oluşturulur. Bu sepet, söz konusu müşterinin istekleri boyunca korunur. Kod şu şekilde olabilir:

Imports System
Imports System.Web
Imports System.Web.SessionState
Imports System.Configuration
Imports istia.st.articles.domain
Imports System.Collections
Imports Spring.Context

Namespace istia.st.articles.web

    Public Class GlobalWebArticles
        Inherits System.Web.HttpApplication

         ' uygulama başlatılıyor
        Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)

             ' yerel veriler
            Dim parameters() As String = {"urlMain", "urlErreurs", "urlInfos", "urlListe", "urlPanier", "urlPanierVide"}
            Dim erreurs As New ArrayList

             ' uygulamanın başlatma parametreleri alınır
            Dim param As String
            For i As Integer = 0 To parameters.Length - 1
                 ' yapılandırma dosyasından okuma
                param = ConfigurationSettings.AppSettings(parameters(i))
                If param Is Nothing Then
                     ' hatkayı kaydediyoruz
                    erreurs.Add("Paramètre [" + parameters(i) + "] absent dans le fichier [web.config]")
                Else
                     ' parametre uygulamada kaydediliyor
                    Application.Item(parameters(i)) = param
                End If
            Next
             ' Hata var mı?
            If erreurs.Count = 0 Then
                 ' iş katmanına erişim için IArticlesDomain nesnesi oluşturulur
                Dim contexte As IApplicationContext = CType(ConfigurationSettings.GetConfig("spring/context"), IApplicationContext)
                Dim articlesDomain As IArticlesDomain
                Try
                    articlesDomain = CType(contexte.GetObject("articlesDomain"), IArticlesDomain)
                     ' nesne uygulamada kaydedilir
                    Application.Item("articlesDomain") = articlesDomain
                Catch ex As Exception
                     ' hata kaydediliyor
                    erreurs.Add("Erreur lors de la construction de l'objet d'accès à la couche métier [" + ex.ToString + "]")
                End Try
            End If
             ' hatalar uygulamaya aktarılır
            Application.Item("erreurs") = erreurs
             ' hatalar varsa işlem tamamlanır
            If erreurs.Count <> 0 Then Return
             ' menü seçenekleri tablosu oluşturulur
            Dim options As New Hashtable
             ' denetleyiciden URL alınır
            Dim urlMain As String = CType(Application.Item("urlMain"), String)
            Dim uneOption As Hashtable
             ' ürün listesi
            uneOption = New Hashtable
            uneOption.Add("href", urlMain + "?action=liste")
            uneOption.Add("lien", "Liste des articles")
            options.Add("liste", uneOption)
             ' sepet
            uneOption = New Hashtable
            uneOption.Add("href", urlMain + "?action=panier")
            uneOption.Add("lien", "Voir le panier")
            options.Add("panier", uneOption)
             ' sepet onaylama
            uneOption = New Hashtable
            uneOption.Add("href", urlMain + "?action=validationpanier")
            uneOption.Add("lien", "Valider le panier")
            options.Add("validationpanier", uneOption)
             ' menü seçeneklerini uygulamaya eklenir
            Application.Item("options") = options
            Return
        End Sub

         ' oturum başlatma
        Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
             ' müşteri için bir alışveriş sepeti oluşturuluyor
            Session.Item("panier") = New Panier
        End Sub
    End Class
End Namespace

Açıklamalar:

  • [web.config]'te beklenen parametreler bir dizide tanımlanmıştır - 18. satır
  • bu parametreler [web.config]'te aranır. Varsa, uygulama bağlamında saklanır; yoksa [erreurs] hata listesine bir hata kaydedilir - satır 21-33
  • Hata yoksa, uygulamanın [domain] katmanına erişimi yöneten [articlesDomain] singleton'una ilişkin bir referans Spring'den istenir - satır 35-47. Olası hatalar [erreurs]'e kaydedilir.
  • Hatalar, uygulama bağlamında kaydedilir – satır 49
  • Hata oluşursa prosedürden çıkılır – satır 51
  • Üç sözlükten oluşan bir dizi oluşturulur. Her birinin iki anahtarı vardır: href ve link. Bu dizi, olası üç menü seçeneğini temsil eder - satır 52-71
  • Bu dizi, uygulama bağlamında saklanır - satır 73
  • Her yeni müşteri için [Session_Start] prosedürü yürütülür. Burada, müşterinin oturumunda boş bir sepet oluşturulur - satır 78-81

1.5.7.2. [main.aspx.vb] denetleyicisi

[main.aspx.vb] denetleyicisi, müşterilerden gelen tüm istekleri görür. Aslında bu isteklerin tümü [/webarticles/main.aspx?action=XX] biçimindedir. Bir istek şu şekilde işlenir:

  • uygulama bağlamındaki [erreurs] nesnesi kontrol edilir. Bu nesne boş değilse, bu durum uygulamanın başlatılması sırasında hatalar oluştuğu ve uygulamanın çalışamayacağı anlamına gelir. Bu durumda yanıt olarak [ERREURS] görünümü gönderilir.
  • İsteğin [action] parametresi alınacak ve kontrol edilecektir. Bilinen bir eyleme karşılık gelmiyorsa, uygun bir hata mesajıyla birlikte [ERREURS] görünümü gönderilir.
  • [action] parametresi geçerliyse, istemcinin isteği işlenmek üzere eyleme özgü bir prosedüre aktarılır:
yöntem
istek
işleme
olası yanıtlar
doListe
GET /main?action=liste
- iş sınıfına ait makalelerin listesini iste
iş sınıfından
- görüntülemek
[LISTE] veya [ERREURS]
doInfos
GET /main?action=infos&id=ID
- id=ID numaralı makaleyi
iş sınıfına
- görüntülemek
[INFOS] veya [ERREURS]
doAchat
POST /main?action=satınalma&id=ID
- satın alınan miktar, gönderilen parametreler arasında yer alır
- id=ID olan ürünü
iş sınıfına
- bunu
müşteri oturumuna
[LISTE] veya [INFOS] veya [ERREURS]
doRetirerAchat
GET /main?action=retirerachat&id=ID
- id=ID olan ürünü
müşterinin sepetindeki
müşteri oturumunun
[PANIER]
doPanier
GET /main?action=panier
- müşteri oturumunun
müşteri oturumu
[PANIER] veya [PANIERVIDE]
doValidationPanier
GET /main?action=sepetonay
- Veritabanında
sepet içinde bulunan tüm ürünlerin
azaltın
GET veya [ERREURS]
[LISTE] veya [ERREURS]

[main.aspx.vb] denetleyicisinin iskeleti şu şekilde olabilir:

Imports System.Collections
Imports System
Imports System.Data

Imports istia.st.articles.dao
Imports istia.st.articles.domain

Namespace istia.st.articles.web

     ' web uygulamasının denetleyici sınıfı
    Public Class MainWebArticles
        Inherits System.Web.UI.Page

         ' özel alanlar
        Private articlesDomain As IArticlesDomain
        Private options As Hashtable

         ' sayfanın yüklenmesi
        Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
....
        End Sub

         ' eylem işleme yöntemleri

         ' makale listesi
        Public Sub doListe()
...
        End Sub

         ' bir ürünle ilgili bilgiler
        Public Sub doInfos()
...
        End Sub

         ' bir ürünün satın alınması
        Public Sub doAchat()
...
        End Sub

         ' bir satın alma işleminin silinmesi
        Public Sub doRetirerAchat()
...
        End Sub

         ' sepeti görüntüleme
        Public Sub doPanier()
...
        End Sub

         ' sepetten satın alma
        Public Sub doValidationPanier()
...
        End Sub

    End Class

End Namespace

Açıklamalar:

  • Sınıfın, yöntemler arasında paylaşılacak iki özel alanı vardır - 15-16. satırlar:
    • articlesDomain: [domain] katmanına erişim sağlayan tekil nesne
    • seçenekler: menü seçenekleri sözlüklerinin dizisi
  • [Page_Load] yordamı:
    • sınıfın iki özel alanını başlatacaktır
    • istekten [action] parametresini alacak ve bu eylemin işleme yöntemini çalıştıracaktır.

1.5.7.3. [Page_Load] yöntemi

Bu olay, sayfada gerçekleşen ilk olaydır. Kod şu şekildedir:

         ' sayfanın yüklenmesi
        Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
             ' uygulamanın düzgün bir şekilde başlatılıp başlatılmadığını kontrol ediyoruz
            Dim erreurs As ArrayList = CType(Application.Item("erreurs"), ArrayList)
             ' hata varsa, [erreurs] görünümünü gönderilir
            If erreurs.Count <> 0 Then
                context.Items("erreurs") = erreurs
                context.Items("options") = New Hashtable() {}
                Server.Transfer(CType(Application("urlErreurs"), String))
            End If
             ' iş sınıfına erişim nesnesi alınır
            articlesDomain = CType(Application.Item("articlesDomain"), IArticlesDomain)
             ' ve menü seçenekleri alınır
            options = CType(Application.Item("options"), Hashtable)
             ' yapılması gereken eylemi alırız
            Dim action As String = Request.QueryString("action")
            If action Is Nothing Then
                action = "liste"
            End If
             ' eylemi yürütürüz
            Select Case action
                Case "liste"
                    doListe()
                Case "infos"
                    doInfos()
                Case "achat"
                    doAchat()
                Case "panier"
                    doPanier()
                Case "retirerachat"
                    doRetirerAchat()
                Case "validationpanier"
                    doValidationPanier()
                Case Else
                    doListe()
            End Select
        End Sub

Açıklamalar:

  • Sayfa her yüklendiğinde, [global.asax] tarafından yapılan uygulama başlatma işleminin başarıyla tamamlandığından emin olunur.
  • Bunun için, uygulama bağlamından [global.asax] tarafından buraya yerleştirilen hata listesi alınır - satır 4
  • Bu liste boş değilse, [ERREURS] görünümünü görüntülenir - satır 6-10
  • [global.asax] tarafından uygulama bağlamına yerleştirilen [articlesDomain] tekil nesnesini alırız ve sınıfın çeşitli yöntemleri tarafından kullanılabilmesi için [articlesDomain] özel alanına kaydederiz - satır 12
  • menü seçenekleri dizisi için de benzer bir işlem yapılır - satır 14
  • istekten [action] parametresi alınır - satır 16
  • İstenen eyleme karşılık gelen yöntemi çalıştırıyoruz. Öngörülmemiş bir eylem, [liste] eylemi olarak kabul edilir - satır 16-36

1.5.7.4. [liste] eyleminin işlenmesi

Bu, ürün listesinin görüntülenmesidir:

Image

Kod şu şekildedir:

         ' ürün listesi
        Public Sub doListe()
             ' hata yönetimi
            Dim erreurs As New ArrayList
             ' ürün listesi istenir
            Dim articles As IList
            Try
                articles = articlesDomain.getAllArticles
            Catch ex As Exception
                 ' hata kaydedilir
                erreurs.Add(ex.ToString)
            End Try
             ' Hata var mı?
            If erreurs.Count <> 0 Then
                 ' [erreurs] görünümü
                context.Items("erreurs") = erreurs
                context.Items("options") = New Hashtable() {CType(options("liste"), Hashtable)}
                Server.Transfer(CType(Application.Item("urlErreurs"), String))
            End If
             ' [liste] görünümünü görüntüleme
            context.Items("articles") = articles
            context.Items("options") = New Hashtable() {CType(options("panier"), Hashtable)}
            If context.Items("message") Is Nothing Then context.Items("message") = ""
            Server.Transfer(CType(Application.Item("urlListe"), String))
        End Sub

Açıklamalar:

  • Olası hatalar [ArrayList] dosyasına kaydedilir - 4. satır
  • ürün listesi, [articlesDomain] tekil nesnesinden istenir - satır 5-12
  • Hata varsa, [ERREURS] görünümü gönderilir - satır 13-19
  • aksi takdirde [LISTE] görünümü gönderilir - satır 20-24

1.5.7.5. [infos] eyleminin işlenmesi

Müşteri belirli bir ürün hakkında bilgi talep etti:

Image

Kod şu şekildedir:

         ' bir ürün hakkında bilgi
        Public Sub doInfos()
             ' hata yönetimi
            Dim erreurs As New ArrayList
             ' istenen ürünün kimliğini alıyoruz
            Dim strId As String = Request.QueryString("id")
             ' bir şey var mı?
            If strId Is Nothing Then
                 ' normal değil - hata sayfası gönderiliyor
                erreurs.Add("action incorrecte (action=infos, id=rien)")
                context.Items("erreurs") = erreurs
                context.Items("options") = New Hashtable() {CType(options("liste"), Hashtable)}
                Server.Transfer(CType(Application.Item("urlErreurs"), String))
                Exit Sub
            End If
             ' bir tamsayı var mı?
            Dim id As Integer
            Try
                id = Integer.Parse(strId)
            Catch ex As Exception
                 ' normal değil - hata sayfası gönderiliyor
                erreurs.Add("action incorrecte (action=infos, id[" + strId + "] invalide)")
                context.Items("erreurs") = erreurs
                context.Items("options") = New Hashtable() {CType(options("liste"), Hashtable)}
                Server.Transfer(CType(Application.Item("urlErreurs"), String))
                Exit Sub
            End Try
             ' anahtar id'sine ait öğe isteniyor
            Dim unArticle As Article
            Try
                unArticle = articlesDomain.getArticleById(id)
            Catch ex As Exception
                 ' verilere erişimde sorun
                erreurs.Add("Problème d'accès aux données (" + ex.ToString + ")")
                context.Items("erreurs") = erreurs
                context.Items("options") = New Hashtable() {CType(options("liste"), Hashtable)}
                Server.Transfer(CType(Application.Item("urlErreurs"), String))
                Exit Sub
            End Try
             ' Bir öğe alındı mı?
            If unArticle Is Nothing Then
                 ' kayıt mevcut değil
                erreurs.Add("L'article d'id=" + id.ToString + " n'existe pas")
                context.Items("erreurs") = erreurs
                context.Items("options") = New Hashtable() {CType(options("liste"), Hashtable)}
                Server.Transfer(CType(Application.Item("urlErreurs"), String))
                Exit Sub
            End If
             ' ürün mevcut - mevcut oturuma ekleniyor
            Session.Item("article") = unArticle
             ' görüntülenmesi hazırlanıyor
            context.Items("options") = New Hashtable() {CType(options("liste"), Hashtable)}
            context.Items("msg") = ""
            context.Items("qte") = ""
            Server.Transfer(CType(Application.Item("urlInfos"), String))
        End Sub

Yorumlar:

  • Olası hatalar [ArrayList] dosyasına kaydedilir - 4. satır
  • İstenen maddenin kimliği, istekte alınır - satır 6
  • bu kimlik doğrulanır. Kimlik mevcut olmalı ve bir tamsayı olmalıdır. Aksi takdirde, uygun hata mesajıyla birlikte [ERREURS] görünümü gönderilir - satır 7-27
  • kimlik doğrulandıktan sonra, ürün [articlesDomain] tekil nesnesinden istenir. Bir istisna oluşursa, [ERREURS] görünümü gönderilir - satır 29-39
  • ürün bulunamazsa, [ERREURS] görünümü gönderilir - satır 41-48
  • ürün bulunursa, kullanıcının oturumuna eklenir ve ardından [INFOS] görünümünde görüntülenir - satır 50-56

1.5.7.6. [achat] eyleminin işlenmesi

Müşteri, [INFOS] görünümünde görüntülenen ürünü satın almıştır.

Image

Kod şu şekildedir:

         ' ürün satın alındı
        Public Sub doAchat()
             ' ürün satın alındı
             ' oturumda bulunan ürünü alıyoruz
            Dim unArticle As Article = CType(Session.Item("article"), Article)
             ' Elimizde bir şey var mı?
            If unArticle Is Nothing Then
                 ' normal değil - ürün listesi görüntüleniyor
                doListe()
            End If
             ' gönderilen miktarı alıyoruz
            Dim strQte As String = Request.Form("txtQte")
             ' bir şey var mı?
            If strQte Is Nothing Then
                 ' normal değil - ürün listesi gönderiliyor
                doListe()
            End If
             ' bir tamsayı var mı?
            Dim qte As Integer
            Try
                qte = Integer.Parse(strQte)
                If (qte <= 0) Then Throw New Exception
            Catch ex As Exception
                 ' normal değil - hata mesajıyla birlikte bilgi sayfasını gönderiyoruz
                context.Items("options") = New Hashtable() {CType(options("liste"), Hashtable)}
                context.Items("msg") = "Quantité incorrecte"
                context.Items("qte") = strQte
                Server.Transfer(CType(Application.Item("urlInfos"), String))
            End Try
             ' her şey yolunda - satın alınan ürünü müşterinin sepetine ekliyoruz
            Dim unPanier As Panier = CType(Session.Item("panier"), Panier)
            unPanier.ajouter(New Achat(unArticle, qte))
             ' ürün listesi görüntüleniyor
            doListe()
        End Sub

Yorumlar:

  • oturumda bulunan makale alınır - 5. satır
  • eğer orada değilse (oturumun süresi dolmuş olabilir), [LISTE] görünümü görüntülenir - satır 7-10
  • satın alınan miktar sorgudan alınır - satır 12
  • geçerliliği kontrol edilir - satır 13-29
  • Geçerli değilse, duruma göre [LISTE] görünümü - satır 16 veya [INFOS] görünümü - satır 24-28 gönderilir
  • her şey normalse, satın alma işlemi sepete kaydedilir - satır 31-32
  • ardından [LISTE] görünümü gönderilir - satır 34

1.5.7.7. [panier] eyleminin işlenmesi

Müşteri çeşitli satın alımlar yaptı ve sepetini görmek istiyor:

Image

Kod şu şekildedir:

         ' sepet görüntüleniyor
        Public Sub doPanier()
             'sepet, oturumdan alınır
            Dim unPanier As Panier = CType(Session.Item("panier"), Panier)
             ' sepet boş mu?
            If unPanier.achats.Count = 0 Then
                 ' boş sepet görüntüleme
                context.Items("options") = New Hashtable() {CType(options("liste"), Hashtable)}
                Server.Transfer(CType(Application.Item("urlPanierVide"), String))
            End If
             ' dolu alışveriş sepeti görüntüleme
            context.Items("options") = New Hashtable() {CType(options("liste"), Hashtable), CType(options("validationpanier"), Hashtable)}
            Server.Transfer(CType(Application.Item("urlPanier"), String))
        End Sub

Açıklamalar:

  • Alışveriş sepeti oturumdan alınır - 4. satır. Burada bir şeyin alındığını doğrulamıyoruz. Oturumun süresi dolmuş olabileceğinden bunu yapmak gerekir.
  • Alışveriş sepeti boşsa, [PANIERVIDE] görünümü gönderilir - 6-10. satırlar
  • Aksi takdirde [PANIER] görünümü gönderilir - satır 11-14

1.5.7.8. [retirerachat] eyleminin işlenmesi

Müşteri, sepetinden bir ürünü çıkarmak istiyor:

Image

Kod şu şekildedir:

         ' bir ürünü sepetten çıkarma
        Public Sub doRetirerAchat()
             'oturumdan sepeti al
            Dim unPanier As Panier = CType(Session.Item("panier"), Panier)
             ' ürünü sepetten çıkar
            Try
                 ' çıkarılan ürünün kimliği alınır
                Dim idArticle As Integer = Integer.Parse(Request.QueryString("id"))
                 ' sepetten çıkarılır
                unPanier.enlever(idArticle)
            Catch ex As Exception
                 ' ürün listesi görüntülenir
                doListe()
            End Try
             ' sepet görüntüleniyor
            doPanier()
        End Sub

Açıklamalar:

  • Sepet, oturumdan alınır - 4. satır. Burada bir şeyin alındığını doğrulamıyoruz. Oturumun süresi dolmuş olabileceğinden bunu yapmak gerekir.
  • İstemden, kaldırılacak ürünün [id] kimlik numarası alınır - 8. satır.
  • İlgili satın alma işlemi sepetten kaldırılır - 10. satır
  • Satın alınan ürünün kimlik numarasının geçerliliği burada kontrol edilmemiştir. Eğer kimlik numarasının türü geçersizse, bir istisna oluşur ve 11-13. satırlarda işlenir. Eğer geçerli ancak mevcut değilse, [panier.enlever] yöntemi (10. satır) hiçbir işlem yapmaz.
  • Yeni sepet görüntülenir - satır 16

1.5.7.9. [validerpanier] eyleminin işlenmesi

Müşteri sepetini onaylamak istiyor:

Image

Kod şu şekildedir:

         ' sepet satın alınır
        Public Sub doValidationPanier()
             ' başlangıçta hata yok
            Dim erreurs As ArrayList
             'oturumdan sepeti alınıyor
            Dim unPanier As Panier = CType(Session.Item("panier"), Panier)
             ' sepeti onaylamaya çalışılıyor
            Try
                articlesDomain.acheter(unPanier)
                 ' olası satın alma hataları kaydediliyor
                erreurs = articlesDomain.erreurs
            Catch ex As Exception
                 ' hata kaydediliyor
                erreurs = New ArrayList
                erreurs.Add(String.Format("Erreur lors de la validation du panier [{0}]", ex.Message))
            End Try
             ' hata varsa hata sayfasına yönlendirme
            If erreurs.Count <> 0 Then
                context.Items("erreurs") = erreurs
                context.Items("options") = New Hashtable() {CType(options("liste"), Hashtable), CType(options("panier"), Hashtable)}
                Server.Transfer(CType(Application.Item("urlErreurs"), String))
                Exit Sub
            End If
             ' her şey yolunda - ürün listesi bir başarı mesajıyla görüntüleniyor
            context.Items("message") = "Votre panier a été validé"
            doListe()
        End Sub

Açıklamalar:

  • Alışveriş sepeti oturumdan alınır - 6. satır. Burada bir şeyin alındığını doğrulamıyoruz. Oturumun süresi dolmuş olabileceğinden bunu yapmak gerekir.
  • Oturumun süresi dolmuşsa, sepet için [nothing] işaretçisi elde edilir ve [acheter] yöntemi (9. satır) bir istisna oluşturur ve [ERREURS] görünümü gönderilir. Ancak hata mesajı kullanıcı için pek açıklayıcı olmayacaktır.
  • 8-16. satırlarda, oturumdan alınan sepetin geçerliliği kontrol edilmeye çalışılır. Talep edilen miktar, ilgili ürünün stok miktarını aşarsa bazı satın alımlar onaylanmayabilir. Bu durumlar, [acheter] yöntemi tarafından bir hata listesinde kaydedilir ve bu liste 11. satırda alınır.
  • Hata varsa, [ERREURS] görünümü gönderilir – satır 18-23
  • aksi takdirde [LISTE] görünümü gönderilir - satır 25-26

1.6. Conclusion

Burada MVC modeline göre bir uygulama geliştirdik. Java'da (Struts, Spring, ...). [Spring.net] projesi yakında böyle bir çerçeve sunacaktır. Bu gelişme gerçekleşene kadar, önceki yöntem orta ölçekli uygulamalar için uygulanabilir bir MVC geliştirme imkanı sunmaktadır.