Skip to content

9. [SimuPaie] uygulaması – sürüm 5 – ASP.NET / web hizmeti


Önerilen kaynaklar: [2] referansı, C# 2008'e Giriş, 10. bölüm "Web Hizmetleri"


9.1. Uygulamanın yeni mimarisi

Pam uygulamasının katmanlı mimarisi şu anda şu şekildedir:

Bunu şu şekilde geliştireceğiz:

Önceki mimaride [web], [metier] ve [dao] katmanları aynı sanal makinede çalışıyordu.NET katmanları, yeni mimaride ise [web] katmanı, [metier] ve [dao] katmanlarından farklı bir sanal makinede çalışacaktır. Bu durum, özellikle [web] katmanı bir M1 makinesindeyken, [metier] ve [dao] katmanları ise bir M2 makinesindeyse geçerli olacaktır. Burada bir istemci/sunucu mimarisi söz konusudur:

  • sunucu, [metier] ve [dao] katmanlarından oluşmaktadır. Bu bir web hizmeti olduğu için çalışabilmesi için 2 numaralı web sunucusuna ihtiyaç duyar.
  • İstemci, [web] katmanından oluşur. Çalışabilmesi için 1 numaralı web sunucusuna ihtiyaç duyar.
  • İstemci ve sunucu, HTTP / SOAP protokolü ile TCP/IP ağı üzerinden iletişim kurar. Bunun için mimariye iki yeni katman eklenmelidir:
    • [S] katmanı, bir web hizmeti olacaktır. Web hizmeti, uzak istemcilerden gelen istekleri alır ve bunları karşılamak için [metier] ve [dao] katmanlarını kullanır. Bir TCP/IP hizmeti oluşturmanın birçok yolu vardır. Web hizmetinin iki avantajı vardır:
      • şirketlerin ve kamu kurumlarının güvenlik duvarlarından geçmesine izin verilen HTTP protokolünü kullanır
      • birçok geliştirme platformu ( .Net, Java, Php, Flex, ...) tarafından uygulanan standart bir HTTP / SOAP alt protokolünü kullanır Böylece bir web hizmeti, .Net, Java, PHP, Flex gibi istemciler tarafından "kullanılabilir" (bu, yaygın olarak kullanılan terimdir).
    • [C] katmanı, uzak web hizmetinin istemcisi olacaktır. Bu katmanın görevi, [S] web hizmeti ile iletişim kurmaktır.

Bu yeni mimari, önceki mimarilerden fazla çaba harcamadan türetilebilir:

  • [metier] ve [dao] katmanları değişmeden kalır
  • [web] katmanı, esas olarak Employe ve FeuilleSalaire gibi, artık [C] istemci katmanının varlıklarına dönüşen varlıklara referans vermek amacıyla hafifçe değiştirilir. Bu varlıklar, [metier] veya [dao] katmanlarındakilere benzerdir, ancak farklı ad alanlarına aittir.
  • [S] sunucu katmanı, [metier] katmanının IPamMetier arayüzünü uygulayan bir sınıftır. Bu uygulama, yalnızca [metier] katmanının ilgili yöntemlerini çağırmakla yetinir. [S] sunucu katmanı tarafından uygulanan yöntemler, bunları çağırabilecek uzak istemcilere "sunulacaktır".
  • [C] istemci katmanı, Visual Studio tarafından oluşturulacaktır.

Yeni mimarinin ilkeleri şunlardır:

  • [web] katmanı, [metier] katmanıyla sanki bu katman yerelmiş gibi iletişim kurmaya devam eder. Bunun için [C] istemci katmanı,gerçek [metier] katmanının IPamMetier arayüzünü uygular ve [web] katmanına yerel bir [metier] katmanı gibi görünür. Daha önce bahsedilen ad alanları sorunu dışında, [web] katmanı değişmez. Katmanlı çalışma yönteminin avantajı da budur. Tek katmanlı bir uygulama oluşturulmuş olsaydı, çok kapsamlı bir şekilde yeniden düzenlenmesi gerekirdi.
  • [C] istemci katmanı, [web] katmanı için şeffaf bir şekilde, bu katmanın isteklerini uzak web hizmeti [S]'e iletir. Bu katman, "ağ iletişimi" ile ilgili tüm işlemleri üstlenir. Uzak web hizmetinden bir yanıt alır ve bunu, [web] katmanının beklediği biçimde biçimlendirerek bu katmana iletir.
  • Sunucu tarafında, [S] web hizmeti uzak müşterilerinden komutlar alır. Bu komutları, [metier] katmanının IPamMetier arayüzündeki yöntemleri çağırmak üzere biçimlendirir. [metier] katmanından yanıtı aldığında, bu yanıtı biçimlendirerek ağ üzerinden [C] istemcisine iletir. [metier] ve [dao] katmanlarında herhangi bir değişiklik yapılması gerekmez.

