WCF - Adım Adım IIS Hosting

Değerli Okurlarım Merhabalar,

Windows Communication Foundation ile ilişkili bir önceki makalemizde mimarinin detaylarına yakından bakmaya çalışmış ve örnek bir uygulama geliştirmiştik. Bu makalemizde ise bir WCF Service projesi geliştirmeye çalışacağız. Bir başka deyişle HTTP protokolünü kullanarak, IIS üzerinden bir .Net kütüphanesini servis olarak yayınlayacağız.

WCF servislerini Self Hosting ve IIS Hosting olmak üzere iki farklı şekilde yayınlayabiliyoruz. Bununla birlikte Self Hosting modeli kendi içerisinde Console, Windows, Windows Service ve Vista ile gelen Windows Activation Service (WAS) olmak üzere dört farklı seçenekten oluşmaktadır.

Ayrıca kendi tiplerimizi döndüren metodlar söz konusu olduğunda veri sözleşmelerini(DataContract) nasıl kullanabileceğimize yakından bakma fırsatı bulacağız. Bunlara ek olarak özellikle .Net Remoting mimarisinde bizi her zaman zorlayan konfigurasyon ayarlarının(Çoğu zaman ezberlemek zorunda olduğumuz ve hatırlamakta güçlük çektiğimiz), WCF içerisinde Edit WCF Configuration seçeneği yardımıyla Visual Studio 2005 içerisinden görsel olarak nasıl daha kolay hazırlanabileceğinide incelemeye çalışacağız.

Aslında IIS(Internet Informatin Service) üzerinden çeşitli tipte istemcilerin (hangi platformda olduklarına bakılmaksızın) belirli fonksiyonellikleri kullanabilmesi amacıyla Xml Web Servisleri (Xml Web Services) oldukça fazla kullanılan bir SOA (Service Oriented Architecture) modelidir. Dolayısıyla WCF içerisinde de buna benzer bir model vardır ve WCF Service olarak adlandırılmaktadır. Visual Studio 2005 için, Framework 3.0' a yönelik eklentileri yüklediğinizde Web Site şablonları arasında WCF Service seçeneğide gelmektedir. Ancak biz bunu kullanmayıp biraz daha elle ilerleyeceğiz ve alt yapı içerisinde yer alan parçaları daha net olarak görmeye çalışacağız. Konuyu daha iyi kavrayabilmek için örnek bir senaryo üzerinden gideceğiz ve bazı basit veritabanı işlemlerini ele alacağız. Gelin hiç vakit kaybetmeden işe başlayalım ve adım adım ilerleyelim.

Bildiğiniz gibi WCF tamamen nitelik(attribute) tabanlı bir mimariye dayanmaktadır. Bununla birlikte istemci tarafına yayınlanacak olan, başka bir deyişle metadata içeriği gönderilecek olan tip(type) aslında ilgili nitelikler ile imzalanmış bir sözleşme(contract) dir. Sözleşmeler genellikle bir arayüz şeklinde tasarlanmakta olup asıl işlevsellikleri yerine getirecek olan uzak nesne modellerinin(sınıflar) türetilmesinde de kullanılır.

.Net Remoting mimarisinden hatırlarsanız eğer; uzak nesneleri (Remote Objects) yayınlamada ele alınan modellerden birisi arayüz(Interface) kullanımını içermektedir. Burada temel amaç istemci tarafında, sunucuda örneklenen uzak nesne referansını taşıyabilecek bir tip olmasıdır. Bununla birlikte istemci tarafının kesin olarak uzak nesne fonksiyonelliklerinin nasıl çalıştığını görmesi gibi bir şansı yoktur. (Elbette bu durum MarshalByReference nesneler için geçerlidir. Bildiğiniz gibi MarshalByValue tipler zaten sunucuda örneklenip istemci tarafına tüm varlığı ile serileştirilerek(Serialization) geçerler). Ayrıca, sunucu tarafındaki uzak nesne metodlarının iç yapılarında meydana gelecek değişiklilikler sonucu, istemcilere yeniden dağıtım(deployement) işlemi uygulanmasına gerek kalmamaktadır.

