10. [SimuPaie] uygulaması – sürüm 6 – bir web hizmetinin ASP.NET istemcisi
10.1. Uygulamanın mimarisi
NUnit testinin istemci/sunucu mimarisini şu şekilde geliştiriyoruz:
![]() |
[1]'te, NUnit testi, sürüm 8'in web uygulamasıyla değiştirilmiştir. Burada, bu mimarinin gösterilmeyen iki web sunucusu içerdiğini unutmamak gerekir:
- [S] web hizmetini çalıştıran bir web sunucusu. Bu, Visual Web Developer'ın ilk örneğinde çalışacaktır.
- [1] web istemcisini çalıştıran bir web sunucusu. Bu, Visual Web Developer'ın ikinci bir örneğinde çalışacaktır.
10.2. [web] istemcisinin Visual Web Developer projesi
ASP.NET adlı yeni bir web projesi oluşturuyoruz:
![]() |
- [1]'te, C# ile bir web projesi seçiyoruz
- [2]'te "ASP.NET Web Uygulaması"nı seçiyoruz
- [3]'te, web projesine bir ad veriyoruz
- [4]'te, bu proje için bir konum belirtiyoruz
- [5] dosyasında, proje oluşturuldu
Projenin bazı özelliklerini değiştiriyoruz:
![]() |
- [1]'te, oluşturulacak derlemenin adı
- [2] olarak, oluşturulacak sınıflar ve arayüzler için varsayılan ad alanı
[pam-v6-client-webservice] projesini derlemek için, [pam-v4-3tier-nhibernate-multivues-monopage] web projesinden [Global.asax] ve [Default.aspx] dosyalarını alıp [pam-v6-client-webservice] projesine kopyalayabiliriz. Bunu öncelikle Windows Dosya Gezgini ile yapabiliriz:
![]() |
- dosyasını [1] projesine, [pam-v4-3tier-nhibernate-multivues-monopage]
- 'i [2]'e, [pam-v6-client-webservice] proje klasörünü de kopyalama işleminden sonra
- [images, pam, ressources]
- [Global.asax, Global.asax.cs] dosyaları
- [Default.aspx, Default.aspx.cs, Default.aspx.designer.cs] dosyaları
- [3]'e kopyalandıktan sonra, Visual Studio Express'te projenin tüm dosyalarını görüntüleyerek yeni eklenen dosyaları ortaya çıkarırız
- [4] dosyasına, eklenen klasörleri ve dosyaları projeye dahil ediyoruz
![]() |
- [5]'te yeni proje [pam-v6-client-webservice]
Bu aşamada, projeyi ilk kez derleyebiliriz: [6]. Aşağıdaki hatalarla karşılaşılır:
Bu hataları anlamak ve düzeltmek için, geliştirilmekte olan web projesinin mimarisine geri dönmek gerekir:
![]() |
[pam-v6-client-webservice] projesi, yukarıdaki şemada [web] ve [1] katmanlarını oluşturmaktadır. Bu katmanın, web hizmetinin [C] istemcisiyle iletişim kurduğu görülüyor; bu istemciyi yakında oluşturacağız.
- 2, 5 ve 7 numaralı hatalar, [pam-v4] kodunun, [metier] katmanındaki DLL'e referans vermesinden kaynaklanmaktadır; DLL katmanında yer alıyordu; bu katman artık istemci tarafında değil, sunucu tarafındadır.
- 1 ve 3 numaralı hataların nedeni aynıdır, ancak bu sefer [dao] katmanındaki DLL ile ilgilidir
- Hata 4, [Global.asax] kodunun Spring kullandığından ve projemizin Spring'in DLL'sine referans vermediğinden kaynaklanmaktadır. Bu referansı ekleyeceğiz.
- Hata 6, [Employe] sınıfının, istemci tarafında mevcut olmayan [dao] katmanında tanımlanmış olmasından kaynaklanmaktadır.
1, 2, 4, 5, 6 ve 7 numaralı ad alanı hataları, web hizmetinin C istemcisinin oluşturulmasıyla çözülecektir. 3 numaralı hata ise projeye Spring'in DLL sınıfına bir referans eklenerek çözülür. Aşağıdaki şekilde ilerleyebiliriz:
![]() |
- [1]'te, projeye [pam-v6-client-webservice] referansı eklenir
- [4]'te, [lib] klasöründeki DLL ve [Spring.Core]'e bir referans eklenmiştir.
Spring'e bu referans eklendikten sonra, proje oluşturma işleminde bir hata azaldı. Diğer tüm hatalar, artık sunucuda bulunan [metier] ve [dao] katmanlarındaki nesnelere referans veren kod satırlarından kaynaklanmaktadır. Göreceğiz ki, bu eksik nesneler web hizmetinin [C] istemcisinde oluşturulacaktır.
![]() |
Web hizmetinin [C] istemcisini oluşturmadan önce, mevcut çeşitli sınıfların ad alanını değiştireceğiz. Bu sınıflar şu anda [pam-v4] ad alanında bulunmaktadır. Bu ad alanını [pam-v6] olarak değiştiriyoruz. İlgili dosyalar şunlardır: Default.aspx.cs, Default.aspx.designer.cs, Global.asax.cs. Örneğin:
....
namespace pam_v6
{
public class Global : System.Web.HttpApplication
{
// --- uygulamanın statik verileri ---
public static Employe[] Employes;
public static IPamMetier PamMetier = null;
....
- satırda, pam_v4 ad alanı, pam_v6 ad alanıyla değiştirilmiştir.
Ayrıca, Default.aspx ve Global.asax dosyalarının etiketleri de değiştirilmelidir:
![]() |
[Default.aspx] dosyasının etiketlemesi şu şekilde olur:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="pam_v6.PagePam" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
.....
- satırda, Inherits özniteliği, [Default.aspx.cs] dosyasının sınıf adını belirtir. Ad alanı değiştirilir.
[Global.asax] etiketlemesi şu şekilde olur:
<%@ Application Codebehind="Global.asax.cs" Inherits="pam_v6.Global" Language="C#" %>
Yukarıda, Inherits özniteliğinin ad alanı değiştirilmiştir.
Şimdi web hizmetinin [C] istemcisini oluşturuyoruz.
![]() |
Aşağıdaki işlemleri gerçekleştirmek için, [S] ve [pam-v5-webservice] web hizmetlerinin başka bir Visual Web Developer örneğinde çalıştırılması gerekir.
![]() |
- [1]'te, [pam-v6-client-webservice] projesine, [pam-v5-webservice] web hizmetine bir referans eklenir
- [2]'te, [pam-v5-webservice] web hizmetinin URI'i. Bu, söz konusu web hizmetinin WSDL dosyasının URL'idir. [pam-v5-webservice] web hizmetinin yapısında, bu URL'yi nasıl bulacağımız belirtilmiştir.
- [3]'te, asistandan [2]'te belirtilen WSDL dosyasını
- [4]'te, [Service1Soap] web hizmeti keşfedilir ve [5]'te bu hizmetin sunduğu uzaktan yöntemler gösterilir.
- [6]'te, [C] istemcisinin sınıflarının ve arayüzlerinin oluşturulacağı ad alanı belirlenir
- [C] istemcisinin oluşturulması başlatılır
![]() |
- [1] dosyasında, oluşturulan istemci bulunur. İçeriğine erişmek için bu dosyaya çift tıklayın.
- [2]'te, nesne gezgininde pam_v6.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, katmanlardaki nesnelerin 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 pam_v6.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.
Hatalar içeren [Global.asax.cs] kodunu inceleyelim:
![]() |
- 3. ve 4. satırlarda, sunucuda mevcut olan ancak istemcide bulunmayan ad alanları kullanılmaktadır.
- 13. satırda, doğru ad alanı bildirilmemiş bir [Employe] sınıfı kullanılmaktadır
- 14. satırda, istemcide bilinmeyen bir IPamMetier arayüzü kullanılmaktadır.
Daha önce incelediğimiz C# istemcisinde de benzer sorunlarla karşılaşmıştık.
Mimari içinde:
![]() |
- yerel [metier] katmanı, pam_v6.WsPam.Service1SoapClient türündeki [C] istemcisi tarafından uygulanmaktadır; bu istemci, aynı adlı yöntemlere sahip olmasına rağmen IPamMetier arayüzünü uygulamamaktadır.
- İşlenen varlıklar (Employe, Indemnites, Cotisations), oluşturulan [C] istemcisi tarafından pam_v6.WsPam ad alanında yer almaktadır
[Global.asax.cs] kodunda aşağıdaki değişiklikler yapılmıştır:
using System;
using System.Collections.Generic;
using Pam.Web;
using Spring.Context.Support;
using pam_v6.WsPam;
namespace pam_v6
{
public class Global : System.Web.HttpApplication
{
// --- uygulamanın statik verileri ---
public static Employe[] Employes;
public static Service1SoapClient PamMetier = null;
public static string Msg;
public static bool Erreur = false;
// uygulamanın başlatılması
public void Application_Start(object sender, EventArgs e)
{
// yapılandırma dosyasının işlenmesi
try
{
// [metier] katmanının örneklenmesi
PamMetier = ContextRegistry.GetContext().GetObject("pammetier") as Service1SoapClient;
// çalışanların basitleştirilmiş listesi
Employes = PamMetier.GetAllIdentitesEmployes();
// başarılı
Msg = "Base chargée...";
}
catch (Exception ex)
{
// hata kaydedildi
Msg = string.Format("L'erreur suivante s'est produite lors de l'accès à la base de données : {0}", ex);
Erreur = true;
}
}
public void Session_Start(object sender, EventArgs e)
{
// oturuma boş bir simülasyon listesi ekleniyor
List<Simulation> simulations = new List<Simulation>();
Session["simulations"] = simulations;
}
}
}
- satırda, Spring aracılığıyla [C] katmanı örneklenir. Bu örneklendirme için gerekli yapılandırma, [web.config] içinde yapılır:
<configSections>
<sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
...
</sectionGroup>
<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="pam_v6.WsPam.Service1SoapClient,pam-v6-client-webservice"/>
</objects>
</spring>
- satırda, [metier] katmanı, [pam_v6.WsPam.Service1SoapClient] sınıfının bir örneğidir ve bu sınıf, DLL ile [pam-v6-client-webservice] içinde bulunur. Hatırlanacağı üzere, [pam-v6-client-webservice] projesini bu DLL'i oluşturacak şekilde yapılandırmıştık.
[Default.aspx.cs] dosyasında hâlâ birkaç hata bulunmaktadır:
![]() | ![]() |
- 5. ve 6. satırlar: Bu ad alanları artık mevcut değil. Varlıklar artık pam_v6 veya pam_v6.WsPam ad alanlarında yer almaktadır.
- 98. satır: Oluşturulan [C] istemcisi, [dao] katmanındaki [PamException] sınıfını devralmamıştır. Web hizmeti bu istisnayı sunmadığı için bunu yapamazdı. PamException'i üst sınıfı olan Exception ile değiştirmeye karar veriyoruz.
Kod şu şekilde olur:
...
using System.Web.UI.WebControls;
using pam_v6.WsPam;
namespace pam_v6
{
public partial class PagePam : Page
{
...
...
try
{
feuillesalaire = Global.PamMetier.GetSalaire(DropDownListEmployes.SelectedValue, HeuresTravaillées, JoursTravaillés);
}
catch (Exception ex)
{
...
Bu hatalar düzeltildikten sonra web uygulamasını çalıştırabiliriz:
![]() |
- [1]'te, uzak web hizmetinin web istemcisi olan URL'te
- [2]'te, çalışanlar listesi doldurulmuştur. İçerdiği veriler web hizmetinden gelmektedir.
Okuyucuyu, sürüm 4'ün bu 6. kopyasını denemeye davet ediyoruz.

