9.2. Web hizmetinin Visual Web Developer projesi

Visual Web Developer ile yeni bir proje oluşturuyoruz:

  • [1]'te, C# ile bir web projesi seçiyoruz
  • [2]'te "ASP.NET Web Hizmeti Uygulaması"nı seçiyoruz
  • [3]'te web projesine bir ad veriyoruz
  • [4]'te, bu proje için bir konum belirliyoruz
  • [1]'te oluşturulan proje. Bu, aşağıdaki ayrıntılar dışında klasik bir web projesidir:
    • Projenin "web hizmeti" türü olduğu belirtilmiştir. Bir web hizmeti, müşterilerine HTML web sayfaları değil, XML formatında veriler gönderir. Bu nedenle, genellikle oluşturulan [Default.aspx] sayfası oluşturulmamıştır.
  • [2] dosyasında, aşağıdaki içeriğe sahip bir [Service1.asmx] dosyası oluşturulmuştur:

<%@ WebService Language="C#" CodeBehind="Service1.asmx.cs" Class="pam_v5_webservice.Service1" %>
  • (devamı)
    • - WebService etiketi, [Service.asmx]'in bir web hizmeti olduğunu belirtir
    • - CodeBehind özniteliği, bu web hizmetinin kaynak kodunun konumunu belirtir
    • - Class özniteliği, kaynak kodda web hizmetini uygulayan sınıfın adını belirtir

Varsayılan olarak oluşturulan web hizmetinin [Service.asmx.cs] kaynak kodu şöyledir:


using System.Web.Services;