Öyleyse ilk yapmamız gereken içerisinde servis sözleşmesini(Service Contract) ve gerekli fonksiyonelliklere ait tanımlamaları barındıracak bir arayüz(interface) tasarlamaktır. Örneğimizde, WCF servisimizi IIS üzerinden sunacağımızdan bahsetmiştik. Bu sebepten ilk olarak bir sınıf kütüphanesi(class library) geliştirmeli ve bu kütüphane içerisine servis sözleşmemizi(Service Contract), uzak nesnemizin modelini(class), veri sözleşmesine(Data Contract) sahip tipimizi katmalıyız. Sonrasında IIS üzerinden ilgili kütüphanemizi işaret edecek bir sanal klasör (virtual path) oluşturmalıyız. Yayınlama ortamı IIS olduğundan, WCF için gerekli konfigurasyon ayarlarını web.config dosyası içerisinde tutmamız gerekmektedir. Bu noktada konfigurasyon ayarlarını görsel bir arayüzü kullanarak kolay bir şekilde oluşturabiliriz. Diğer taraftan aynı web servislerinde olduğu gibi asmx uzantılı dosyaların görevini üstlenen svc uzantılı bir dosya oluşturmalıyız.

İlk olarak bilgisayarımızın herhangibir yerinde konuşlandırılacak bir sınıf kütüphanesi (class library) projesi oluşturalım. UrunKutuphanesi isimli projemizi yine .Net Framework 3.0 sonrası Visual Studio 2005 için gelen eklentilerden WCF Service Library olarak açabiliriz. Ama bu şablon yoksada önemli değildir. Çünkü yapmamız gereken System.ServiceModel, System.Runtime.Serialization ve System.IdentityModel assembly' larını referans edecek olan bir proje geliştirmektir. (Bu assembly' ların .Net Framework 3.0 ile geldiklerine dikkat edelim.)

Sınıf kütüphanemiz içerisinden, AdventureWorks içerisindeki tablolara ilişkin bazı hizmetler vereceğiz. Bunlardan biriside HumanResources şemasındaki Employee tablosundan herhangibir çalışan bilgisini döndürecek bir metod olacaktır. Lakin bu metodun dönüşünde biz kendi geliştireceğimiz sınıfımıza ait bir nesne örneğini döndüreceğiz. Bu nedenle ilk olarak aşağıdaki gibi bir sınıfı, kütüpanemiz içerisine katarak işe başlayabiliriz.

[DataContract]
public class Employee
{
    [DataMember]
    public int EmployeeId;

    [DataMember]
    public string Title;

    [DataMember]
    public DateTime BirthDate;

    [DataMember]
    public int VacationHours;

    public Employee()
    {
    }
    public Employee(int id, string title, DateTime birth, int vacation)
    {
        EmployeeId = id;
        Title = title;
        BirthDate = birth;
        VacationHours = vacation;
    }
}

Employee isim sınıfımız çok basit olarak bir kaç public alan(Field) ile, aşırı yüklenmiş(overload) ve varsayılan yapıcı(default constructor) metodları içermektedir. Ancak burada asıl dikkat edilmesi gereken sınıfın ve üyelerin nitelikleridir. Dikkat ederseniz sınıfımız DataContract niteliği(attribute) ile, public olan alanlarımız ise DataMember nitelikleri ile işaretlemiş durumdadır. DataContract ve DataMember isimli niteliklerimiz System.Runtime.Serialization isim alanı altında yer alan sınıflardır. Böylece servisimizin döndüreceği özel bir tip için gerekli veri sözleşmesini bildirmiş bulunuyoruz.

Eğer servis metodlarımız geriye ilkel tipler döndürmüyorsa (int, double, string gibi), özellikle Employee gibi geliştirici tarafından tasarlanmış tipler söz konusu ise mutlaka bir veri sözleşmesinin(data contract) tanımlanması gerekmektedir. (İlerleyen makalelerimizde veri sözleşmelerine daha detaylı bir şekilde bakmaya çalışacağız.) Artık kendi veri sözleşmemizide(Data Contract) tanımladığımıza, bir başka deyişle servisteki ilgili metoddan geriye nasıl bir tip döndürüleceğini bildirdiğimize göre, iş yapan metodlarımızı içerecek tip için gerekli servis sözleşmesini (service contract) yazarak işlemlerimize devam edebiliriz. IAdventure isimli arayüzümün içeriği aşağıda görüldüğü gibidir.

