12. Web Hizmetleri
12.1. Introduction
Bir önceki bölümde birkaç TCP/IP istemci-sunucu uygulaması sunduk. İstemciler ve sunucu metin satırları alışverişinde bulundukları için, bunlar herhangi bir dilde yazılabilir. İstemcinin yalnızca sunucunun beklediği iletişim protokolünü bilmesi yeterlidir.
Web hizmetleri de TCP/IP sunucu uygulamalarıdır. Aşağıdaki özelliklere sahiptirler:
- Web sunucuları tarafından barındırılırlar ve istemci-sunucu iletişim protokolü, HTTP (HyperText Taşıma Protokolü) olup, bu protokol TCP-IP protokolünün üzerinde yer alır.
- Web hizmeti, sağlanan hizmet ne olursa olsun standart bir iletişim protokolüne sahiptir. Bir web hizmeti, S1, S2, .., Sn gibi çeşitli hizmetler sunar. Her biri, istemci tarafından sağlanan parametreleri bekler ve istemciye bir sonuç döndürür. Her hizmet için istemcinin şunları bilmesi gerekir:
- hizmetin tam adı, eğer
- hizmetin sağlanması için gerekli parametrelerin listesi ve türleri
- hizmet tarafından döndürülen sonucun türü
Bu unsurlar bilindiğinde, sorgulanan web hizmeti ne olursa olsun istemci-sunucu iletişimi aynı formatı izler. Böylece istemcilerin yazımı standart hale gelir.
- İnternetten gelen saldırılara karşı güvenlik nedeniyle, birçok kuruluş özel ağlara sahiptir ve sunucularının yalnızca belirli bağlantı noktalarını İnternet’e açar: esas olarak web hizmetinin 80 numaralı bağlantı noktası. Diğer tüm bağlantı noktaları kilitlidir. Dolayısıyla, önceki bölümde anlatıldığı gibi istemci-sunucu uygulamaları özel ağ (intranet) içinde oluşturulur ve genellikle dışarıdan erişilemez. Bir hizmeti bir web sunucusunda barındırmak, onu tüm internet topluluğuna erişilebilir hale getirir.
- Web hizmeti, uzak bir nesne olarak modellenebilir. Sunulan hizmetler bu durumda bu nesnenin yöntemleri haline gelir. Bir istemci, bu uzak nesneye sanki yerelmiş gibi erişebilir. Bu, ağ iletişiminin tamamını gizler ve bu katmandan bağımsız bir istemci oluşturulmasına olanak tanır. Bu katman değişirse bile istemcinin değiştirilmesine gerek kalmaz.
- Bir önceki bölümde tanıtılan TCP/IP istemci-sunucu uygulamalarında olduğu gibi, istemci ve sunucu herhangi bir dilde yazılabilir. Aralarında metin satırları alışverişi yaparlar. Bu satırlar iki bölümden oluşur:
- HTTP protokolü için gerekli başlıklar
- mesajın gövdesi. Sunucudan istemciye gönderilen yanıt, XML (eXtensible İşaretleme Dili) biçimindedir. İstemciden sunucuya gönderilen bir istek için mesajın gövdesi, XML dahil olmak üzere çeşitli biçimlerde olabilir. İstemciden gelen XML isteği, SOAP (Simple Object Access Protocol) adı verilen özel bir biçime sahip olabilir. Bu durumda, sunucunun yanıtı da SOAP biçimini izler.
Bir web hizmeti tabanlı istemci/sunucu uygulamasının mimarisi şu şekildedir:
![]() |
Bu, özel ağ iletişim sınıflarının eklendiği 3 katmanlı mimarinin bir uzantısıdır. Benzer bir mimariye, 11.9.1. paragrafında Windows grafik istemci / TCP vergi sunucusu uygulamasında daha önce rastlamıştık.
Bu genel bilgileri ilk örnekle açıklayalım.
12.2. Visual Web Developer ile ilk web hizmeti
Aşağıdaki basitleştirilmiş mimariye sahip ilk istemci/sunucu uygulamasını oluşturacağız:
![]() |
12.2.1. Sunucu tarafı
Bir web hizmetinin bir web sunucusu tarafından barındırıldığını belirtmiştik. Bir web hizmetinin yazılması, genel olarak sunucu tarafı web programlamasının bir parçasıdır. Daha önce web istemcileri yazma fırsatımız olmuştu; bu da web programlamanın bir parçasıdır, ancak bu sefer istemci tarafında gerçekleşir. "Web programlama" terimi, genellikle istemci tarafı programlamadan ziyade sunucu tarafı programlamayı ifade eder. Web hizmetleri veya daha genel olarak web uygulamaları geliştirmek için Visual C# uygun bir araç değildir. Visual Studio 2008’in Express sürümlerinden biri olan Visual Developer’ı kullanacağız; bu sürümü [2] adresinden indirebilirsiniz: [1] : [http://msdn.microsoft.com/fr-fr/express/future/bb421473(en-us).aspx] (Mayıs 2008) :
![]() |
- [1]: indirme adresi
- [2]: indirme sekmesi
- [3]: Visual Developer 2008'i indirin
İlk web hizmetinizi oluşturmak için, Visual Developer'ı başlattıktan sonra aşağıdaki adımları uygulayabilirsiniz:
![]() |
- [1]: Dosya / Yeni Web Sitesi seçeneğini seçin
- [2]: ASP.NET Web Hizmeti türünde bir uygulama seçin
- [3]: Geliştirme dilini seçin: C#
- [4]: Projenin oluşturulacağı klasörü belirtin
![]() |
- [5]: Visual Web Developer'da oluşturulan proje
- [6]: diskteki proje klasörü
Web Developer'da bir web uygulaması şu şekilde yapılandırılır:
- Web sitesinin belgelerinin (statik HTML web sayfaları, resimler, dinamik .aspx web sayfaları, .asmx web hizmetleri, ...) bulunduğu bir kök dizin. Burada ayrıca, web uygulamasının yapılandırma dosyası olan [web.config] dosyası da bulunur. Bu dosya, Windows uygulamalarındaki [App.config] dosyasıyla aynı işlevi görür ve aynı şekilde yapılandırılmıştır.
- Derlenecek olan web sitesinin sınıflarını ve arayüzlerini içeren bir [App_Code] klasörü.
- [App_Data] klasörü; bu klasöre, [App_Code]'teki sınıflar tarafından kullanılan veriler yerleştirilecektir. Örneğin, burada bir SQL Server *.mdf veritabanı bulunabilir.
[Service.asmx], oluşturulmasını talep ettiğimiz web hizmetidir. İçinde yalnızca şu satır bulunur:
<%@ WebService Language="C#" CodeBehind="~/App_Code/Service.cs" Class="Service" %>
Yukarıdaki kaynak kodu, uygulamayı barındıracak web sunucusu içindir. Üretim modunda bu sunucu genellikle Microsoft’un web sunucusu olan IIS (Internet Information Server) olur. Visual Web Developer, geliştirme modunda kullanılan hafif bir web sunucusu içerir. Önceki yönerge, web sunucusuna şunu belirtir:
- [Service.asmx], C# ile yazılmış bir web hizmetidir (WebService yönergesi)
- C# ile yazılmıştır (Language özniteliği)
- web hizmetinin C# kodu [~/App_Code/Service.cs] dosyasında bulunur (CodeBehind özniteliği). Web sunucusu, derlemek için kodu buradan alacaktır.
- web hizmetini uygulayan sınıfın adı Service'tir (Class özniteliği)
Visual Developer tarafından oluşturulan web hizmetinin C# kodu [Service.cs] şu şekildedir:
using System.Web.Services;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// Bu Web Hizmetinin ASP.NET AJAX kullanılarak komut dosyasından çağrılabilmesi için aşağıdaki satırın yorum satırını kaldırın.
// [System.Web.Script.Services.ScriptService]
public class Service : System.Web.Services.WebService
{
public Service () {
//Tasarlanmış bileşenler kullanılıyorsa aşağıdaki satırın yorum satırını kaldırın
//InitializeComponent();
}
[WebMethod]
public string HelloWorld() {
return "Hello World";
}
}
Service sınıfı, klasik bir C# sınıfına benzemektedir, ancak dikkat edilmesi gereken birkaç nokta vardır:
- 7. satır: Sınıf, System.Web.Services ad alanında tanımlanan WebService sınıfından türetilmiştir. Bu miras alma her zaman zorunlu değildir. Özellikle bu örnekte, bu miras almadan da yapılabilirdi.
- 3. satır: Sınıfın başında, web hizmetine bir ad alanı atamak amacıyla [WebService(Namespace="http://tempuri.org/")] özniteliği yer almaktadır. Bir sınıf satıcısı, sınıflarına benzersiz bir ad vermek ve böylece aynı adı taşıyan diğer satıcıların sınıflarıyla çakışmaları önlemek için sınıflarına bir ad alanı atar. Web hizmetleri için de durum aynıdır. Her web hizmeti, benzersiz bir adla tanımlanabilmelidir; burada bu ad http://tempuri.org/’dir. Bu ad herhangi bir şey olabilir. Mutlaka bir HTTP URI biçimine sahip olması gerekmez.
- 15. satır: HelloWorld yönteminin başında, derleyiciye bu yöntemin web hizmetinin uzak istemcileri tarafından görülebilir hale getirilmesi gerektiğini belirten [WebMethod] özniteliği bulunur. Bu özniteliğin önünde bulunmayan bir yöntem, web hizmetinin istemcileri tarafından görülemez. Bu, diğer yöntemler tarafından kullanılan ancak yayınlanmak üzere tasarlanmamış bir dahili yöntem olabilir.
- 9. satır: Web hizmetinin oluşturucusu. Uygulamamızda buna gerek yoktur.
Oluşturulan [Service.cs] sınıfı şu şekilde dönüştürülür:
using System.Web.Services;
[WebService(Namespace = "http://st.istia.univ-angers.fr")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
[WebMethod]
public string DisBonjourALaDame(string nomDeLaDame) {
return string.Format("Bonjour Mme {0}", nomDeLaDame);
}
}
Web uygulaması için oluşturulan [web.config] yapılandırma dosyası şöyledir:
<?xml version="1.0"?>
<!--
Note: As an alternative to hand editing this file you can use the
web admin tool to configure settings for your application. Use
the Website->Asp.Net Configuration option in Visual Studio.
A full list of settings and comments can be found in
machine.config.comments usually located in
\Windows\Microsoft.Net\Framework\v2.x\Config
-->
<configuration>
<configSections>
<sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
...
</sectionGroup>
</configSections>
<appSettings/>
<connectionStrings/>
...
</configuration>
Dosya 140 satırdan oluşmaktadır. Dosya karmaşıktır ve üzerinde yorum yapmayacağız. Dosyayı olduğu gibi bırakacağız. Yukarıda <configuration>, <configSections>, <sectionGroup>, <appSettings>, <connectionString> etiketleri bulunmaktadır; bu etiketleri Windows uygulamalarının [App.config] dosyasında da görmüştük.
Çalıştırılabilen bir web hizmetimiz var:
![]() |
- [1,2]: [Service.asmx] dosyasına sağ tıklayıp sayfayı tarayıcıda görüntülemeyi seçiyoruz
- [3]: Visual Web Developer, yerleşik web sunucusunu başlatır ve sunucunun simgesini görev çubuğunun sağ alt köşesine yerleştirir. Web sunucusu rastgele bir bağlantı noktasında başlatılır; burada 1906. Görüntülenen URI /WsHello, [4] adlı web sitesinin adıdır.
Visual Web Developer, istenen sayfayı (yani [Service.asmx]) görüntülemek için bir tarayıcı da başlatmıştır:
![]() |
- [1]'te, sayfanın URI'si. Burada, [http://localhost:1906/WsHello] web sitesinin URI'si ve ardından /Service.asmx sayfasının URI'si yer almaktadır.
- [2]'te, .asmx uzantısı web sunucusuna bunun bir HTML sayfası oluşturan normal bir web sayfası (.aspx uzantısı) değil, bir web hizmeti sayfası olduğunu belirtmiştir. Ardından, [WebMethod] özniteliğine sahip web hizmetinin her bir yöntemi için bir bağlantı içeren bir web sayfası otomatik olarak oluşturulur. Bu bağlantılar, yöntemleri test etmeye yarar.
Yukarıdaki [2] bağlantısına tıkladığımızda şu sayfaya yönlendiriliyoruz:
![]() |
- [1] adresinde, yeni sayfanın URI'si olan [http://localhost:1906/WsHello/Service.asmx?op=DisBonjourALaDame]'e dikkat edin. Bu, op=M parametresine sahip web hizmetinin URI’sidir; burada M, web hizmetinin yöntemlerinden birinin adıdır.
- [DisBonjourALaDame] yönteminin imzasını hatırlayalım:
public string DisBonjourALaDame(string nomDeLaDame) ;
Yöntem, string türünde bir parametre kabul eder ve yine string türünde bir sonuç döndürür. Bu sayfa, [DisBonjourALaDame] yöntemini çalıştırmamıza olanak tanır: [2] alanına nomDeLaDame parametresinin değerini girip, [3] alanından yöntemin çalıştırılmasını talep ediyoruz. Aşağıdaki sonucu elde ediyoruz:
![]() |
- [1]'te, yanıtın URI'sinin istekinkiyle aynı olmadığına dikkat edilmelidir. Değişmiştir.
- [2]'te, web sunucusunun yanıtı. Aşağıdaki noktalara dikkat edilmelidir:
- Bu, HTML değil, XML yanıtıdır
- [DisBonjourALaDame] yönteminin sonucu, türünü temsil eden bir <string> etiketine yerleştirilmiştir.
- <string> etiketinin xmlns (xml name space) özniteliği vardır; bu, web hizmetimize verdiğimiz ad alanıdır (aşağıdaki 1. satır).
[WebService(Namespace = "http://st.istia.univ-angers.fr")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
Web tarayıcısının isteğini nasıl oluşturduğunu öğrenmek için test formunun HTML koduna bakmak gerekir:
- 11. satır: Formun değerleri (form etiketi), [ http://localhost:1906/WsHello/Service.asmx/DisBonjourALaDame] URL'sine (action özniteliği) POST yöntemiyle (method özniteliği) gönderilecektir.
- 19. satır: Giriş alanı nomDeLaDame olarak adlandırılmıştır (name özniteliği).
[/Service.asmx] web hizmetinin çalıştırılmasını talep etmek, bu hizmetin yöntemlerini test etmemizi ve istemci-sunucu iletişimi hakkında asgari düzeyde bir anlayış kazanmamızı sağladı.
12.2.2. İstemci tarafı
![]() |
Yukarıdaki uzak web hizmetinin istemcisini temel bir TCP/IP istemcisi ile uygulamak mümkündür. Aşağıda, uzak web hizmetine (localhost,1906) bağlı bir putty istemcisi ile gerçekleştirilen istemci/sunucu diyaloğuna bir örnek verilmiştir:
- 1-5. satırlar: putty istemcisi tarafından gönderilen mesajlar
- 1. satır: POST komutu
- 6-10. satırlar: sunucunun yanıtı. Bu, istemcinin POST değerlerini gönderebileceği anlamına gelir.
- satır 11: param1=val1¶m2=val2& biçiminde gönderilen değerler.... Bazı karakterler, bir URL'de kabul edilebilir karakterler olmalıdır. Buna daha önce "kodlanmış URL" denmişti. Burada formun nomDeLaDame adlı tek bir parametresi vardır. Gönderilen değer toplamda 23 karakterden oluşur. Bu uzunluk, 4. satırdaki HTTP başlığında belirtilmelidir.
- 12-22. satırlar: sunucunun yanıtı
- 22. satır: [DisBonjourALaDame] web yönteminin sonucu.
Visual C# ile bir sihirbaz yardımıyla uzak bir web hizmetinin istemcisini oluşturmak mümkündür. Şimdi bunu inceleyeceğiz.
![]() |
Yukarıdaki [1] katmanı, Windows Uygulaması türünde ve ClientWsHello adlı bir Visual Studio C# projesi ile uygulanır:
![]() |
- [1]'te, Visual C#'daki ClientWsHello projesi
- [2]'e dönüştürüldüğünde, projenin varsayılan ad alanı Client olacaktır (projeye sağ tıklayın / Özellikler / Uygulama). Bu ad alanı, oluşturulacak istemcinin ad alanını oluşturmak için kullanılacaktır.
- [3]'te, projeye sağ tıklayarak uzak bir web hizmetine referans ekleyin
![]() |
- [4]'te, daha önce oluşturulan web hizmetinin URI'sini girin
- [4b]'te, Visual C#'ı [4] ile belirtilen web hizmetine bağlayın. Visual C#, web hizmetinin tanımını alacak ve bu tanım sayesinde bir istemci oluşturabilecektir.
- [5]'te, web hizmetinin açıklaması alındıktan sonra, Visual C# bu hizmetin genel yöntemlerini görüntüleyebilir
- [6]'te, oluşturulacak istemci için bir ad alanı belirtin. Bu, [2]'te tanımlanan ad alanına eklenecektir. Böylece istemcinin ad alanı Client.WsHello olacaktır.
- [6b]'te sihirbazı onaylayın.
- [7]'te, WsHello web hizmetine yapılan referans projede görünür. Ayrıca, [app.config] adlı bir yapılandırma dosyası oluşturulmuştur.
- [8]'te, projedeki tüm dosyaları görüntüleyin.
- [9]'te, WsHello web hizmetine yapılan referans, burada ayrıntılı olarak açıklamayacağımız çeşitli dosyalar içerir. Ancak, oluşturulan istemci C# kodu olan [Reference.cs] dosyasına bir göz atacağız:
namespace Client.WsHello {
...
public partial class ServiceSoapClient : System.ServiceModel.ClientBase<Client.WsHello.ServiceSoap>, Client.WsHello.ServiceSoap {
public ServiceSoapClient() {
}
...
public string DisBonjourALaDame(string nomDeLaDame) {
Client.WsHello.DisBonjourALaDameRequest inValue = new Client.WsHello.DisBonjourALaDameRequest();
inValue.Body = new Client.WsHello.DisBonjourALaDameRequestBody();
inValue.Body.nomDeLaDame = nomDeLaDame;
Client.WsHello.DisBonjourALaDameResponse retVal = ((Client.WsHello.ServiceSoap)(this)).DisBonjourALaDame(inValue);
return retVal.Body.DisBonjourALaDameResult;
}
}
}
- 1. satır: Oluşturulan istemcinin ad alanı Client.WsHello'tir. Bu ad alanını değiştirmek isterseniz, bunu buradan yapmanız gerekir.
- 3. satır: ServiceSoapClient sınıfı, oluşturulan istemcinin sınıfıdır. Bu, Windows uygulamasından uzak bir web hizmetinin kullanıldığını gizleyeceği için bir proxy sınıfıdır. Windows uygulaması, yerel Client.WsHello.ServiceSoapClient sınıfı aracılığıyla uzak WsHello sınıfını kullanacaktır. İstemcinin bir örneğini oluşturmak için 5. satırdaki oluşturucu kullanılacaktır:
- 8. satır: DisBonjourALaDame yöntemi, web hizmetindeki DisBonjourALaDame yönteminin istemci tarafındaki karşılığıdır. Windows uygulaması, yerel Client.WsHello.ServiceSoapClient.DisBonjourALaDame yöntemi aracılığıyla uzaktaki DisBonjourALaDame yöntemini aşağıdaki biçimde kullanacaktır:
Oluşturulan [app.config] dosyası şöyledir:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
....
</bindings>
<client>
<endpoint address="http://localhost:1906/WsHello/Service.asmx"... />
</client>
</system.serviceModel>
</configuration>
Bu dosyadan, web hizmetinin URI'sini içeren 8. satırı alacağız. URI değişirse, Windows istemcisinin yeniden derlenmesine gerek yoktur. Yalnızca [app.config] dosyasındaki URI'yi değiştirmek yeterlidir.
Şimdi, oluşturmak istediğimiz Windows uygulamasının mimarisine geri dönelim:
![]() |
Web hizmetinin [client] katmanını oluşturduk. [ui] katmanı ise şöyle olacaktır:
![]() |
No. | tür | ad | rol |
1 | TextBox | textBoxNomDame | bayanın adı |
2 | Button | buttonSalutations | uzaktaki WsHello web hizmetine bağlanmak ve DisBonjourALaDame yöntemini sorgulamak için. |
3 | Etiket | labelBonjour | web hizmeti tarafından döndürülen sonuç |
[Form1.cs] form kodunun içeriği şöyledir:
using System;
using System.Windows.Forms;
using Client.WsHello;
namespace ClientSalutations {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void buttonSalutations_Click(object sender, EventArgs e) {
// kum saati
Cursor=Cursors.WaitCursor;
// web hizmeti sorgulama
labelBonjour.Text = new ServiceSoapClient().DisBonjourALaDame(textBoxNomDame.Text.Trim());
// normal imleç
Cursor = Cursors.Arrow;
}
}
}
- 15. satır: Web hizmetinin istemcisi oluşturulur. Türü Client.WsHello.ServiceSoapClient'tir. Client.WsHello ad alanı 3. satırda tanımlanmıştır. ServiceSoapClient().DisBonjourALaDame yerel yöntemi çağrılır. Bu yöntemin, web hizmetindeki aynı adlı uzak yöntemi çağırdığı bilinmektedir.
12.3. Aritmetik işlemler için bir web hizmeti
Yine aşağıdaki basitleştirilmiş mimariye sahip ikinci bir istemci/sunucu uygulaması oluşturacağız:
![]() |
Önceki web hizmeti tek bir yöntem sunuyordu. Şimdi ise dört aritmetik işlemi sunacak bir web hizmeti ele alacağız:
- a+b sonucunu veren ekle(a,b)
- çıkarma(a,b) – a-b sonucunu verir
- çarpma(a,b) – a*b sonucunu verir
- bölme(a,b) – a/b sonucunu verir
ve aşağıdaki grafik arayüz üzerinden sorgulanacak olan bir web hizmeti ele alalım:
![]() |
- [1]'te, yapılacak işlem
- [2,3]: işlenecek değerler
- [4]'te, web hizmetini çağırma düğmesi
- [5]'te, web hizmeti tarafından döndürülen sonuç
12.3.1. Sunucu tarafı
Visual Web Developer ile bir web hizmeti projesi oluşturuyoruz:
![]() |
- [1]'te, oluşturulan web uygulaması WsOperations
- [2]'te, WsOperations web uygulaması şu şekilde yeniden tasarlandı:
- [Service.asmx] adlı web sayfası, [Operations.asmx] olarak yeniden adlandırıldı
- [Service.cs] sınıfı, [Operations.cs] olarak yeniden adlandırıldı
- [web.config] dosyası, gerekli olmadığı gösterilmek üzere silinmiştir.
[Service.asmx] web sayfasında şu satır yer almaktadır:
<%@ WebService Language="C#" CodeBehind="~/App_Code/Operations.cs" Class="Operations" %>
Web hizmeti, aşağıdaki [Operations.cs] sınıfı tarafından sağlanmaktadır:
using System.Web.Services;
[WebService(Namespace = "http://st.istia.univ-angers.fr/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Operations : System.Web.Services.WebService
{
[WebMethod]
public double Ajouter(double a, double b)
{
return a + b;
}
[WebMethod]
public double Soustraire(double a, double b)
{
return a - b;
}
[WebMethod]
public double Multiplier(double a, double b)
{
return a * b;
}
[WebMethod]
public double Diviser(double a, double b)
{
return a / b;
}
}
Web hizmetini yayına almak için [3]'te belirtildiği şekilde ilerliyoruz. Böylece, WsOperations web hizmetinin 4 yöntemini içeren test sayfasını elde ediyoruz:

Okuyucunun bu 4 yöntemi test etmesi önerilir.
12.3.2. İstemci tarafı
![]() |
Visual C# ile ClientWsOperations adlı bir Windows uygulaması oluşturuyoruz:
![]() |
- [1]'te, Visual C#'daki ClientWsOperations projesi
- [2]'te, projenin varsayılan ad alanı Client olacaktır (projeye sağ tıklayın / Özellikler / Uygulama). Bu ad alanı, oluşturulacak istemci ad alanını oluşturmak için kullanılacaktır.
- [3]'te, projeye sağ tıklayarak mevcut bir web hizmetine referans ekleyin
![]() |
- [4]'te, daha önce oluşturulan web hizmetinin URI'sini girin. Bunun için, web hizmetinin test sayfasını görüntüleyen tarayıcının adres çubuğunda ne yazdığını kontrol etmeniz gerekir.
- [4b]'te, Visual C#'ı [4] ile belirtilen web hizmetine bağlayın. Visual C#, web hizmetinin açıklamasını alacak ve bu açıklama sayesinde bir istemci oluşturabilecektir.
- [5]'te, web hizmetinin açıklaması alındıktan sonra, Visual C# bu hizmetin genel yöntemlerini görüntüleyebilir
- [6]'te, oluşturulacak istemci için bir ad alanı belirtin. Bu, [2]'te tanımlanan ad alanına eklenecektir. Böylece istemcinin ad alanı Client.WsOperations olacaktır.
- [6b]'te sihirbazı onaylayın.
- [7]'te, WsOperations web hizmetine yapılan referans projede görünür. Ayrıca, [app.config] adlı bir yapılandırma dosyası oluşturulmuştur.
Oluşturulan istemcinin Client.WsOperations.OperationsSoapClient türü olduğunu hatırlatırız; burada
- Client.WsOperations, web hizmeti istemcisinin ad alanıdır
- Operations ise uzak web hizmetinin sınıfıdır.
Bu adı mantıklı bir şekilde oluşturmanın bir yolu olsa da, varsayılan olarak gizli olan [Reference.cs] dosyasında bulmak genellikle daha kolaydır. Dosyanın içeriği şöyledir:
namespace Client.WsOperations {
...
public partial class OperationsSoapClient : System.ServiceModel.ClientBase<Client.WsOperations.OperationsSoap>, Client.WsOperations.OperationsSoap {
public OperationsSoapClient() {
}
...
public double Ajouter(double a, double b) {
...
}
public double Soustraire(double a, double b) {
...
}
public double Multiplier(double a, double b) {
...
}
public double Diviser(double a, double b) {
...
}
}
}
Uzak web hizmetinin Ajouter, Soustraire, Multiplier ve Diviser yöntemlerine, Client.WsOperations.OperationsSoapClient tipi istemcinin (satır 3) aynı adlı proxy yöntemleri (satır 8, 12, 16, 20) aracılığıyla erişilecektir.
Geriye grafik arayüzü oluşturmak kalıyor:
![]() |
no | tür | ad | rol |
1 | ComboBox | comboBoxOperations | aritmetik işlemler listesi |
2 | TextBox | textBoxA | a sayısı |
3 | TextBox | textBoxB | sayı b |
4 | Düğme | buttonExécuter | uzaktaki web hizmetini sorgular |
5 | Etiket | labelRésultat | işlemin sonucu |
[Form1.cs] kodunun sonucu şöyledir:
using System;
using System.Windows.Forms;
using Client.WsOperations;
namespace ClientWsOperations {
public partial class Form1 : Form {
// işlem tablosu
private string[] opérations = { "Ajouter", "Soustraire", "Multiplier", "Diviser" };
// iletişim kurulacak web hizmeti
private OperationsSoapClient opérateur = new OperationsSoapClient();
// oluşturucu
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
// işlemlerin açılır menü ile doldurulması
comboBoxOperations.Items.AddRange(opérations);
comboBoxOperations.SelectedIndex = 0;
}
private void buttonExécuter_Click(object sender, EventArgs e) {
// işlemin a ve b parametrelerinin doğrulanması
textBoxMessage.Text = "";
bool erreur = false;
Double a = 0;
if (!Double.TryParse(textBoxA.Text, out a)) {
textBoxMessage.Text += "Nombre a erroné...";
}
Double b = 0;
if (!Double.TryParse(textBoxB.Text, out b)) {
textBoxMessage.Text += String.Format("{0}Nombre b erroné...", Environment.NewLine);
}
if (erreur) {
return;
}
// işlemin yürütülmesi
Double c=0;
try {
switch (comboBoxOperations.SelectedItem.ToString()) {
case "Ajouter":
c=opérateur.Ajouter(a, b);
break;
case "Soustraire":
c=opérateur.Soustraire(a, b);
break;
case "Multiplier":
c=opérateur.Multiplier(a, b);
break;
case "Diviser":
c=opérateur.Diviser(a, b);
break;
}
// sonucun görüntülenmesi
labelRésultat.Text = c.ToString();
} catch (Exception ex) {
textBoxMessage.Text = ex.Message;
}
}
}
}
- 3. satır: Uzak web hizmeti istemcisinin ad alanı
- 10. satır: Uzak web hizmetinin istemcisi, formla birlikte başlatılır
- 17-21. satırlar: İşlem listesi, formun ilk yüklenmesi sırasında doldurulur
- 23. satır: Kullanıcı tarafından talep edilen işlemin yürütülmesi
- 25-37. satırlar: a ve b girdilerinin gerçekten gerçek sayılar olup olmadığı kontrol edilir
- 41-54. satırlar: Kullanıcı tarafından talep edilen uzaktan işlemi yürütmek için bir switch
- 43, 46, 49, 52. satırlar: Yerel istemci sorgulanır. Yerel istemci, şeffaf bir şekilde uzak web hizmetini sorgular.
12.4. Vergi hesaplama web hizmeti
Artık iyi bilinen vergi hesaplama uygulamasını ele alıyoruz. Bu uygulama üzerinde en son çalıştığımızda, onu internet üzerinden çağrılabilen uzak bir TCP sunucusu haline getirmiştik. Şimdi ise onu bir web hizmeti haline getiriyoruz.
Sürüm 8’in mimarisi şöyleydi:
![]() |
Sürüm 9'un mimarisi de buna benzer olacak:
![]() |
Bu mimari, 11.9.1 numaralı paragrafta incelenen sürüm 8'in mimarisine benziyor, ancak burada TCP sunucusu ve istemcisi, bir web hizmeti ve onun proxy istemcisi ile değiştirilmiştir. Sürüm 8’deki [ui], [metier] ve [dao] katmanlarını aynen devralacağız.
12.4.1. Sunucu kısmı
Visual Web Developer ile bir web hizmeti türü proje oluşturuyoruz:
![]() |
- [1]'te, oluşturulan WsImpot web uygulaması
- [2]'e dönüştürüldü, WsImpot web uygulaması şu şekilde yeniden tasarlandı:
- [Service.asmx] web sayfası, [ServiceImpot.asmx] olarak yeniden adlandırıldı
- [Service.cs] sınıfı, [ServiceImpot .cs] olarak yeniden adlandırıldı
[ServiceImpot.asmx] web sayfası şu satırı içeriyor:
<%@ WebService Language="C#" CodeBehind="~/App_Code/ServiceImpot.cs" Class="ServiceImpot" %>
Web hizmeti, aşağıdaki [ServiceImpot.cs] sınıfı tarafından sağlanmaktadır:
using System.Web.Services;
[WebService(Namespace = "http://st.istia.univ-angers.fr/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class ServiceImpot : System.Web.Services.WebService
{
[WebMethod]
public int CalculerImpot(bool marié, int nbEnfants, int salaire)
{
return 0;
}
}
Web hizmeti, yalnızca 9. satırdaki CalculerImpot yöntemini sunacaktır.
Sürüm 8'in istemci/sunucu mimarisine geri dönelim:
![]() |
[1] sunucusunun Visual Studio projesi şu şekildeydi:
![]() |
- [1] adlı projede. Burada şu öğeler bulunuyordu:
- [ServeurImpot.cs]: Konsol uygulaması biçiminde vergi hesaplama TCP/IP sunucusu.
- [dbimpots.sdf]: 9.8.5. paragrafında açıklanan sürüm 7'ye ait SQL Server compact veritabanı.
- [App.config]: Uygulamanın yapılandırma dosyası.
- [2] içinde, [lib] klasörü proje için gerekli olan DLL dosyalarını içerir:
- [ImpotsV7-dao]: Sürüm 7'nin [dao] katmanı
- [ImpotsV7-metier]: Sürüm 7'nin [metier] katmanı
- [antlr.runtime, CommonLogging, Spring.Core] (Spring için)
- [3]'te, proje referansları
Sürümün [metier] ve [dao] katmanları zaten mevcuttur: bunlar sürüm 7 ve 8'de kullanılan katmanlardır. Bunlar DLL biçimindedir ve bunları projeye şu şekilde entegre ediyoruz:
![]() |
- [1]'e, sürüm 8 sunucusundaki [lib] klasörü, sürüm 9 web hizmeti projesine kopyalandı.
- [2]'te, sayfanın özelliklerini değiştirerek [lib] klasöründeki DLL ve [4] öğelerini [3] projesinin referanslarına ekliyoruz.
Bu işlemden sonra, aşağıdaki [1] sunucusu için gerekli tüm katmanlara sahip oluruz:
![]() |
[1], [serveur], [metier], [dao], [entites], [spring] öğeleri Visual Studio projesinde mevcut olsa da, web uygulamasının başlatılması sırasında bunları örneklendirecek öğe eksiktir. Sürüm 8'de, [Main] statik yöntemine sahip bir ana sınıf, Spring'in yardımıyla katmanları örneklendirme işini yapıyordu. Bir web uygulamasında, benzer bir işi yapabilen sınıf, [Global.asax] dosyasına ( ) bağlı sınıftır:
![]() |
- [1] dosyasında, web projesine yeni bir öğe eklenir
- [2]'te, Global Application Class türü seçilir
- [3]'te, bu öğe için önerilen varsayılan ad
- [4]'te, eklenmesini onaylayın
- [5]'te, yeni öğe projeye eklenmiştir
[Global.asax] dosyasının içeriğine bir göz atalım:
<%@ Application Language="C#" %>
<script runat="server">
void Application_Start(object sender, EventArgs e)
{
// Uygulama başlangıcında çalışan kod
}
void Application_End(object sender, EventArgs e)
{
// Uygulama kapatıldığında çalışan kod
}
void Application_Error(object sender, EventArgs e)
{
// İşlenmemiş bir hata oluştuğunda çalışan kod
}
void Session_Start(object sender, EventArgs e)
{
// Yeni bir oturum başlatıldığında çalışan kod
}
void Session_End(object sender, EventArgs e)
{
// Oturum sona erdiğinde çalışan kod.
}
</script>
Dosya, web sunucusuna yönelik etiketler (1., 3. ve 30. satırlar) ile C# kodunun bir karışımıdır. Bu yöntem, Microsoft’un web programlama için kullandığı mevcut teknoloji olan ASP.NET’in öncülü olan ASP ile kullanılan tek yöntemdi. ASP.NET ile bu yöntem hâlâ kullanılabilir, ancak varsayılan yöntem değildir. Varsayılan yöntem, “CodeBehind” olarak adlandırılan ve web hizmetleri sayfalarında karşılaştığımız yöntemdir; örneğin burada, [ServiceImpot.asmx]’te:
<%@ WebService Language="C#" CodeBehind="~/App_Code/ServiceImpot.cs" Class="ServiceImpot" %>
CodeBehind özniteliği, [ServiceImpot.asmx] sayfasının kaynak kodunun nerede bulunduğunu belirtir. Bu öznitelik olmasaydı, kaynak kodu [ServiceImpot.asmx] sayfasında, [Global.asax]'te bulunan sözdizimine benzer bir sözdizimiyle yer alırdı. [Global.asax] dosyasını oluşturulduğu haliyle saklamayacağız, ancak kodunu inceleyerek ne işe yaradığını anlayabiliriz:
- Global.asax ile ilişkili sınıf, uygulamanın başlatılması sırasında örneklenir. Ömrü, uygulamanın tamamının ömrü kadardır. Somut olarak, yalnızca web sunucusu durdurulduğunda ortadan kalkar.
- Ardından Application_Start yöntemi yürütülür. Bu, yöntemin yürütüleceği tek zamandır. Bu nedenle, tüm kullanıcılar arasında paylaşılan nesneleri oluşturmak için kullanılır. Bu nesneler şu konumlara yerleştirilir:
- ya da Global.asax ile ilişkili sınıfın statik alanlarında. Bu sınıf kalıcı olarak mevcut olduğundan, herhangi bir kullanıcı herhangi bir sorgu yoluyla buradaki bilgileri okuyabilir.
- ya da Application konteyneri. Bu konteyner de uygulamanın başlatılmasıyla oluşturulur ve ömrü uygulamanın ömrü kadardır.
- Bu konteynere veri eklemek için Application["clé"]=değer yazılır;
- veriyi almak için ise T değer=(T)Application["clé"]; yazılır; burada T, valeur'in türüdür.
- Session_Start yöntemi, her yeni kullanıcı bir istek gönderdiğinde yürütülür. Yeni bir kullanıcı nasıl tanınır? Her kullanıcı (çoğunlukla bir tarayıcı), ilk isteğinin ardından, her kullanıcı için benzersiz bir karakter dizisi olan bir oturum jetonu alır. Ardından kullanıcı, yaptığı her yeni istekte aldığı oturum jetonunu geri gönderir. Bu, web sunucusunun kullanıcıyı tanımasını sağlar. Aynı kullanıcının farklı istekleri sırasında, kullanıcıya özgü veriler Session konteynerinde saklanabilir:
- bu kapsayıcıya bir veri eklemek için Session["clé"]=değer yazılır;
- bu veriyi geri almak için ise T değer=(T)Session["clé"]; yazılır; burada T, valeur'in türüdür.
Bir oturumun ömrü, varsayılan olarak kullanıcının 20 dakika boyunca etkin olmamasına bağlı olarak sınırlandırılmıştır (c.a.d. yani, kullanıcı 20 dakikadır oturum jetonunu geri göndermedi).
- Application_Error yöntemi, web uygulaması tarafından yönetilmeyen bir istisna web sunucusuna ulaştığında yürütülür.
- Diğer yöntemler daha nadiren kullanılır.
Bu genel bilgilerin ardından, Global.asax bize ne işe yarayabilir? Application_Start yöntemini kullanarak [metier] katmanlarını başlatacağız, [dao] ve [entites] katmanlarını başlatmak için kullanacağız. Bunları oluşturmak için Spring'i kullanacağız. Bu şekilde oluşturulan katmanların referansları daha sonra Global.asax ile ilişkili sınıfın statik alanlarında saklanacaktır.
İlk adım olarak, Global.asax'teki C# kodunu ayrı bir sınıfa taşıyoruz. Proje şu şekilde gelişiyor:
![]() |
[1]'te, [Global.asax] dosyası, aşağıdaki tek satırı içeren [Global.cs] [2] sınıfıyla ilişkilendirilecektir:
<%@ Application Language="C#" Inherits="WsImpot.Global"%>
Inherits="WsImpot.Global" özniteliği, Global.asax ile ilişkilendirilen sınıfın WsImpot.Global sınıfından miras aldığını belirtir. Bu sınıf, [Global.cs] içinde şu şekilde tanımlanmıştır:
using System;
using Metier;
using Spring.Context.Support;
namespace WsImpot
{
public class Global : System.Web.HttpApplication
{
// iş mantığı katmanı
public static IImpotMetier Metier;
// Uygulamanın başlatılması sırasında yürütülen yöntem
private void Application_Start(object sender, EventArgs e)
{
// [metier] ve [dao] katmanlarının örneklendirilmesi
Metier = ContextRegistry.GetContext().GetObject("metier") as IImpotMetier;
}
}
}
- 4. satır: sınıfın ad alanı
- 6. satır: Global sınıfı. Bu sınıfa istediğiniz adı verebilirsiniz. Önemli olan, System.Web.HttpApplication sınıfından türetilmiş olmasıdır.
- 9. satır: [metier] katmanına bir referans içerecek olan statik bir public alan.
- 12. satır: Uygulamanın başlatılması sırasında çalıştırılacak Application_Start yöntemi.
- 15. satır: Spring, [web.config] dosyasını işlemek için kullanılır; bu dosyada, [metier] ve [dao] katmanlarını oluşturmak üzere örneklenecek nesneler bulunur. Bir Windows uygulamasında [App.config] ile Spring'in kullanılması ile bir web uygulamasında [web.config] ile Spring'in kullanılması arasında hiçbir fark yoktur. [web.config] ve [App.config] de aynı yapıya sahiptir. 15. satır, [metier] katmanının referansını 9. satırdaki statik alana kaydeder; böylece bu referans, tüm kullanıcıların tüm istekleri için kullanılabilir hale gelir.
[web.config] dosyası şu şekilde olacaktı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 name="dao" type="Dao.DataBaseImpot, ImpotsV7-dao">
<constructor-arg index="0" value="MySql.Data.MySqlClient"/>
<constructor-arg index="1" value="Server=localhost;Database=bdimpots;Uid=admimpots;Pwd=mdpimpots;"/>
<constructor-arg index="2" value="select limite, coeffr, coeffn from tranches"/>
</object>
<object name="metier" type="Metier.ImpotMetier, ImpotsV7-metier">
<constructor-arg index="0" ref="dao"/>
</object>
</objects>
</spring>
</configuration>
Bu, uygulamanın 7. sürümünde kullanılan ve 9.8.4. paragrafında incelenen [App.config] dosyasıdır.
- 16-20. satırlar: MySQL5 veritabanıyla çalışan bir [dao] katmanını tanımlar. Bu veritabanı 9.8.1. paragrafında açıklanmıştır.
- 21-23. satırlar: [metier] katmanını tanımlar
Sunucu bulmacasına geri dönelim:
![]() |
Uygulamanın başlatılmasıyla birlikte, [metier] ve [dao] katmanları oluşturulmuştur. Katmanların ömrü, uygulamanın ömrüyle aynıdır. Web hizmeti ne zaman oluşturulur? Aslında, kendisine yapılan her istekle birlikte. İsteğin sonunda, isteği işleyen nesne silinir. Dolayısıyla bir web hizmeti ilk bakışta durum bilgisi içermez. İki istek arasında kendisine ait alanlarda bilgi depolayamaz. Ancak kullanıcının oturumunda bilgi depolayabilir. Bunun için, hizmetin sunduğu yöntemler özel bir öznitelikle etiketlenmelidir:
[WebMethod(EnableSession=true)]
public int CalculerImpot(bool marié, int nbEnfants, int salaire)
....
Yukarıda, 1. satır, CalculerImpot yönteminin daha önce bahsettiğimiz Session konteynerine erişmesine izin vermektedir. Uygulamamızda bu özniteliği kullanmamız gerekmeyecek. Dolayısıyla, WsImpot web hizmeti her istek sırasında örneklenecek ve durum bilgisi içermeyecektir.
Şimdi, web hizmetini uygulayan [ServiceImpot.cs] kodunu yazabiliriz:
using System.Web.Services;
using WsImpot;
[WebService(Namespace = "http://st.istia.univ-angers.fr/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class ServiceImpot : System.Web.Services.WebService
{
[WebMethod]
public int CalculerImpot(bool marié, int nbEnfants, int salaire)
{
return Global.Metier.CalculerImpot(marié, nbEnfants, salaire);
}
}
- 10. satır: web hizmetinin tek yöntemi
- 12. satır: [metier] katmanındaki CalculerImpot yöntemi kullanılır. Bu katmanın bir referansı, Global sınıfının Metier statik alanında bulunur. Bu katman, WsImpot ad alanına aittir (satır 2).
Web hizmetini başlatmaya hazırız. Öncelikle, bdimpots veritabanına erişilebilmesi için SGBD ve MySQL5'i başlatmamız gerekir. Bu işlem tamamlandıktan sonra, [1] web hizmetini başlatıyoruz:
![]() |
Tarayıcı, [2] sayfasını görüntüler. Bağlantıyı takip ediyoruz:
![]() |
CalculerImpot yönteminin üç parametresinin her birine bir değer atar ve yöntemin çalıştırılmasını talep ederiz. Aşağıdaki doğru sonucu elde ederiz:

12.4.2. Uzak web hizmeti için bir Windows grafik istemcisi
Web hizmeti yazıldığına göre, şimdi istemciye geçelim. İstemci/sunucu uygulama mimarisine tekrar göz atalım:
![]() |
[2] istemcisini yazmamız gerekiyor. Grafik arayüzü, sürüm 8'dekiyle aynı olacaktır:
![]() |
Sürüm 9'un [client] kısmını yazmak için, sürüm 8'in [client] kısmından başlayacağız ve ardından gerekli değişiklikleri yapacağız. 11.9.4.1 numaralı paragrafta incelediğimiz Visual Studio projesini kopyalayıp, adını ClientWsImpot olarak değiştirip Visual Studio’ya yükleyeceğiz:
![]() |
Sürüm 8'deki Visual Studio çözümü 2 projeden oluşuyordu:
- [metier] projesi, vergi hesaplama TCP sunucusunun bir TCP istemcisiydi
- grafik kullanıcı arayüzü projesi olan [ui] ve [2].
Yapılması gereken değişiklikler şunlardır:
- [metier] projesi artık bir web hizmetinin istemcisi olmalıdır
- [ui] projesi, yeni [metier] katmanındaki DLL'e referans vermelidir
- [App.config] içindeki [metier] katmanının yapılandırması değiştirilmelidir.
12.4.2.1. Yeni [metier] katmanı
![]() |
- [1]'te, IImpotMetier, [metier] katmanının arayüzüdür ve ImpotMetierTcp, bir TCP istemcisi tarafından
- [2]'te, ImpotMetierTcp uygulamasını kaldırıyoruz. Bir web hizmetinin istemcisi olacak IImpotMetier arayüzünün başka bir uygulamasını oluşturmamız gerekiyor.
- [3]'te, [metier] projesinin varsayılan ad alanını Client olarak adlandırıyoruz. Oluşturulacak DLL, [ImpotsV9-metier.dll] olarak adlandırılacaktır.
![]() |
- [4] dosyasında, WsImpot web hizmetine bir referans oluşturuyoruz.
- [5]'te, bunu yapılandırıp onaylıyoruz.
- [6] dosyasında, WsImpot web hizmetine bir referans oluşturuldu ve [app.config] dosyası oluşturuldu.
Gizli dosya [Reference.cs]'te:
- ad alanı Client.WsImpot'tir
- istemci sınıfının adı ServiceImpotSoapClient'tir
- tek bir imza yöntemi vardır:
public int CalculerImpot(bool marié, int nbEnfants, int salaire) ;
Geriye IImpotMetier arayüzünü uygulamak kalıyor:
namespace Metier {
public interface IImpotMetier {
int CalculerImpot(bool marié, int nbEnfants, int salaire);
}
}
Bunu aşağıdaki ImpotMetierWs sınıfıyla uyguluyoruz:
using System.Net.Sockets;
using System.IO;
using Client.WsImpot;
namespace Metier {
public class ImpotMetierWs : IImpotMetier {
// uzak web hizmeti istemcisi
private ServiceImpotSoapClient client = new ServiceImpotSoapClient();
// vergi hesaplaması
public int CalculerImpot(bool marié, int nbEnfants, int salaire) {
return client.CalculerImpot(marié, nbEnfants, salaire);
}
}
}
- 6. satır: ImpotMetierWs sınıfı, IImpotMetier arayüzünü uygular.
- 9. satır: Bir ImpotMetierWs örneği oluşturulduğunda, client alanı, vergi hesaplama web hizmetinin bir istemcisinin örneği ile başlatılır.
- 12. satır: IImpotMetier arayüzünün uygulanması gereken tek yöntem.
- 13. satır: Vergi hesaplama uzaktan web hizmetinin istemcisindeki CalculerImpot yöntemi kullanılır. Sonuç olarak, uzaktan web hizmetinin CalculerImpot yöntemi çağrılacaktır.
Projeden DLL dosyası oluşturulabilir:
![]() |
- [1]'e dönüştürülebilir; [client] projesi nihai haliyle
- [2]'e dönüştürülür; projenin DLL dosyası
- [3]'e dönüştürülür; DLL ve ImpotsV9-metier.dll, projenin /bin/Release klasöründedir.
12.4.2.2. Yeni katman [ui]
![]() |
Müşterinin [client] katmanı yazıldı. Geriye [ui] katmanını yazmak kaldı. Visual Studio projesine geri dönelim:
![]() |
- [1]'te, sürüm 8'den türetilen [ui] projesi
- [2]'e, eski katmandaki DLL ve ImpotsV8-metier, [metier]'in yerine yeni katmandaki DLL ImpotsV9-metier ile değiştirildi
- [3]'te, DLL ve ImpotsV9-metier dosyaları proje referanslarına eklenmiştir.
İkinci değişiklik [App.config] dosyasında yapılmıştır. Bu dosyanın, Spring tarafından [metier] katmanını oluşturmak için kullanıldığını unutmamak gerekir. Bu katman değiştiği için, [App.config] dosyasının yapılandırması da değiştirilmelidir. Öte yandan, [App.config] dosyası, uzaktaki vergi hesaplama web hizmetine bağlanmayı sağlayan yapılandırmaya sahip olmalıdır. Bu yapılandırma, [metier] projesindeki [app.config] dosyasında, uzaktaki web hizmetine referans eklendiğinde oluşturulmuştur.
Böylece [App.config] dosyası şu şekilde olur:
<?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 name="metier" type="Metier.ImpotMetierWs, ImpotsV9-metier">
</object>
</objects>
</spring>
<!-- web hizmeti -->
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ServiceImpotSoap" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:2172/WsImpot/ServiceImpot.asmx"
binding="basicHttpBinding" bindingConfiguration="ServiceImpotSoap"
contract="WsImpot.ServiceImpotSoap" name="ServiceImpotSoap" />
</client>
</system.serviceModel>
</configuration>
- 15-18. satırlar: Spring yalnızca bir nesne oluşturur; [metier] katmanı
- 16. satır: [metier] katmanı, DLL ImpotsV9-metier içinde bulunan [Metier.ImpotMetierWs] sınıfı tarafından örneklenir.
- 22-46. satırlar: Uzak web hizmetinin istemci yapılandırması. Bu, [metier] projesindeki [app.config] dosyasının içeriğinin kopyalanıp yapıştırılmasıyla oluşturulmuştur.
Hazırız. Uygulamayı Ctrl-F5 tuşlarıyla çalıştırıyoruz (web hizmeti başlatılmış olmalı, SGBD ve MySQL5 dosyaları çalıştırılmış olmalı ve yukarıdaki 42. satırdaki bağlantı noktası doğru olmalıdır):
![]() |
12.5. Vergi hesaplama web hizmeti için bir web istemcisi
Az önce yazılan istemci/sunucu uygulama mimarisini tekrar gözden geçirelim:
![]() |
Yukarıdaki [ui] katmanı, bir Windows grafik istemcisi ile uygulanmıştı. Şimdi bunu bir web arayüzü ile uygulayacağız:
![]() |
Bu, kullanıcılar için önemli bir değişikliktir. Şu anda istemci/sunucu uygulamamızın 9. sürümü, aynı anda birden fazla istemciye hizmet verebilmektedir. Bu, bir seferde yalnızca bir istemciye hizmet veren 8. sürüme kıyasla bir gelişmedir. Buradaki kısıtlama, vergi hesaplama web hizmetini kullanmak isteyen kullanıcıların bilgisayarlarında bizim yazdığımız Windows istemcisine sahip olmaları gerektiğidir. 10 sürümü olarak adlandıracağımız bu yeni sürümde, kullanıcılar tarayıcıları aracılığıyla vergi hesaplama web hizmetine erişebilecekler.
Yukarıdaki mimaride:
- sunucu tarafında herhangi bir değişiklik yoktur. Sürüm 9’daki haliyle kalır.
- istemci tarafında, [client du service web] katmanı değişmez. Bu katman, DLL ve [ImpotsV9-metier] içinde kapsüllenmiştir. Bu DLL'i yeniden kullanacağız.
- Sonuç olarak, tek değişiklik bir Windows grafik arayüzünü bir web arayüzüyle değiştirmektir.
Sunucu tarafında web programlamaya ilişkin yeni kavramları ele alacağız. Bu belgenin amacı web programlamayı öğretmek olmadığı için, izlenecek yaklaşımı ayrıntılara girmeden açıklamaya çalışacağız. Dolayısıyla bu bölümde biraz "sihirli" bir yön olacak. Bununla birlikte, katmanlardan birinin değiştirildiği yeni bir çok katmanlı mimari örneği göstermek için bu yaklaşımı benimsemenin ilginç olacağını düşünüyoruz.
Dolayısıyla, sürüm 10’un mimarisi şu şekildedir:
![]() |
[web] katmanı hariç, tüm katmanlara zaten sahibiz. Yapılacakları daha iyi anlayabilmek için, istemci mimarisi hakkında daha ayrıntılı bilgi vermemiz gerekiyor. İstemci mimarisi şu şekilde olacaktır:
![]() |
- Web kullanıcısının tarayıcısında bir web formu bulunmaktadır
- bu form, web sunucusu 1'e gönderilir ve sunucu, formu [web] katmanı aracılığıyla işler
- [web] katmanı, [ImpotsV9-metier.dll] içinde kapsüllenmiş olan uzak web hizmeti istemcisinin hizmetlerine ihtiyaç duyacaktır.
- Uzak web hizmetinin istemcisi, uzak web hizmetini barındıran web sunucusu 2 ile iletişim kuracaktır.
- Uzak web hizmetinin yanıtı, müşterinin web katmanına kadar yükselecek ve müşteri bu yanıtı bir sayfa halinde biçimlendirip kullanıcıya gönderecektir.
Dolayısıyla buradaki görevimiz şudur:
- Kullanıcının tarayıcısında göreceği web formunu oluşturmak
- Kullanıcının isteğini işleyecek ve ona yeni bir web sayfası biçiminde yanıt gönderecek web uygulamasını yazmak. Bu sayfa, aslında ödenecek vergi tutarının eklendiği formla aynı olacaktır
- tüm bunların birlikte çalışmasını sağlayan "bağlayıcı"yı yazmak.
Tüm bunlar, Visual Web Developer ile oluşturulan yeni bir web sitesi yardımıyla gerçekleştirilecektir:
![]() |
- [1]: Dosya / Yeni Web Sitesi seçeneğini seçin
- [2]: ASP.NET Web Sitesi türünde bir uygulama seçin
- [3]: Geliştirme dilini seçin: C#
- [4]: Projenin oluşturulacağı klasörü belirtin
![]() |
- [5]: Visual Web Developer'da oluşturulan proje
- [Default.aspx], “varsayılan sayfa” olarak adlandırılan bir web sayfasıdır. Belge belirtilmeden http://.../ClientAspImpot URL’si istendiğinde görüntülenecek olan sayfadır. Kullanıcının tarayıcısında göreceği vergi hesaplama formunu içeren sayfa budur.
- [Default.aspx.cs], sayfayla ilişkili sınıftır; bu sınıf, kullanıcıya gönderilecek formu oluşturur ve kullanıcı formu doldurup onayladıktan sonra işler.
- [web.config], uygulamanın yapılandırma dosyasıdır. Önceki örneklerin aksine, bu dosyayı koruyacağız.
Şimdi, oluşturmamız gereken mimariye geri dönelim:
![]() |
- [1], [Default.aspx] tarafından uygulanacaktır
- [2], [Default.aspx.cs] tarafından uygulanacaktır
- [3], DLL ve [ImpotV9-metier] tarafından uygulanacak
Öncelikle [3] katmanını uygulamaya başlayalım. Bunun için birkaç adım vardır:
![]() |
- [1]'te, Windows sürüm 9 grafik istemcisinin [lib] klasörü, [ClientAspWsImpot] web projesi klasörüne kopyalanır. Bu işlem Windows Dosya Gezgini ile gerçekleştirilir. Bu klasörün Web Developer çözümünde görünmesi için, [2] düğmesiyle çözümü yenilemeniz gerekir.
- Ardından bunları [3,4,5] projesinin referanslarına ekleyin. Referans verilen DLL'ler, [6] projesinin /bin klasörüne otomatik olarak kopyalanır.
Artık Spring'in çalışması için gerekli DLL'lere sahibiz ve uzak web hizmetinin istemci katmanı da uygulanmıştır. Hizmetin kodu mevcut olsa da, yapılandırması henüz yapılmamıştır. Sürüm 9'da, bu yapılandırma aşağıdaki [App.config] dosyası ile gerçekleştiriliyordu:
<?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 name="metier" type="Metier.ImpotMetierWs, ImpotsV9-metier">
</object>
</objects>
</spring>
<!-- web hizmeti -->
<system.serviceModel>
<bindings>
<basicHttpBinding>
...
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:2172/WsImpot/ServiceImpot.asmx"
binding="basicHttpBinding" bindingConfiguration="ServiceImpotSoap"
contract="WsImpot.ServiceImpotSoap" name="ServiceImpotSoap" />
</client>
</system.serviceModel>
</configuration>
Bu yapılandırmayı aynen alıyoruz ve aşağıdaki şekilde [web.config] dosyasına ekliyoruz:
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.web.extensions"...>
...
</sectionGroup>
<!-- Spring bölümü başlangıcı -->
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
<!-- Spring bölümü sonu -->
</configSections>
<!-- Spring yapılandırmasının başlangıcı -->
<spring>
<context>
<resource uri="config://spring/objects" />
</context>
<objects xmlns="http://www.springframework.net">
<object name="metier" type="Metier.ImpotMetierWs, ImpotsV9-metier">
</object>
</objects>
</spring>
<!-- Spring yapılandırmasının sonu -->
<!-- uzak web hizmetinin istemci yapılandırmasının başlangıcı -->
<system.serviceModel>
<bindings>
<basicHttpBinding>
...
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:2172/WsImpot/ServiceImpot.asmx"
binding="basicHttpBinding" bindingConfiguration="ServiceImpotSoap"
contract="WsImpot.ServiceImpotSoap" name="ServiceImpotSoap" />
</client>
</system.serviceModel>
<!-- uzak web hizmetinin istemci yapılandırmasının sonu -->
<!-- oluşturulan web.config dosyasında zaten mevcut olan diğer yapılandırmalar -->
...
</configuration>
- satırın, uzak web hizmetinin bağlantı noktasını gösterdiğine dikkat edin. Visual Developer, web hizmetini rastgele bir bağlantı noktasında başlattığı için bu bağlantı noktası değişebilir.
Şimdi, oluşturmamız gereken web istemcisinin mimarisine geri dönelim:
![]() |
- [1], [Default.aspx] tarafından uygulanacaktır
- [2], [Default.aspx.cs] tarafından uygulanacaktır
- [3], DLL ve [ImpotV9-metier] tarafından uygulanmıştır
[3] katmanını az önce uyguladık. Şimdi, [Default.aspx] sayfası tarafından uygulanan [1] web arayüzüne geçiyoruz. Tasarım moduna geçmek için [Default.aspx] sayfasına çift tıklayalım.
![]() |
Bir web sayfası oluşturmanın iki yolu vardır:
- [2]'te olduğu gibi grafiksel olarak. Bu durumda, [1]'te [Design] modunu seçmek gerekir. Bu düğme çubuğu, web sayfası düzenleyicisinin durum çubuğunun altında bulunur.
- [3] örneğinde olduğu gibi bir etiket dili kullanarak. Bu durumda, [1]'te [Source] modunu seçmek gerekir.
[Design] ve [Source] modları çift yönlüdür: [Design] modunda yapılan bir değişiklik, [Source] modunda bir değişikliğe yol açar ve bunun tersi de geçerlidir. Tarayıcıda görüntülenecek web formunun şu şekilde olduğunu hatırlatmak isteriz:
![]() |
- [1]'te, tarayıcıda görüntülenen form
- [2], formun oluşturulmasında kullanılan bileşenler
- [3], formun tasarım sayfasıdır. Aşağıdaki öğeleri içerir:
- A satırı, RadioButtonOui ve RadioButtonNon adlı iki radyo düğmesi
- B satırı, TextBoxEnfants adlı bir giriş alanı ve LabelErreurEnfants adlı bir etiket
- C satırı, TextBoxSalaire adlı bir giriş alanı ve LabelErreurSalaire adlı bir etiket
- D satırı, LabelImpot adlı bir etiket
- E satırında, ButtonCalculer ve ButtonEffacer adlı iki düğme
Bir bileşen tasarım yüzeyine yerleştirildiğinde, özelliklerine erişilebilir:
![]() |
- [1]'te, bir bileşenin özelliklerine erişim
- [2]'te, [LabelErreurEnfants ] bileşeninin özellikler sayfası
- [3]'te, (ID) bileşenin adıdır
- [4]'te, etiket üzerindeki karakterlere kırmızı renk verdik.
Form üzerine bileşenleri yerleştirmek ve ardından özelliklerini ayarlamak yeterli değildir. Ayrıca bunların yerleşimini de düzenlemek gerekir. Bir Windows grafik arayüzünde bu yerleşim mutlaktır. Bileşeni olmak istediği yere sürükleyip bırakırız. Bir web sayfasında ise durum farklıdır; daha karmaşıktır ama aynı zamanda daha güçlüdür. Bu konuya burada değinilmeyecektir.
Bu tasarımla oluşturulan [Default.aspx] kaynak kodu şöyledir:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Calculer votre impôt</title>
</head>
<body bgcolor="#ffff99">
<h2>
Calculer votre impôt</h2>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager2" runat="server" EnablePartialRendering="true" />
<asp:UpdatePanel runat="server" ID="UpdatePanelPam">
<ContentTemplate>
<div>
</div>
<table>
<tr>
<td>
Etes-vous marié(e)
</td>
<td>
<asp:RadioButton ID="RadioButtonOui" runat="server" GroupName="statut" Text="Oui" />
<asp:RadioButton ID="RadioButtonNon" runat="server" GroupName="statut" Text="Non"
Checked="True" />
</td>
</tr>
<tr>
<td>
Nombre d'alt öğeler
</td>
<td>
<asp:TextBox ID="TextBoxEnfants" runat="server" Columns="3"></asp:TextBox>
</td>
<td>
<asp:Label ID="LabelErreurEnfants" runat="server" ForeColor="#FF3300"></asp:Label>
</td>
</tr>
<tr>
<td>
Salaire annuel
</td>
<td>
<asp:TextBox ID="TextBoxSalaire" runat="server" Columns="8"></asp:TextBox>
</td>
<td>
<asp:Label ID="LabelErreurSalaire" runat="server" ForeColor="#FF3300"></asp:Label>
</td>
</tr>
<tr>
<td>
Impôt à payer
</td>
<td>
<asp:Label ID="LabelImpot" runat="server" BackColor="#99CCFF"></asp:Label>
</td>
</tr>
</table>
<br />
<table>
<tr>
<td>
<asp:Button ID="ButtonCalculer" runat="server" Text="Calculer" OnClick="ButtonCalculer_Click" />
</td>
<td>
<asp:Button ID="ButtonEffacer" runat="server" Text="Effacer" OnClick="ButtonEffacer_Click" />
</td>
<td>
</td>
</tr>
</table>
</div>
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
Form bileşenleri 23, 24, 33, 36, 44, 47, 55, 63 ve 66. satırlarda görülebilir. Geri kalanı ise esasen biçimlendirmeyle ilgilidir.
Şimdi inşa etmemiz gereken mimariye geri dönelim:
![]() |
- [1], [Default.aspx] tarafından uygulanmıştır
- [2], [Default.aspx.cs] tarafından uygulanacak
- [3], DLL ve [ImpotV9-metier] tarafından uygulanmıştır
[1] ve [3] katmanları artık uygulanmıştır. Geriye, formu oluşturan, kullanıcıya gönderen, kullanıcı tarafından doldurulup geri gönderildiğinde işleyen, vergi hesaplaması için [3] katmanını kullanan, kullanıcıya yanıt web sayfasını oluşturan ve ona geri gönderen [2] katmanını yazmak kaldı. Tüm bu işleri yapan kod [Default.aspx.cs]'tir:
using System;
using WsImpot;
public partial class _Default : System.Web.UI.Page
{
protected void ButtonCalculer_Click(object sender, EventArgs e)
{
...
}
protected void ButtonEffacer_Click(object sender, EventArgs e)
{
...
}
}
Bu kod, klasik bir Windows formunun koduna çok benzemektedir. ASP.NET teknolojisinin en önemli avantajı budur: Windows programlama modeli ile ASP.NET web programlama modeli arasında bir kopukluk yoktur. Sadece şu şemayı her zaman akılda tutmak gerekir:
![]() |
[1]'te kullanıcı [Calculer] düğmesine tıkladığında, [Default.aspx.cs] dosyasının 6. satırındaki ButtonCalculer_Click prosedürü çalıştırılacaktır. Ancak bu sırada:
- doldurulmuş formun değerleri HTTP protokolü aracılığıyla tarayıcıdan web sunucusuna aktarılacak
- ASP.NET sunucusu isteği analiz edecek ve [Default.aspx] sayfasına aktaracaktır
- [Default.aspx] sayfası oluşturulacak.
- bu sayfanın bileşenleri (RadioButtonOui, RadioButtonNon, TextBoxEnfants, TextBoxSalaire, LabelErreurEnfants, LabelErreurSalaire, LabelImpot) "ViewState" adlı bir mekanizma sayesinde, formun tarayıcıya ilk kez gönderildiği andaki değerleriyle başlatılacaktır.
- Gönderilen değerler, ilgili bileşenlere atanacaktır (RadioButtonOui, RadioButtonNon, TextBoxEnfants, TextBoxSalaire). Dolayısıyla, kullanıcı çocuk sayısı olarak 2'yi girmişse, TextBoxEnfants.Text="2" olacaktır.
- [Default.aspx] sayfasında [Page_Load] adlı bir yöntem varsa, bu yöntem çalıştırılacaktır
- 6. satırdaki [ButtonCalculer_Click] yöntemi, [Calculer] düğmesine tıklandığında çalıştırılacaktır
- [Effacer] düğmesine tıklandığında, 10. satırdaki [ButtonEffacer_Click] yöntemi çalıştırılacaktır
Kullanıcının tarayıcısında bir olay oluşturduğu an ile bu olayın [Default.aspx.cs]'te işlendiği an arasında büyük bir karmaşıklık vardır. Bu karmaşıklık gizlidir ve web sayfasının olay işleyicilerini yazarken sanki yokmuş gibi davranılabilir. Ancak, olay ile olay işleyicisi arasında ağın var olduğunu ve bu nedenle, istemci-sunucu arasında maliyetli gidip gelmelere neden olacak Mouse_Move gibi fare olaylarını yönetmenin söz konusu olamayacağını asla unutmamak gerekir...
[Calculer] ve [Effacer] düğmelerine tıklama işleyicilerinin kodu, klasik bir Windows uygulaması için yazılacağı gibi şöyledir:
protected void ButtonCalculer_Click(object sender, EventArgs e)
{
// veri doğrulama
int nbEnfants;
bool erreur = false;
if (!int.TryParse(TextBoxEnfants.Text.Trim(), out nbEnfants) || nbEnfants < 0)
{
LabelErreurEnfants.Text = "Valeur incorrecte...";
erreur = true;
}
int salaire;
if (!int.TryParse(TextBoxSalaire.Text.Trim(), out salaire) || salaire < 0)
{
LabelErreurSalaire.Text = "Valeur incorrecte...";
erreur = true;
}
// hata mı?
if (erreur) return;
// olası hatalar siliniyor
LabelErreurEnfants.Text = "";
LabelErreurSalaire.Text = "";
// medeni durum
bool marié = RadioButtonOui.Checked;
// vergi hesaplaması
try
{
LabelImpot.Text = String.Format("{0} euros",Global.Metier.CalculerImpot(marié, nbEnfants, salaire));
}
catch (Exception ex)
{
LabelImpot.Text = ex.Message;
}
}
- Bu kodu anlamak için şunu bilmek gerekir
- çalışmaya başladığında, [Default.aspx] formunun, kullanıcı tarafından doldurulduğu haliyle mevcut olduğunu bilmek gerekir. Böylece alanlar (RadioButtonOui, RadioButtonNon, TextBoxEnfants, TextBoxSalaire) kullanıcı tarafından girilen değerleri alır.
- Yürütme işlemi tamamlandığında, aynı [Default.aspx] sayfası kullanıcıya geri gönderilecektir. Bu işlem otomatik olarak gerçekleştirilir.
Dolayısıyla ButtonCalculer_Click prosedürü, alanların (RadioButtonOui, RadioButtonNon, TextBoxEnfants, TextBoxSalaire) tüm alanların değerlerini (RadioButtonOui, RadioButtonNon, TextBoxEnfants, TextBoxSalaire, LabelErreurEnfants, LabelErreurSalaire, LabelImpot) değerlerini ayarlayın.
Bu kodda özel bir zorluk yoktur. Yalnızca 27. satırın açıklanması gerekir. Bu satır, daha önce karşımıza çıkmamış bir Global.Metier alanının CalculerImpot yöntemini kullanmaktadır. Bu konuya yakında tekrar döneceğiz.
ButtonEffacer_Click yöntemi şu şekildedir:
protected void ButtonEffacer_Click(object sender, EventArgs e)
{
// form sıfırlama
TextBoxEnfants.Text = "";
TextBoxSalaire.Text = "";
LabelImpot.Text = "";
LabelErreurEnfants.Text = "";
LabelErreurSalaire.Text = "";
}
Şimdi inşa etmemiz gereken mimariye geri dönelim:
![]() |
- [1], [Default.aspx] tarafından uygulanmıştır
- [2], [Default.aspx.cs] tarafından uygulanmıştır
- [3], DLL ve [ImpotV9-metier] tarafından uygulanmıştır
Şimdi bu üç katmanın etrafına "bağlayıcı" eklememiz gerekiyor. Bu temel olarak şunu ifade ediyor:
- uygulamanın başlatılması sırasında [3] katmanını başlatmak
- [Default.aspx.cs] web sayfasının, her başlatıldığında ve vergi hesaplaması istenildiğinde bu katmanı alabileceği bir yere bir referans eklemek.
Bu yeni bir sorun değildir. Uzak web hizmetinin oluşturulmasında daha önce karşılaşılmış ve 12.4.1. paragrafında incelenmiştir. Çözümün şunlardan oluştuğu bilinmektedir:
- [Global.cs] sınıfıyla ilişkili bir [Global.asax] dosyası oluşturmak
- [Global.cs] sınıfının Application_Start yönteminde [3] katmanını örneklendirmek
- [3] katmanının referansını, [Global.cs] sınıfının statik bir alanına yerleştirmek, çünkü bu sınıfın ömrü uygulamanın ömrü kadardır.
Bu nedenle web projemiz şu şekilde gelişmektedir:
![]() |
- 'den [1]'e, [Global.asax] dosyası
- [2]'e, ilgili [Global.cs] kodu. Bu dosyanın bulunduğu [App_Code] klasörü, web çözümünde varsayılan olarak mevcut değildir. Oluşturmak için [3]'i kullanın.
Global.asax dosyası şöyledir:
<%@ Application Language="C#" Inherits="WsImpot.Global"%>
[Global.cs] kodu şöyledir:
using System;
using Metier;
using Spring.Context.Support;
namespace WsImpot
{
public class Global : System.Web.HttpApplication
{
// iş mantığı katmanı
public static IImpotMetier Metier;
// uygulamanın başlatılması sırasında yürütülen yöntem
private void Application_Start(object sender, EventArgs e)
{
// [metier] ve [dao] katmanlarının örneklenmesi
Metier = ContextRegistry.GetContext().GetObject("metier") as IImpotMetier;
}
}
}
- 6. satır: Sınıfın adı Global'tir ve WsImpot ad alanının bir parçasıdır (4. satır). Dolayısıyla tam adı WsImpot.Global'tir ve Global.asax'in Inherits özniteliğine bu adın yazılması gerekir.
- 6. satır: Global.asax ile ilişkili sınıfın, zorunlu olarak System.Web.HttpApplication sınıfından türetilmesi gerektiği bilinmektedir.
- 12. satır: Web uygulamasının başlatılması sırasında yürütülen Application_Start yöntemi.
- 15. satır: Spring ve [web.config] içindeki aşağıdaki yapılandırma kullanılarak [metier] katmanı (geliştirilmekte olan uygulamanın [3] katmanı) oluşturulur:
<!-- Spring nesneleri -->
<spring>
<context>
<resource uri="config://spring/objects" />
</context>
<objects xmlns="http://www.springframework.net">
<object name="metier" type="Metier.ImpotMetierWS, ImpotsV9-metier">
</object>
</objects>
</spring>
Yukarıdaki (g) satırındaki [Metier.ImpotMetierWS] sınıfı, [ImpotsV9-metier.dll] içinde bulunur.
Oluşturulan [metier] katman referansı, 9. satırdaki statik alana yerleştirilir. ButtonCalculer_Click prosedürünün 27. satırında kullanılan alan budur:
LabelImpot.Text = String.Format("{0} euros",Global.Metier.CalculerImpot(marié, nbEnfants, salaire));
Test için hazırız. Uzak web hizmeti olan SGBD MySQL5'i başlatmalı ve çalıştığı bağlantı noktasını not etmeliyiz:
![]() |
Bu işlem tamamlandıktan sonra, web istemcisindeki [web.config] dosyasında uzaktaki web hizmetinin bağlantı noktasının doğru olup olmadığını kontrol etmeliyiz:
![]() |
Bu işlem tamamlandıktan sonra, uzaktan web hizmetinin web istemcisi Ctrl-F5 tuşlarıyla başlatılabilir:
![]() |
12.6. Vergi hesaplama web hizmeti için bir Java konsol istemcisi
Web hizmetlerine herhangi bir dilde yazılmış istemcilerle erişilebileceğini göstermek amacıyla, basit bir Java konsol istemcisi yazıyoruz. İstemci/sunucu uygulamasının mimarisi şu şekilde olacaktır:
![]() |
- [1] istemcisi Java ile yazılacaktır
- [2] sunucusu ise C# ile yazılmış olan sunucudur
Öncelikle, vergi hesaplama web hizmetimizde bir ayrıntıyı değiştireceğiz. [ServiceImpot.cs] içindeki mevcut tanımı şu şekildedir:
...
public class ServiceImpot : System.Web.Services.WebService
{
[WebMethod]
public int CalculerImpot(bool marié, int nbEnfants, int salaire)
{
return Global.Metier.CalculerImpot(marié, nbEnfants, salaire);
}
}
Testler, 6. ve 8. satırlardaki marié parametresindeki aksanın Java / C# arasında uyumluluk sorunu yaratabileceğini göstermiştir. Aşağıdaki yeni tanımı kullanacağız:
...
public class ServiceImpot : System.Web.Services.WebService
{
[WebMethod]
public int CalculerImpot(bool marie, int nbEnfants, int salaire)
{
return Global.Metier.CalculerImpot(marie, nbEnfants, salaire);
}
}
Bu hizmet, WsImpotsSansAccents adlı yeni bir Web Developer projesine yerleştirilecektir. Web hizmetinin URL'si ise [/WsImpotSansAccents/ServiceImpot.asmx] olacaktır.

Java istemcisini yazmak için IDE NetBeans [http://www.netbeans.org/]'i kullanacağız:
![]() |
- [1]'te, [2,3] adında yeni bir proje oluşturun
- [2,3]'te, Java Uygulaması türünde bir proje seçin.
- [4]'te bir sonraki adıma geçin
- [5]'te, projeye bir ad verin
- [6]'te, proje için proje adını taşıyan bir alt klasörün oluşturulacağı klasörü belirtin
- [7]'te, uygulamanın başlatılması sırasında yürütülecek olan main yöntemini içerecek sınıfa bir ad verin
- [8]'te, sihirbazı tamamlayın
![]() |
- [9]: Oluşturulan Java projesi
- [10]: Vergi hesaplama web hizmeti istemcisini oluşturmak için projeye sağ tıklayın
![]() |
- [11], vergi hesaplama web hizmetini açıklayan dosyanın URL'si:
http://localhost:1089/WsImpotSansAccents/ServiceImpot.asmx?WSDL
Bu URL, ?WSDL parametresinin eklendiği [ServiceImpot.asmx] hizmetine aittir. Bu URL'de bulunan belge, [15] hizmetinin neler yapabileceğini XML dilinde açıklamaktadır. Bu, bir web hizmetinin standart bir bileşenidir.
- [12], oluşturulacak sınıfların yerleştirileceği paket (C#'daki ad alanına eşdeğer)
- [13]'te, varsayılan değeri olduğu gibi bırakın
- [14]'te, sihirbazı tamamlayın
![]() |
- [16]'te, içe aktarılan web hizmeti Java projesine entegre edildi. Bu hizmet, Soap ve Soap12 olmak üzere iki iletişim protokolünü desteklemektedir.
- [17]'te, oluşturulan istemciyi kullanacağımız [Main] sınıfı
![]() |
- [18]'te, [main] yöntemine kod ekleyeceğiz. İmleci kodun ekleneceği yere getirin, sağ tıklayın ve [19] seçeneğini seçin
- [20] seçeneğini seçin, uzaktaki vergi hesaplama hizmetinin CalculerImpot işlevini çağıran kodu oluşturmak istediğinizi belirtin ve ardından Tamam'a tıklayın.
[Main]'te oluşturulan kod şöyledir:
Oluşturulan kod, uzaktan vergi hesaplama hizmetinin CalculerImpot işlevinin nasıl çağrılacağını gösterir. C#'da görülenlerle karşılaştırırsak, 7. satırdaki port değişkeni, C#'da kullanılan istemciye eşdeğerdir. Bu kod hakkında daha fazla yorum yapmayacağız. Kodu şu şekilde yeniden düzenliyoruz:
- 1. satır: Sihirbaz tarafından oluşturulan istemciyi temsil eden ServiceImpot sınıfını içe aktarıyoruz.
- 6. satır: main içinde oluşturulan kodda belirtilen prosedürü izleyerek CalculerImpot uzaktan yöntemini çağırıyoruz.
Çalıştırma sırasında konsolda elde edilen sonuçlar (F6) şunlardır:



































