namespace pam_v5_webservice
{
  /// <summary>
  /// Hizmet1'in özet açıklaması
  /// </summary>
  [WebService(Namespace = "http://tempuri.org/")]
  [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
  [System.ComponentModel.ToolboxItem(false)]
  // ASP.NET AJAX kullanılarak bir komut dosyasından bu web hizmetinin çağrılmasına izin vermek için, aşağıdaki satırdaki yorum işaretlerini kaldırın. 
  // [System.Web.Script.Services.ScriptService]
  public class Service1 : System.Web.Services.WebService
  {

    [WebMethod]
    public string HelloWorld()
    {
      return "Hello World";
    }
  }
}
  • 8. satır: WebService etiketiyle, 13. satırdaki Service1 sınıfı bir web hizmeti olarak sunulacaktır. Bir web hizmeti, dünyada iki web hizmetinin aynı adı taşımasını önlemek için bir ad alanına aittir. İleride bu ad alanını değiştirmemiz gerekecektir.
  • 13. satır: Service1 sınıfı, .NET çerçevesindeki WebService sınıfından türetilmiştir.
  • 16. satır: WebMethod anotasyonu, anotasyonu yapılan yöntemin uzak istemcilere açılmasını ve bu sayede istemcilerin yöntemi çağırabilmesini sağlar.
  • 17-20. satırlar: HelloWorld yöntemi bir örnek yöntemdir. Bunu daha sonra sileceğiz. Bu yöntem, ilk testleri yapmamızı ve Visual Studio araçlarını keşfetmemizi, ayrıca web hizmetleri hakkında bilinmesi gereken bazı unsurları öğrenmemizi sağlar.
  • [1]'te, [Service.asmx] web hizmetini çalıştırıyoruz
  • VS Web Developer, yerleşik web sunucusunu başlattı ve onu rastgele bir bağlantı noktasında (burada 1599) dinleme moduna aldı. Ardından, [2] URL'si web sunucusuna gönderildi. Bu, web hizmetinin bir test sayfasının adresidir.
  • [3] adresinde ise web hizmetinin tanım dosyasını görüntülemeye olanak tanıyan bir bağlantı bulunmaktadır. Son eki (.wsdl) nedeniyle WSDL (WebService Tanım Dili) olarak adlandırılan bu dosya, web hizmeti tarafından sunulan yöntemleri açıklayan bir XML dosyasıdır. Müşteriler, bu WSDL dosyasından şunları öğrenebilirler:
    • web hizmetinin ad alanı
    • web hizmeti tarafından sunulan yöntemlerin listesi
    • her birinin beklediği parametreler
    • her birinin döndürdüğü yanıt
  • [4] dosyasında ise, web hizmeti tarafından sunulan tek yöntem yer almaktadır.
  • [5]'te, [3] bağlantısı aracılığıyla elde edilen WSDL dosyasının içeriği. URL ve [6] dosyalarına dikkat edilmelidir. Web hizmetinin müşterileri için bu bilgileri bilmek gereklidir.
  • [7]'te, [4] bağlantısını takip ederek ulaşılan sayfa, web hizmetinin [HelloWorld] yöntemini çağırmaya olanak tanır
  • [8]'te elde edilen sonuç: bir XML yanıtı. Yöntemin URL ve [9] değerlerine dikkat edilmelidir.

Önceki sayfaların incelenmesi, bir web hizmetinin yönteminin nasıl çağrıldığını ve ne tür bir yanıt döndürdüğünü anlamamızı sağlar. Bu sayede, web hizmetiyle iletişim kurabilen HTTP istemcileri yazılabilir. Günümüzde kullanılan çoğu IDE, bu istemcinin otomatik olarak oluşturulmasına olanak tanır ve böylece geliştiricinin bunu yazma zahmetinden kurtulmasını sağlar. Bu durum özellikle Visual Studio Express için geçerlidir.

Bu projeye devam etmeden önce, sınıfların oluşturulmasında varsayılan olarak kullanılan ad alanını değiştireceğiz:

Proje özelliklerini seçtiğimizde (projeye sağ tıklama / Özellikler), [1] alanında projenin adı (l'assembly) ve [2] alanında varsayılan ad alanı yer alır.

Bunu yaptıktan sonra,

  • [Service1.asmx.cs]'te sınıfın ad alanını şu şekilde değiştiriyoruz:

using System.Web.Services;

namespace pam_v5
{
...
  public class Service1 : System.Web.Services.WebService
  {
...
  }
}
  • [Service.asmx]'te, [Service1] sınıfı için kullanılan ad alanını da değiştiriyoruz (sağ tıklama / etiketleri göster):

<%@ WebService Language="C#" CodeBehind="Service1.asmx.cs" Class="pam_v5.Service1" %>

Uygulamamızın mimarisine geri dönelim:

  • [S] katmanı web hizmetidir. Bu katman, [metier] katmanındaki yöntemleri uzak istemcilere sunmakla yetinir. Şu anda oluşturmakta olduğumuz katman budur.
  • [C] katmanı, web hizmetinin HTTP istemcisidir. IDE'lerin otomatik olarak oluşturabildiği katman budur.
  • [web] katmanı, [C] katmanını yerel bir [metier] katmanı olarak görür; bunun için [C] katmanınınuzak [metier] katmanının arayüzünü uygulamasını sağlarsak.

Aşağıda, web hizmetimizin şunları yapacağını görüyoruz:

  • [metier] katmanının yöntemlerini sunacak
  • bu katmanla iletişim kuracak ve bu katman da [dao] katmanıyla iletişim kuracaktır.

Dolayısıyla proje, [metier] ve [dao] katmanlarının DLL arayüzlerini kullanmalıdır. Proje şu şekilde gelişmektedir:

  • [1]'e dönüştürülür, projeye referanslar eklenir
  • [2]'e, [lib] klasöründen her zamanki DLL'leri seçin. Hepsinin "Yerel Kopya" özelliğinin True olarak ayarlandığından emin olun. Seçilen DLL dosyaları, [metier] ve [dao] katmanlarını NHibernate desteği ile uygulayan dosyalardır.

"ASP.NET Web hizmeti" türündeki bir web uygulaması, geleneksel bir "ASP.NET web sitesi" uygulaması gibi "Global.asax" genel uygulama sınıfına sahip olabilir. Böyle bir sınıfın faydalarını daha önce görmüştük:

  • uygulama başlatıldığında örneklenir ve bellekte kalır
  • böylece tüm istemciler tarafından paylaşılan ve salt okunur olan verileri depolayabilir. Uygulamamızda, önceki uygulamalarda olduğu gibi, çalışanların basitleştirilmiş listesini depolayacaktır. Bu sayede, bir istemci bu listeyi talep ettiğinde veritabanından bu listeyi aramaya gerek kalmayacaktır.
  • [1]'te, projeye sağ tıklayın
  • [2]'te, [Ajouter un nouvel élément] seçeneğini seçin
  • [3]'te, [Classe d'application globale]'i seçin
  • [4]'te, [Global.asax] dosyası projeye eklendi

[Global.asax] dosyasının içeriği şöyledir:


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

[Global.asax.cs] dosyasının içeriği şöyledir:


using System;

namespace pam_v5
{
  public class Global : System.Web.HttpApplication
  {