[ServiceContract(Name="Adventure Works Services")]
public interface IAdventure
{
    [OperationContract]
    Employee GetEmployee(int employeeId);

    [OperationContract]
    DataSet GetAllProducts();

    [OperationContract]
    List<string> GetAllSubCategoryNames();

    [OperationContract]
    double AverageSubTotalFromHeaders();
}

IAdventure arayüzümüze(interface) ait üyelerde özellikle çeşitli tiplerden dönüş değerleri kullanmaya çalıştık. Bildiğiniz gibi, yazacağımız servisin istemciler tarafından kullanılacak bir sözleşmesi olması gerekmektedir. Herhanbiri arayüzün veya sınıfın bir servis sözleşmesi (Service Contract) sağlayacağını bildirmek için ServiceContract niteliği ile imzalamak gerekmektedir. Benzer şekilde servisin sunabileceği metodları bildirmek içinse OperationContract isimli nitelik kullanılmaktadır. ServiceContract ve OperationContract isimli nitelikler(attributes), System.ServiceModel isim alanı(namespace) altında yer almaktadır.

Servis sözleşmemizi tanımladıktan sonra, uzak nesne olarak asıl iş yapan metodları taşıyacak ve istemcilerin başvuruda bulanabileceği sınıfı tasarlayabiliriz. AdventureManager isimli sınıfımız herşeyden önce IAdventure arayüzünü uyarlamalıdır(Implementation).

class AdventureManager:IAdventure
{
    #region IAdventure Members

    public Employee GetEmployee(int employeeId)
    {
        Employee emp=null;
        using (SqlConnection conn = new SqlConnection("data source=localhost;database=AdventureWorks;integrated security=SSPI"))
        {
            SqlCommand cmd = new SqlCommand("Select EmployeeId,Title,BirthDate,VacationHours From HumanResources.Employee Where EmployeeId=@EmpId", conn);
            cmd.Parameters.AddWithValue("@EmpId", employeeId);
            conn.Open();
            SqlDataReader dr = cmd.ExecuteReader();
            if (dr.Read())
            {
                emp = new Employee();
                emp.EmployeeId = Convert.ToInt32(dr["EmployeeId"]);
                emp.Title = dr["Title"].ToString();
                emp.VacationHours = Convert.ToInt32(dr["VacationHours"]);
                emp.BirthDate = Convert.ToDateTime(dr["BirthDate"]);
            }
            dr.Close();
        }
        return emp;
    }

    public DataSet GetAllProducts()
    {
        DataSet ds=null;
        using (SqlConnection conn = new SqlConnection("data source=localhost;database=AdventureWorks;integrated security=SSPI"))
        {
            SqlDataAdapter da = new SqlDataAdapter("Select ProductId,Name,ListPrice,Class,SellStartDate From Production.Product", conn);
            ds = new DataSet();
            da.Fill(ds);
        }
        return ds;
    }

    public List<string> GetAllSubCategoryNames()
    {
        List<string> categoryNames = null;
        using (SqlConnection conn = new SqlConnection("data source=localhost;database=AdventureWorks;integrated security=SSPI"))
        {
            SqlCommand cmd = new SqlCommand("Select ProductSubCategoryId,Name From Production.ProductSubCategory Order By Name", conn);
            conn.Open();
            SqlDataReader dr = cmd.ExecuteReader();
            categoryNames = new List<string>();
            while (dr.Read())
            {
                categoryNames.Add(dr["Name"].ToString());
            }
            dr.Close();
        }
        return categoryNames;
    }

    public double AverageSubTotalFromHeaders()
    {
        double average=0;
        using (SqlConnection conn = new SqlConnection("data source=localhost;database=AdventureWorks;integrated security=SSPI"))
        {
            SqlCommand cmd = new SqlCommand("Select Avg(SubTotal) From Sales.SalesOrderHeader", conn);
            conn.Open();
            average = Convert.ToDouble(cmd.ExecuteScalar());
        }
        return average;
    }

    #endregion
}