    protected void Application_Start(object sender, EventArgs e)
    {

    }
...
  }
}

Application_Start yönteminde ne yapmalıyız? Önceki web uygulamalarında yaptığımızın aynısını. Uygulama mimarisine geri dönelim ve [Global] sınıfını buraya yerleştirelim:

Yukarıdaki şemada,

  • [Global] sınıfı, web hizmeti başlatıldığında örneklenir. Web hizmeti aktif olduğu sürece bellekte kalır.
  • [Global] sınıfı, [metier] ve [dao] katmanlarını [Application_Start] yönteminde örneklendirir
  • Performansı artırmak için, [Global] sınıfı, çalışanların basitleştirilmiş listesini bir iç alana yerleştirir. Çalışan listesini bu alandan döndürür.
  • Web hizmeti ise her istemci isteğinde bir örnek olarak oluşturulur. İsteği karşıladıktan sonra ortadan kalkar. Doğrudan [metier] katmanına değil, [Global] sınıfına hitap edecektir. Bu sınıf, [metier] katmanının arayüzünü uygulayacaktır.

[Global] sınıfı, önceki uygulamalar için daha önce oluşturulmuş olan sınıfa benzerdir:


using System;
using Pam.Dao.Entites;
using Pam.Metier.Entites;
using Pam.Metier.Service;
using Spring.Context.Support;

namespace pam_v5
{
  public class Global : System.Web.HttpApplication
  {
    // --- uygulamanın statik verileri ---
    public static Employe[] Employes;
    public static IPamMetier PamMetier = null;

    protected void Application_Start(object sender, EventArgs e)
    {
      // [metier] katmanının örneklenmesi
      PamMetier = ContextRegistry.GetContext().GetObject("pammetier") as IPamMetier;
      // basitleştirilmiş çalışan tablosu alınır 
      Employes = PamMetier.GetAllIdentitesEmployes();
    }

    // çalışanların basitleştirilmiş listesi
    static public Employe[] GetAllIdentitesEmployes()
    {
      return Employes;
    }

    // bir çalışanın maaşı
    static public FeuilleSalaire GetSalaire(string SS, double heuresTravaillées, int joursTravailles)
    {
      return PamMetier.GetSalaire(SS, heuresTravaillées, joursTravailles);
    }
  }
}

[Global] sınıfı, [IPamMetier] arayüzünü uygular, ancak bu, bildirimde açıkça belirtilmemiştir:


  public class Global : System.Web.HttpApplication, IPamMetier

Nitekim, GetAllIdentitesEmployes (24. satır) ve GetSalaire (30. satır) yöntemleri statik iken, IPamMetier arayüzündeki yöntemler statik değildir. Bu nedenle, Global sınıfı, IPamMetier arayüzünü uygulayamaz. Ayrıca, GetAllIdentitesEmployes ve GetSalaire yöntemlerini statik olmayan olarak tanımlamak mümkün değildir. Zira bu yöntemlere, sınıfın bir örneği üzerinden değil, sınıf adı üzerinden erişilir.