AdventureManager isimli sınıfımız içerisinde kullandığımız metodlar basit Ado.Net fonksiyonelliklerini ele alarak farklı tiplerde sonuçlar üretmektedir. Konumuz WCF olduğu için metod içerisindeki kod parçalarının işleyiş şekline çok fazla değinmeyeceğiz. Sırada servis için gerekli sanal klasörün, svc dosyasının ve web.config dosyasının oluşturulması adımları yer almaktadır.

İlk olarak IIS üzerinde sanal klasörümüzü oluşturalım. Özellikle IIS üzerinden host edilen assembly' lar göz önüne alındığında, dll' in Bin klasörü altında yer alması ve Bin klasörü ile aynı seviyede bir web.config dosyası olması gerekmektedir. Söz konusu web.config dosyası uzak nesne kullanımı için gerekli alt yapı ayarlarını barındırmaktadır. Örneğimizde IIS altına açacağımız sanal klasör(Virtual Directory) içinde aynı durumu ele almak istediğimizden proje özelliklerine girip Build sekmesinde yer alan Output Path özelliğinin değerinin bin\debug adresinden bin\ adresine çekilmesi yeterli olacaktır. Böylece, kodda yapacağımız değişikliker anında canlı ortamada yansıyacaktır.

Bu tarz bir işlem zorunlu değildir. Sanal Klasörün(Virtual Directory) işaret edeceği başka bir fiziki adreste belirlenebilir ancak yine Bin klasörünün olması, dll' in kopyasının burada yer alması ve bin ile aynı seviyede bir web.config dosyasının alt yapı ayarlarını içerecek şekilde olması şarttır. Örneğimizde, yapacağımız derlemelerin anında yansımalarını test edebilmek amacıyla bu tarz bir ön hazırlık yapmayı tercih ediyoruz. Artık IIS altında sanal klasörümüzü oluşturabiliriz. Aşağıdaki flash animasyonunda basit olarak IIS üzerinde yapmamız gereken adımlar gösterilmektedir. (Flash animasyonunun boyutu 187 kb olup yüklenmesi zaman alabilir.)

Makalemizde ilerlemeden önce Web servisleri ile HTTP üzerinden iletişime geçerken devreye giren asmx uzantılı dosyaları göz önüne almamızda fayda olacaktır. Sonuç itibariyle WCF servisimizi IIS üzerinden host ederken asmx ile aynı amaca yönelik bir dosya var olmalıdır ki bu sayede istemciler URL üzerinden servis metadata içeriğini talep edebilsinler. İşte WCF için bu görevi yerine getiren svc uzantılı bir servis dosyası olacaktır. Bu dosya aynı zamanda EndPoint için gerekli adres tanımlanırkende ele alınacaktır. (Bildiğiniz gibi bir WCF servisi içerisinde birden fazla EndPoint yer alabilir ve bunların ayrıt edici özelliklerinden biriside adresleridir.) Bu nedenle projemize aşağıdaki içeriğe sahip olan svc uzantılı bir dosya eklememiz gerekmektedir. Bu dosya tipini öğeler arasından bulamayabilirsiniz. Bu nedenle boş bir text dosyasını svc uzantısı ile kaydederek sorunu aşabiliriz.

<%@ServiceHost Service="UrunKutuphanesi.AdventureManager"%>
<%@Assembly Name="UrunKutuphanesi"%>

Svc dosyamız içerisinde iki direktif yer almaktadır. ServiceHost direktifi içerisinde Service' e ait tip bilgisi yer alır. Bir başka deyişle uzak nesne görevini üstlenecek olan tipimizi bildiririz. Dikkat ederseniz notasyon olarak isimAlanı.tipAdı formatı kullanılmıştır. Assembly direktifinde ise söz konusu tipin, içerisinde yer aldığı assembly adı bildirilmektedir.

Artık web.config dosyamız için gerekli konfigurasyon tanımlamalarını yapabiliriz. (Yada görsel aracımız yardımıyla kolayca inşa edebiliriz :) ) Bu amaçla projemize yeni bir Application Configuration File öğesi (Item) ekleyelim ve ismini web.config olarak değiştirelim. Konfigurasyon ayarlarımızı yapmak için web.config dosyamıza sağ tıklayıp, Edit WCF Configuration seçeneğini işaretlememiz yeterli olacaktır.