  • 15. satır: Application_Start yöntemi, önceki sürümlerde incelenen [Global] sınıflarındakine benzerdir. [metier] katmanını örneklendirir (18. satır) ve ardından 12. satırdaki çalışanlar dizisini başlatır (20. satır).
  • 24. satır: GetAllIdentitesEmployes yöntemi, sadece 12. satırdaki çalışanlar dizisini döndürür. Uygulamanın başlangıcında bu diziyi bellekte tutmanın önemi de budur.
  • satır 30: GetSalaire yöntemi, [metier] katmanındaki aynı isimli yöntemi çağırır.

[metier] katmanını (18. satır) örneklendirmek için [Global] sınıfı Spring çerçevesini kullanır. Bu çerçeve, önceki projeninkiyle aynı olan [Web.config] dosyası tarafından yapılandırılır: Spring ve NHibernate'i, web hizmetinin [metier] ve [dao] katmanlarını örneklendirmek üzere yapılandırır.

İstemci/sunucu uygulamamızın mimarisine geri dönelim:

Sunucu tarafında geriye sadece [S] web hizmetini yazmak kalıyor. Uygulamanın mimarisine geri dönersek:

gördüğümüz gibi, sunucu tarafında [metier] katmanından önceki tüm katmanlar, bu katmanın arayüzünü (IPamMetier) uygulamaktadır. Bu zorunlu değildir, ancak mantıklı görünen bir yaklaşımdır. Bu mantık, istemci tarafında, [S] web hizmetinin [C] istemcisine de uygulanabilir. Böylece, [web] katmanını [metier] katmanından ayıran tüm katmanlar, IPamMetier arayüzünü uygular. Böylece, üç katmanlı bir uygulamaya geri döndüğümüz söylenebilir:

  • sunum katmanı [web] [1]
  • [metier] ve [2] katmanları
  • veri erişim katmanı [3]

[Service1.asmx.cs] web hizmetinin uygulaması şu şekilde olabilir:


using System.Web.Services;
using Pam.Dao.Entites;
using Pam.Metier.Entites;
using Pam.Metier.Service;

namespace pam_v5
{
  [WebService(Namespace = "http://st.istia.univ-angers.fr/")]
  [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
  [System.ComponentModel.ToolboxItem(false)]
  public class Service1 : System.Web.Services.WebService, IPamMetier
  {

    // tüm çalışan kimliklerinin listesi 
    [WebMethod]
    public Employe[] GetAllIdentitesEmployes()
    {
      return Global.GetAllIdentitesEmployes();
    }

    // ------- maaş hesaplaması 
    [WebMethod]
    public FeuilleSalaire GetSalaire(string ss, double heuresTravaillees, int joursTravailles)
    {
      return Global.GetSalaire(ss, heuresTravaillees, joursTravailles);
    }
  }
}
  • 8. satır: Sınıf, [WebService] özniteliği ile işaretlenmiştir ve web hizmetinin ad alanına bir ad veriyoruz
  • 11. satır: [Service1] sınıfı, [WebService] sınıfından miras alır ve [IPamMetier] arayüzünü uygular
  • 15. ve 22. satırlar: Sınıfın her yöntemi, uzak istemcilere açığa çıkarılmak üzere [WebMethod] özniteliği ile işaretlenmiştir. Varsayılan olarak, bir web hizmetinin tüm genel yöntemleri açığa çıkarılır. Dolayısıyla, 15. ve 22. satırlardaki öznitelikler burada isteğe bağlıdır. [IPamMetier] arayüzünü uygulamak için her yöntem, [Global] sınıfındaki aynı adlı yöntemi çağırmakla yetinir.

Web hizmetini çalıştırmaya hazırız:

  • [1]'te proje yeniden oluşturulur
  • [2]'te, [Service1.asmx] web hizmetini seçip [3] tarayıcısında görüntülüyoruz
  • [4]'te, görüntülenen web sayfası. Bu sayfada web hizmetinin yöntemleri gösterilmektedir.
  • [4] adresinde, [GetAllIdentitesEmployes] bağlantısını takip ediyoruz ve [5] adresinde bu yöntemin test sayfasını görüyoruz.
  • [6] adresinde, yöntemin URL adresi
  • [7] adresinde, yöntemi test etmemizi sağlayan [Appeler] düğmesi bulunur. Bu yöntem herhangi bir parametre gerektirmez.
  • [8]'te, web hizmeti tarafından döndürülen XML sonucu. Bu sonuçta, yalnızca SS, Nom, Prenom özellikleri önemlidir; çünkü [GetAllIdentitesEmployes] yöntemi yalnızca bu özellikleri talep eder. Ancak bu yöntem, bir Employe nesneleri dizisi döndürür. [8]'te görüldüğü gibi, sayısal özellikler Id ve Version, geri gönderilen XML akışında yer alırken, null değerine sahip özellikler yer almamaktadır: Adresse, Ville, CodePostal, Indemnites.

Etkin bir web hizmetimiz var. Şimdi bu hizmet için bir C# istemcisi yazacağız. Bunun için, web hizmetinin WSDL dosyasındaki URI değerine ihtiyacımız olacak. Bu değeri, [Service.asmx] çalıştırıldığında başlangıçta görüntülenen sayfadan elde ediyoruz:

  • [1]'te, web hizmetinin URI dosyası
  • [2]'e, WSDL dosyasına yönlendiren bağlantı
  • [3]'e, bu bağlantının değeri

9.3. Web hizmetinin NUnit istemcisi için C# projesi

Web hizmetinin istemcisi için (Visual Web Developer değil, Visual C# ile) bir C# projesi oluşturuyoruz. Bu, bir test istemcisi NUnit olacaktır. Ayrıca proje, "Sınıf Kütüphanesi" türünde olacaktır.

  • [1]'te, "Sınıf Kütüphanesi" türünde bir C# projesi oluşturuyoruz
  • [2]'te projeye bir isim veriyoruz
  • [3]'te projeyi görüyoruz. [Class1.cs]'i siliyoruz.
  • [4]'te, yeni proje.
  • Proje özelliklerinde, [Application] [5] sekmesinde, projenin ad alanını belirliyoruz. IDE tarafından oluşturulan her sınıf bu ad alanında oluşturulacaktır.

Yeni projemizi uygun bir konuma kaydederiz:

 

Bunu yaptıktan sonra, uzak web hizmetinin istemcisini oluşturuyoruz. Ne yapacağımızı anlamak için, şu anda oluşturulmakta olan istemci/sunucu mimarisine geri dönmemiz gerekiyor:

IDE, [S] web hizmetinin WSDL dosyasındaki URI'ten [C] istemci katmanını oluşturacaktır. Bu dosyanın URI dosyasının daha önce not edildiğini hatırlayalım. adresinden şu şekilde ilerliyoruz:

  • [1]'e dönüştürürken, References dalına sağ tıklayıp bir hizmet referansı ekleyin
  • [2]'e, daha önce not edilen web hizmetinin WSDL dosyasının URL değerini belirtin. Bu hizmet henüz başlatılmamışsa, önceden başlatılmalıdır.
  • [3]'te, WSDL dosyası aracılığıyla web hizmetinin keşfedilmesini isteyin
  • [4] dosyasında, keşfedilen web hizmeti
  • [5]'te, web hizmeti tarafından sunulan yöntemler.
  • [6]'te, oluşturulacak istemcinin sınıflarını ve arayüzlerini yerleştirmek istediğiniz ad alanı.
  • sihirbazı onaylıyoruz

  • [1]'te, oluşturulan istemci 'si. İçeriğine erişmek için üzerine çift tıklayın.
  • [2]'te, nesne gezgininde Client.WsPam ad alanına ait sınıflar ve arayüzler görüntülenir. Bu, oluşturulan istemcinin ad alanıdır.
  • [3]'te, web hizmeti istemcisini uygulayan sınıf bulunur.
  • [4]'te, [Service1SoapClient] istemcisi tarafından uygulanan yöntemler bulunur. Burada, [5] ve [6] adlı iki uzak web hizmeti yöntemi yer alır.
  • [2] dosyasında ise katmanlardaki varlıkların görüntüleri bulunur:
    • [metier]: FeuilleSalaire, ElementsSalaire
    • [dao]: Employe, Cotisations, Indemnites

Bundan sonra, bu uzak varlıkların görüntülerinin istemci tarafında ve PamV5Client.WsPam ad alanında bulunduğunu unutmamak gerekir.

Bunlardan birinin sunduğu yöntem ve özellikleri inceleyelim:

  • [1]'te, yerel [Employe] sınıfı seçilir
  • [2]'te, uzak [Employe] varlığının özelliklerinin yanı sıra yerel varlığın kendi ihtiyaçları için kullanılan özel alanlar da bulunur.

C# uygulamamıza geri dönelim. Uygulamaya NUnit adlı bir test sınıfı ekliyoruz:

  • [1]'te, [NUnit] sınıfı eklendi. [NUnit] sınıfı, NUnit çerçeveye ve dolayısıyla bu çerçevenin DLL sınıfına bir referansa ihtiyaç duyacaktır. Burada, NUnit çerçevesinin bilgisayara (http://nunit.org/) yüklendiğini varsayıyoruz.
  • [2] dosyasında,
  • [3] sekmesinde. Bilgisayarda kayıtlı DLL dosyalarını bir araya getiren NET sekmesinde, [4]'i seçin, DLL ve [nunit.framework] için minimum sürüm 2.4.6'dır.

Ayrıca, [S] web hizmetinin yerel istemcisi [C]'i oluşturmak için Spring'i kullanacağız:

DLL Spring referansı, NUnit framework'ünde olduğu gibi eklenebilir; bunun için DLL'lerin önceden bilgisayara kaydedilmiş olması gerekir (http://www.springframework.net/download.html).

Biz farklı bir yol izliyoruz. Spring için gerekli olan DLL'leri içeren önceki projelerin [lib] klasörünü kullanıyoruz ve projeye Spring referansını ekliyoruz:

Şu anda geliştirilmekte olan istemci mimarisine geri dönelim:

Yukarıda, [1] test istemcisinin, genişletilmiş bir [metier] [2] katmanıyla arayüz oluşturduğunu görüyoruz. Bu katman, uzak [metier] katmanıyla aynı yöntemlere sahiptir. Bu nedenle, C# projesi [pam-metier-dao-nhibernate]’te [metier] katmanını test ederken daha önce karşılaştığımız test sınıfını kullanabiliriz:


using NUnit.Framework;
using Pam.Dao.Entites;
using Pam.Metier.Entites;
using Pam.Metier.Service;
using Spring.Context.Support;

namespace Pam.Metier.Tests {

    [TestFixture()]
    public class NunitTestPamMetier : AssertionHelper {

        // test edilecek [metier] katmanı 
        private IPamMetier pamMetier;

        // oluşturucu
        public NunitTestPamMetier() {
            // [dao] katmanının örneklenmesi
            pamMetier = ContextRegistry.GetContext().GetObject("pammetier") as IPamMetier;
        }


        [Test]
        public void GetAllIdentitesEmployes() {
            // çalışan sayısının doğrulanması 
            Expect(2, EqualTo(pamMetier.GetAllIdentitesEmployes().Length));
        }

        [Test]
        public void GetSalaire1() {
            // maaş bordrosu hesaplama 
            FeuilleSalaire feuilleSalaire = pamMetier.GetSalaire("254104940426058", 150, 20);
            // kontroller 
            Expect(368.77, EqualTo(feuilleSalaire.ElementsSalaire.SalaireNet).Within(1E-06));
            // var olmayan bir çalışanın maaş bordrosu 
            bool erreur = false;
            try {
                feuilleSalaire = pamMetier.GetSalaire("xx", 150, 20);
            } catch (PamException) {
                erreur = true;
            }
            Expect(erreur, True);
        }

    }
}

Yapılması gereken birkaç değişiklik var:

  • 18. satırda, [metier] katmanını Spring çerçevesiyle örneklendiriyoruz. Her iki durumda da sınıf aynı değildir. Burada, yerel [metier] katmanı, [PamV5Client.WsPam.Service1SoapClient] sınıfının bir örneğidir; bu sınıf, IDE tarafından oluşturulmuştur. Bu nedenle, C# projesindeki [app.config] dosyasında Spring şu şekilde yapılandırılmıştır:

<?xml version="1.0" encoding="utf-8" ?>
<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>
            <resource uri="config://spring/objects" />
        </context>
        <objects xmlns="http://www.springframework.net">
            <object id="pammetier" type="PamV5Client.WsPam.Service1SoapClient, pam-v5-client-csharp-webservice"/>
        </objects>
    </spring>


    <system.serviceModel>
...
  • Yukarıdaki 16. satırda, [pammetier] nesnesi, [pam-v5-client-csharp-webservice] derlemesinde (assembly) bulunan [PamV5Client.WsPam.Service1SoapClient] sınıfının bir örneğidir. İlk bilgiyi elde etmek için, nesne gezgininde (9.3. paragraf) [Service1SoapClient] sınıfının tanımına geri dönmeniz yeterlidir:
  • [2]'te, yerel [metier] katmanının uygulama sınıfı ve [1]'te ad alanı
  • [3] olarak değiştirin; proje özelliklerinde, derleme adı, Spring nesnesi [pammetier]'in yapılandırılması için gerekli ikinci bilgidir.

Şimdi, [NUnit.cs] içinde yerel [metier] katmanının örneklenmesine ilişkin koda geri dönelim:


        // test edilecek [metier] katmanı 
        private IPamMetier pamMetier;

        // oluşturucu
        public NunitTestPamMetier() {
            // [dao] katmanının örneklenmesi
            pamMetier = ContextRegistry.GetContext().GetObject("pammetier") as IPamMetier;
        }

  1. satırda, uzak [metier] katmanı IPamMetier türündeydi. Burada ise [metier] katmanı [Service1SoapClient] türündedir:

public class Service1SoapClient : System.ServiceModel.ClientBase<Service1Soap>

Görüyoruz ki, Service1SoapClient sınıfı, aynı isimde yöntemler sunsa da IPamMetier arayüzünü uygulamamaktadır. Dolayısıyla, yerel [metier] katmanının örneklenmesini şu şekilde yazmamız gerekir:


        // test edilecek [metier] katmanı 
        private Service1SoapClient pamMetier;

        // oluşturucu
        public NunitTestPamMetier() {
            // [metier] katmanının örneği
            pamMetier = ContextRegistry.GetContext().GetObject("pammetier") as Service1SoapClient;
}

Yapılması gereken bir diğer değişiklik:


        [Test]
        public void GetSalaire1() {
...
            try {
                feuilleSalaire = pamMetier.GetSalaire("xx", 150, 20);
            } catch (PamException) {
                erreur = true;
            }
            Expect(erreur, True);
        }

Yukarıdaki kodun 6. satırında, istemci tarafında mevcut olmayan PamException türü kullanılmaktadır. Bunu, üst sınıfı olan Exception türüyle değiştireceğiz.


        [Test]
        public void GetSalaire1() {
...
            try {
                feuilleSalaire = pamMetier.GetSalaire("xx", 150, 20);
            } catch (Exception) {
                erreur = true;
            }
            Expect(erreur, True);
        }

Son olarak, içe aktarılan ad alanları artık aynı değil:


using System;
using PamV5Client.WsPam;
using NUnit.Framework;
using Spring.Context.Support;

Bu işlem tamamlandıktan sonra, "Sınıf Kütüphanesi" türündeki proje oluşturulabilir. Aşağıdaki DLL dosyası oluşturulur:

  • [1] dosyasında, C# projesinin [bin/Release] klasörü
  • [2]'te, projenin DLL dosyası.

NUnit testi daha sonra NUnit çerçeve tarafından yürütülür (test için MySQL ve dbpam_nhibernate temel dosyalarının etkin olması gerekir):

  • [3] ve [4]'te, DLL ve [2], NUnit test uygulamasına yüklenir
  • [5]'te test sınıfı seçilir ve çalıştırılır [6]
  • [7]'te, başarılı bir testin sonuçları

Artık çalışır durumda bir web hizmetimiz var.