Edit WCF Configuration vasıtasıyla açılan yardımcı arabirim aslında, IIS üzerinde yer alan Asp.Net sekmesindeki Edit Configuration linki yardımıyla açılana benzemektedir. Ancak kullanım amacı tamamıyla WCF' a yöneliktir ve daha da önemlisi IDE dışına çıkmadan gerekli ön hazırlıkların yapılabilmesini sağlamaktadır.

Elbette buradaki ayarları yapmadan önce bir WCF servisi için gereken temel konfigurasyon ayarlarının ne olduğunu bilmek gerekmektedir. Bu konu ile ilgili bir önceki makalemizden de hatırlayacağınız gibi, WCF' nin ABC' si önemli bir rol oynamaktadır. Yani AddressBindingContract üçlemesinden söz ediyoruz. Bu kuralları konfigurasyon dosyamızda da göz önüne almalıyız. WCF Configuration arabirimi, service ve istemci(Client) tarafı için ayrı ayrı konfigurasyon dosyaları hazırlanabilmesine olanak tanımaktadır. Şu aşamadan biz servis(Service) tarafı için gerekli konfigurasyon ayarlarını yapacağız. Bu amaçla Create a New Service linkinden faydalanabilir yada manuel olarak Configuration sekmesini kullanabiliriz. Biz örneğimizde Create a New Service linkinden faydalanacağız.

Bu linke tıklandıktan sonra sihirbaz bizden uzak nesne görevini üstlenecek tipi seçmemizi isteyecektir. Örneğimizde söz konusu olan tip AdventureManager sınıfıdır. Bu seçimin arkasından sihirbaz, servis sözleşmesini(Service Contract) içeren tipi belirtmemizi isteyecektir. Örneğimizde bu yükü üstlenen IAdventure isimli arayüzdür(Interface). WCF Configuration IDE' si eğer ilk adımda seçilen tipin uyarladığı ve ServiceContract niteliğini taşıyan bir arayüz var ise bunu otomatik olarak bulacaktır. Bir sonraki adımda bağlantı tipi seçilir. Burada HTTP, TCP, MSMQ, Peer To Peer gibi seçenekler yer almaktadır. Örneğimizde HTTP tipini seçerek ilerleyeceğiz. Takip eden adımımızda WSI (Web Service Interoperability) ayarları yapılabilir veya varsayılan hali ile bırakılabilir. Biz bu adımı değiştirmeden devam edebiliriz. Son adımda ise servisimiz için bir endpoint adresi bildirilmesi gerekmektedir.

WCF mimarisinde istemciler(Clients), WCF Servisleri ile haberleşirken taleplerini proxy sınıflarına iletirler. Proxy sınıfları ise servis üzerinde yer alan endpoint' ler ile haberleşebilirler. Bu sebepten servis tarafında endpoint tanımlamalarının yapılması gerekmektedir. Bir endpoint tanımlaması içerisinde servisin adres bilgiside bulunur. Bu sebepten bu adımda HTTP protokolüne uygun bir adres girilmesi gerekir. Zaten örneğimizi IIS üzerinden sunduğumuz ve sanal klasörümüzü buna göre oluşturduğumuz için vereceğimiz adres bellidir.http://localhost/AdventureService/Adventure.svc .Dikkat ederseniz adresimizde daha önceden oluşturduğumuz Adventure.svc isimli dosyamızda yer almaktadır. Böylece şimdilik gerekli WCF ayarlarını tamamlamış bulunuyoruz. Aşağıdaki Flash animasyonuda gerekli ayarların nasıl yapıldığını izleyebilirsiniz. (Flash dosyasının boyutu 229 kb olduğu için yüklenmesi zaman alabilir)

Bu işlemlerin ardından web.config dosyamızın içeriğide aşağıdaki gibi olacaktır.

<?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <system.serviceModel>
            <services>
                <service name="UrunKutuphanesi.AdventureManager">
                    <endpoint address="http://localhost/AdventureService/Adventure.svc" binding="basicHttpBinding" bindingConfiguration="" contract="UrunKutuphanesi.IAdventure" />
                </service>
            </services>
        </system.serviceModel>
</configuration>

Artık servisimizin çalışıp çalışmadığını tarayıcı penceremiz üzerinden test edebiliriz. Tek yapmamız gereken http://localhost/AdventureService/Adventure.svc adresini talep etmek olacaktır. Bu talep sonucunda eğer herşey yolunda ise aşağıdakine benzer bir ekran görüntüsü ile karşılaşırız.

Yine dikkat edilecek olursa servisin metadata yayınlamasının(MetaData Publishing) aktif olmadığını görürüz. Bildiğiniz gibi metadata bilgisi istemcilerin proxy sınıflarını oluşturabilmeleri için gereklidir. Bunu sağlamak maksadıyla yeni bir servis davranışı(Service Behavior) oluşturulmalı ve servise bildirilmelidir. Bu amaçla ilk olarak Advanced sekmesinde yer alan Service Behaviors kısmından yeni bir davranış nesnesi eklenmeli ve aşağıdaki ekran görüntüsünde yer alan ayarlar yapılmalıdır. Bu ayarlara göre eklenen servis davranışına bir isim verilmiş (Name özelliği ile) ve serviceMetadata elementi dahil edilmiştir.

ServiceMetadata elementinin içeriğininde aşağıdaki gibi düzenlenmesi gerekmektedir. Burada HttpGetEnabled özelliğinin değerini true olarak belirlemeliyiz ki HTTP üzerinden servis metadata içeriğini çekebilelim.

Sonrasında ise servisimizin belirtilen davranışı kullanacağını bildirmemiz gerekmektedir. Bunun içinde servisin, BehaviorConfiguration elementine aşağıdaki ekran görüntüsünde olduğu gibi az önce oluşturulan Service Behavior nesnesinin adını vermeliyiz.

Bu işlemlerin ardından servisimize ait web.config dosyasının son halide aşağıdaki gibi olacaktır.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="AdventureServiceBehavior">
                    <serviceMetadata httpGetEnabled="true" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <services>
            <service behaviorConfiguration="AdventureServiceBehavior" name="UrunKutuphanesi.AdventureManager">
                <endpoint address="http://localhost/AdventureService/Adventure.svc" binding="basicHttpBinding" bindingConfiguration="" contract="UrunKutuphanesi.IAdventure" />
            </service>
        </services>
    </system.serviceModel>
</configuration>

Gördüğünüz gibi servisimiz için berlilediğimiz davranış ve servis ile olan ilişkisi otomatik olarak konfigurasyon dosyasına element ve nitelikler yardımıyla yansıtılmıştır. Servisimizi tarayıcı penceresi üzerinden yeniden talep edersek aşağıdaki ekran görüntüsü ile karşılaşırız. Dikkat edersek, servise ait Wsdl dökümanını elde edebilmemizi sağlayacak bir link bilgiside yer almaktadır.

Bu kadar işlemden sonra artık istemcimizi yazmaya başlayabiliriz. İstemci tarafında herhangibir uygulama söz konusu olabilir. Biz mimariyi basit bir şekilde ele almaya çalıştığımızdan bir Console uygulaması geliştireceğiz. Yine Visual Studio 2005' in Add Service Reference seçeneğini kullanarak ilgili servisi otomatik olarak uygulamamıza ekleyebilir ve gerekli proxy sınıfının kolay bir şekilde oluşturulmasını sağlayabiliriz.

Visual Studio 2005 dışında, bir WCF servisine ait metadata bilgisini elde edip proxy sınıfını ve istemci için gereken konfigurasyon dosyasını elde etmek amacıyla, svcutil isimli Framework 3.0 aracıda kullanılabilmektedir.

Console uygulamamızı oluşturduktan sonra projeye sağ tıklayıp Add Service Reference seçeneğini kullanarak WCF servisimizi projemize eklememiz gerekmektedir. Burada içeride kullanmak istediğimiz isim alanının adınıda belirtebiliriz. Varsayılan olarak aynı web servislerinde olduğu gibi localhost verilmektedir.

Bu işlemin ardından istemci için gereken proxy sınıfı ve konfigurasyon dosyası otomatik olarak oluşturulacaktır. Artık aşağıdaki kod satırlarını kullanarak sanki sıradan bir web servisini kullanıyormuş gibi WCF Servisimizi ele alabiliriz.

using System;
using System.Data;
using Istemci.localhost;

namespace Istemci
{
    class Program
    {
        static void Main(string[] args)
        {
            localhost.AdventureWorksServicesClient adw = new Istemci.localhost.AdventureWorksServicesClient();
            DataSet ds = adw.GetAllProducts();
            Console.WriteLine("Urun sayısı {0} dır",ds.Tables[0].Rows.Count.ToString());

            string[] categoryNames=adw.GetAllSubCategoryNames();
            foreach (string category in categoryNames)
                Console.WriteLine(category);

            Employee emp=adw.GetEmployee(1);
            Console.WriteLine(emp.Title + " " + emp.BirthDate.ToShortDateString() + " " + emp.VacationHours.ToString());

            Console.WriteLine("Ortalama Sub Total {0}",adw.AverageSubTotalFromHeaders().ToString("C2"));
        }
    }
}

Uygulamayı bu haliyle çalıştırdığımızda GetAllProducts metodu için aşağıdaki gibi çalışma zamanı istisnası (run-time exception) alırız.

Bunun sebebi istemci tarafında oluşturulan konfigurasyon dosyasında belirtilen MaxReceivedMessageSize boyutunun düşük olmasıdır. Nitekim dönen DataSet içeriğinin yer aldığı paketin boyutu çok daha fazladır. Bu nedenle istemci uygulamaya ait App.config dosyasını Edit WCF Configuration ile açıp aşağıdaki ekran görüntüsünde olduğu gibi MaxReceivedMessageSize ve MaxBufferSize özelliklerinin aynı değere set edilmesi gerekir. Örneğimizde bu değerlerin sonuna bir 0 eklenmiştir. Burada dikkat edilmesi gereken noktalardan birisi de, her iki değerinde aynı olması zorunluluğudur. Aksi takdire çalışma zamanında yine bir istisna alırız.

Bu sebepten ayarlarımız örneğin aşağıdaki gibi olmalıdır.

Örneğimizdeki kodlarımızı incelersek eğer, ilginç olan bir nokta olduğunu farkederiz. GetAllSubCategoryNames metodu servis tarafında geriye generic bir List koleksiyonu döndürüyorkan, istemci tarafında metodun dönüşü string[] tipinden bir dizi olmuştur. Buda aslında farklı tipteki istemciler için ortak bir standart koyulmaya çalışıldığı şeklinde yorumlanabilir. Uygulamayı çalıştırdığımızda aşağıdakine benzer bir ekran görüntüsü elde ederiz.

Bu makalemizde Windows Communication Foundation çatısı altında, servislerimizi IIS üzerinden nasıl yayınlayıp kullanabileceğimizi incelemeye çalıştık. Bunu yaparken bir servis sözleşmesini(Service Contract) nasıl tanımlayabileceğimizi, bu sözleşmeyi uygulayan asıl uzak nesne sınıfının geriye kullanıcı tanımlı bir tip döndürmesi halide veri sözleşmesini(data contract) nasıl geliştirmemiz gerektiğini gördük. Bunlara ek olarak özellikle IIS Hosting için svc uzantılı dosyaların rolünü inceledik ve konfigurasyon dosyalarını daha kolay oluşturabilmemizi sağlayan Edit WCF Configuration seçeneğini ele aldık. Böylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde görüşmek dileğiyle hepinize mutlu günler dilerim.

Örnek Uygulama İçin Tıklayınız.

Yorumlar (5) -

  • http://localhost/AdventureService/Adventure.svc talep ettikten sonra " 'UrunKutuphanesi' dosyasını veya derlemesini ya da bağımlılıklarından birini yükleyemedi. Sistem belirtilen dosyayı bulamıyor." (ekran :  http://prntscr.com/bcyfxn )

    virtual path de izinleri verdim ııs_ıusrs şeklinde.
    • publish metoduyla yaparak düzelttim.
  • ali
    Merhaba. Servis içinde ikinci bir servisim var. Studio localhostunda Formdan veri gönderip alıyorum. IIS içine dosyalarımı attığımda mscorbil.dll diye uzun bir hata alıyorum.
  • ali
    servis içinde ikinci servisi kaldırdığımda ise hata yok
  • Merhabalar,

    WCF  standart hostlarda çalışır mı? Yoksa Angular'da olduğu gibi uygulama sunucu mu gerektirir?

    Teşekkürler

Yorum ekle

Loading