Değerli Okurlarım Merhabalar,
Bir önceki makalemizde WCF(Windows
Communication Foundation) mimarisinde veri sözleşmelerinin(Data
Contracts) karşı taraflarda farklı versiyonlarının olması durumunda
oluşan vakaları incelemeye çalışmıştık. Versiyonlama(Versioning)
vakaları dışında serileştirmede önem arz eden konulardan biriside,
servis tarafında yayınlanan veri sözleşmeleri içerisinde
serileştirilemeyen(NotSerializable) tiplerin var olmasıdır. Bu durum
çoğunlukla, serieştirilebilen tipin kullandığı bazı dahili tiplerin
farklı assembly dosyaları içerisinde yer aldığı vakalarda ortaya
çıkmaktadır. Öyleki, diğer assembly içerisinde yer alan
tipe(type) geliştirici tarafından müdahale edilemeyebilir ve bu
sebepten serileştirilebilmesi için DataContract veya
DataMember üyeleri uygulanamayabilir. Bu durum aşağıdaki şekilde
örnek bir senaryo üzerinden ifade edilmeye çalışılmaktadır.

Dikkat edileceği üzere Urun
sınıfı bir veri sözleşmesi(Data Contract) olacak şekilde,
ServiceLibrary.dll assembly dosyası içerisinde yer
almaktadır. Söz konusu sınıfın üyelerinden Ureten isimli
özellik(Property) Uretici sınıfı tipindendir. Ne varki
Uretici sınıfı, Ureticiler.dll assembly dosyası
içerisinde yer almaktadır ve serileştirilebilir bir tip değildir(NotSerializable).
Bu sebepten dolayı Urun sınıfının kullanıldığı bir senaryoda
istemci açısından sorunlar oluşacaktır. Örneğin tipin istemci için
gerekli proxy üretimi sırasında metadata içerisine gömülmesi mümkün
olamayacaktır. Çözüm olarak servis tarafında
serileştirme(Serializing) ve ters-serileştirme(DeSerializing),
şema çıkartma(Schema Exporting) veya dahil etme(Schema Importing)
işlemleri sırasında müdahalede bulunmak gerekmektedir. Ama nasıl?
 |
Serileştirilemeyen tipler
servis tarafından istemcilere Metadata bilgileri
içerisinde gönderilemezler. Bu sebepten dolayı istemci için önem
arz eden proxy nesneleri içerisine konulamazlar ki buda söz
konusu tiplerin istemci tarafından ele alınıp kullanılamayacağı
anlamına gelir. |
Bu noktada bir vekil(Surrogate)
sınıf kullanılma yolu tercih edilir. Vekil sınıf serileştirilebilir
olmakla birlikte, serileştirilemeyen sınıfın üyelerini taşıyacak şekilde
tasarlanır. Daha sonra serileşen ve serileşemeyen sınıflar arasında
köprü görevi üstelenecek ek bir sınıf daha tasarlanır. Bu ek sınıfın
görevi serileştirme, ters-serileştirme, şema import ve export işlemleri
sırasında, serileştirilemeyen sınıf ile eşleştirme yapılmasını
sağlamaktır. Bu sınıf, IDataContractSurrogate
arayüzünü(Interface) uygulayacak şekilde tanımlanır. Buna ek olarak
WCF çalışma ortamına, serileştirme, ters
serileştirme, şema yayınlamak gibi işlemler sırasında
devreye girecek olan IDataContractSurrogate uyarlamalı tipin,
davranış(behavior) olarak atanması gerekmektedir ki bu işlemlerde
çoğunlukla nitelik(attribute) olarak kullanılabilecek bir sınıf
içerisinde ele alınır. :) Bu karmaşık sürecin adım adım incelenmesinden
önce, yukarıdaki senaryodaki gibi bir durum oluşması halinde çalışma
zamanında neler olacağını irdelemekle başlamakta yarar vardır. Bu amaçla
ilk olarak Uretciler.dll isimli assembly, Uretici
sınıfını içerecek şekilde aşağıdaki gibi tasarlanır.

using System;
namespace Ureticiler
{
public class Uretici
{
public int Id { get; set; }
public string Ad { get; set; }
public string Adres { get; set; }
public Uretici(int id,string
ad,string adres)
{
Id = id;
Ad = ad;
Adres =
adres;
}
}
} |
Uretici sınıfı içerisinde yer
alan aşırı yüklenmiş yapıcı metod(Overloaded Constructor) nedeni
ile, varsayılan yapıcı metod(Default Constructor) geçersiz
kalmaktadır. Buda tipin serileştirilmesini engelleyecek ve istenilen
sorunun oluşmasına neden olacaktır. Servis sözleşmesi(Service
Contract), uygulayıcı sınıf ve veri sözleşmesini(Data Contract)
içeren WCF Servis kütüphanesi(WCF Service Library)
içeriği ise aşağıdaki gibidir. (Servis kütüphanesinin, Ureticiler.dll
assembly dosyasını referans etmesi gerektiği unutulmamalıdır.)

Urun sınıfı içeriği;
using System;
using
System.Runtime.Serialization;
namespace UrunYonetim
{
[DataContract(Name="Urun")]
public class Urun
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Ad { get; set; }
[DataMember]
public double BirimFiyat { get; set;
}
[DataMember]
public int StokMiktari { get; set; }
[DataMember]
public
Ureticiler.Uretici
Ureten
{ get; set; }
}
} |
Urun sınıfı içerisinde yer alan
Ureten özelliğinin(Property), Uretici tipinden
olduğuna ve serileştirilemediğine dikkat edilmelidir.
IUrunYonetici arayüzü içeriği;
using System;
using
System.ServiceModel;
namespace UrunYonetim
{
[ServiceContract(Name="UrunServisi",Namespace="http://www.bsenyurt.com/UrunServisi")]
public interface IUrunYonetici
{
[OperationContract]
void UrunEkle(Urun
urun);
[OperationContract]
Urun
UrunGuncelle(Urun urun);
}
} |
IUrunYonetici arayüzü içerisinde
iki adet operasyon tanımlanmıştır. UrunEkle metodu, parametre
olarak Urun tipinden bir nesne örneği alır. UrunGuncelle
metodu ise parametre olarak alınan Urun üzerinden bir takım
güncellemeler yapılmasını ve geriye döndürülmesini sağlamak üzere
tanımlanmıştır. Dikkat edileceği üzere her iki operasyonda Urun
isimli veri sözleşmesini kullanmaktadır.
UrunYonetici sınıfı içeriği;
using System;
namespace UrunYonetim
{
public class UrunYonetici
:IUrunYonetici
{
#region IUrunYonetici Members
public void
UrunEkle(Urun
urun)
{
String bilgi
= String.Format("{0} numaralı {1} ürün eklenmiştir", urun.Id,
urun.Ad);
Console.WriteLine(bilgi);
}
public
Urun
UrunGuncelle(Urun urun)
{
urun.Ureten = new
Ureticiler.Uretici(1, "Adventure Vendor", "Adventure yolu
üzeri");
urun.StokMiktari += 10;
urun.BirimFiyat += 1.1;
return urun;
}
#endregion
}
} |
Servis tarafındaki uygulama yine
olayların basit bir şekile anlaşılabilmesi için Console projesi
şeklinde tasarlanmaktadır. Servis uygulamasına ait konfigurasyon dosyası
ve kod içeriği başlangıçta aşağıdaki gibidir.(Servis uygulamasının
System.ServiceModel.dll ile UrunYonetim.dll assembly
dosyalarını referans etmesi gerektiği unutulmamalıdır.)
Konfigurasyon(App.config)
içeriği;
<?xml
version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="UrunServisiBehavior">
<serviceMetadata />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service
behaviorConfiguration="UrunServisiBehavior"
name="UrunYonetim.UrunYonetici">
<endpoint address="" binding="netTcpBinding"
bindingConfiguration="" name="UrunServisiTcpEndPoint"
contract="UrunYonetim.IUrunYonetici" />
<endpoint address="Mex" binding="mexTcpBinding"
bindingConfiguration="" name="UrunServisiMexEndPoint"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add
baseAddress="net.tcp://localhost:2501/UrunServisi"
/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration> |
Örnekte TCP bazlı bir
EndPoint kullanılmaktadır. Bununla birlikte istemci için gerekli
olan Proxy sınıfının kolay üretilebilmesi amacıyla yine TCP
bazlı bir MexEndPoint kullanılmaktadır.
Servis tarafı Program içeriği;
using System;
using
System.ServiceModel;
using
UrunYonetim;
namespace Sunucu
{
class Program
{
static void Main(string[] args)
{
ServiceHost host =
new ServiceHost(typeof(UrunYonetici));
host.Open();
Console.WriteLine(host.State);
Console.WriteLine("Kapatmak için bir tuşa basın");
Console.ReadLine();
host.Close();
}
}
} |
İstemci uygulama için gerekli olan
proxy sınıfı ve konfigurasyon dosyası içeriği MEX EndPoint
kullanımı nedeni ile svcutil aracı veya Visual
Studio->Add Service Reference yardımıyla çekilebilir. Tabi bu
işlemler sırasında servis uygulamasının çalışıyor olmasına dikkat
edilmelidir. Ne varki, söz gelimi svcutil aracı ile ilgili servis
üzerinden metadata bilgisi çekilmek istendiğinde aşağıdaki ekran
görüntüsü ile karşılaşılır.

Her ne kadar hata mesajı çok açık
olmasada ve tutarlı bir bilgi vermesede sorun, Uretici sınıfının
serileştirilemiyor olmasından kaynaklanmaktadır. Bu sebepten istemci
tarafına aktarılacak olan Metadata bilgisi kesilmiştir. Nitekim
serileştirilemeyen bir tipin, istemci tarafına export edilecek
olan şema(Schema) içeriğine dahil edilmesi mümkün değildir. İşte
sorun burada başlamaktadır. Çözüm ise ilerleyen adımlarda ele
alınacaktır. Bölümün başındada belirtildiği gibi ilk olarak,
serileştirilemeyen tipin yerine geçecek bir vekil sınıf yazılmalıdır ki
bu çoğunlukla Surrogate Data Contract olarak
anılır.

Yukarıdaki şekle göre Uretici
sınıfı için UreticiSurrogated isimli bir vekil tip tayin
edilmiştir. Bu sınıfın kendisi bir veri sözleşmesi olacak şekilde
tanımlanmıştır. Burada en önemli nokta vekil tipin serileştirilebilir
olmasıdır. UreticiSurrogated sınıfı servis tarafında aşağıdaki
gibi tasarlanabilir.

using System;
using
System.Runtime.Serialization;
namespace UrunYonetim
{
[DataContract(Name="Vendor")] // Bilinçli olaraktan Vendor adı
verilmiştir.
public class UreticiSurrogated
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Ad { get; set; }
[DataMember]
public string Adres { get; set; }
}
} |
Bu sınıf sadece ve sadece
serileştirilemeyen Uretici sınıfı yerine kullanılacak vekil
tiptir. Şimdi serileştirme, ters serileştirme, şema yayınlama gibi
işlemler sırasında devreye girecek olan bir sınıfın daha tasarlanması
gerekmektedir. Bu sınıfın en önemli özelliği ise
IDataContractSurrogate arayüzünü(Interface) uyguluyor
olmasıdır. Bu arayüze ait metodlar yukarıda bahsedilen işlemler
sırasında devreye girmektedir. Söz konusu WCF servis kütüphanesi
içerisinde aşağıdaki gibi tasarlanabilir.(IDataContractSurrogate
arayüzünün(Interface) kullanılabilmesi için
System.Runtime.Serialization.dll assembly dosyasının projeye
referans edilmesi gerekmektedir.)

using System;
using
System.Runtime.Serialization;
using Ureticiler;
namespace UrunYonetim
{
public class UreticiSurrogater
:IDataContractSurrogate
{
#region IDataContractSurrogate
Members
public object
GetCustomDataToExport(Type
clrType, Type dataContractType)
{
return
null;
}
public object
GetCustomDataToExport(System.Reflection.MemberInfo
memberInfo, Type dataContractType)
{
return
null;
}
// Bu metod
serileştirme(Serialization), ters-serileştirme(DeSerialization),
schema import ve export işlemleri sırasında devreye girer.
// Serileşemeyen tip ile Surrogate
tip arasındakai eşleştirmeyi yapar.
// type isimli metod parametresi
serileştirilmiş, ters serileştirilmiş, şeması import veya export
edilmiş tipi işaret etmektedir.
public
Type
GetDataContractType(Type
type)
{
if
(typeof(Uretici).IsAssignableFrom(type))
return
typeof(UreticiSurrogated);
return type;
}
// Bu metod surrogate tip örneğinin
orjinal tip örneğine dönüştürülmesi sırasında kullanılır.
// Ters-serileştirme(Deserialization)
işlemi sırasında çalışır.
public
object
GetDeserializedObject(object
obj, Type targetType)
{
if (obj is
UreticiSurrogated)
{
UreticiSurrogated surrogated = (UreticiSurrogated)obj;
Uretici
uretici = new
Uretici(surrogated.Id,surrogated.Ad,surrogated.Adres);
return
uretici;
}
return obj;
}
public void
GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type>
customDataTypes)
{
}
// Orjinal tip örneğini, surrogate
tip örneğine dönüştürmek için kullanılır.
// Serileştirme işlemi için bu metod
gereklidir.
public
object
GetObjectToSerialize(object
obj, Type targetType)
{
if (obj is
Uretici)
{
Uretici
uretici = (Uretici)obj;
UreticiSurrogated surrogated = new UreticiSurrogated();
surrogated.Ad = uretici.Ad;
surrogated.Id = uretici.Id;
surrogated.Adres = uretici.Adres;
return
surrogated;
}
return obj;
}
// Schema import' u sırasında bu
metod çalıştırılır.
public
Type
GetReferencedTypeOnImport(string
typeName, string typeNamespace, object customData)
{
if (typeName ==
"UreticiSurrogated")
return
typeof(Uretici);
return null;
}
public
System.CodeDom.CodeTypeDeclaration
ProcessImportedType(System.CodeDom.CodeTypeDeclaration
typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
{
throw new
NotImplementedException();
}
#endregion
}
} |
Bu işlemin ardından servis tarafında
davranışların(Behavior) Surrogater tipine göre
özelleştirilmesi ve Metadata Export işlemleri için gerekli
ek kodlamaların yapılması gerekmektedir. İlk olarak Surrogate
implemantasyonunun nasıl yapılacağı ele alınmalıdır. Bu amaçla kod
tarafında aşağıdaki adımlar izlenmelidir.
- İlk olarak ServiceHost
nesnesi üzerinden tüm ServiceEndPoint nesneleri dolaşılır.
- Her bir ServiceEndpoint
örneği içerisinden o andaki EndPoint bileşenine ait
OperationDescription nesneleri bulunur.
- Bulunan OperationDescription
nesneleri içerisinde DataContractSerializerOperationBehavior
örnekleri Find metodu ile aranır.
- Eğer
DataContractSerializerOperationBehavior örnekleri bulunursa,
DataContractSurrogate özelliğine geliştirilen Surrogater
nesne örneği atanır. Böylece ilgili operasyon çağrısında, orjinal
tip ile Surrogate tipin eşleştirmelerini yapacak, bir birleri
arasında serileştirme geçişlerini sağlayacak olan tip, WCF
Runtime ortamına bildirilmiş olunur.
- Opsiyonel olarak eğer söz
konusu davranış bulunamassa,
DataContractSerializerOperationBehavior örneğinin oluşturulması,
yine DataContractSurrogate özelliğie ilgili atamanın
yapılması ve bukez davranışın ilgili operasyona eklenmesi
gerekmektedir.
Söz konusu adımlara göre aşağıdaki gibi
bir kod parçası geliştirilebilir.
using System;
using System.ServiceModel;
using
System.ServiceModel.Description;
using UrunYonetim;
namespace Sunucu
{
class Program
{
static void Main(string[] args)
{
ServiceHost
host = new ServiceHost(typeof(UrunYonetici));
SurrogaterEkle(host);
host.Open();
Console.WriteLine(host.State);
Console.WriteLine("Kapatmak için bir tuşa basın");
Console.ReadLine();
host.Close();
}
private static void
SurrogaterEkle(ServiceHost host)
{
foreach
(ServiceEndpoint endPoint in host.Description.Endpoints)
{
foreach
(OperationDescription oprDesc in endPoint.Contract.Operations)
{
DataContractSerializerOperationBehavior dcBehavior =
(DataContractSerializerOperationBehavior)oprDesc.Behaviors.Find<DataContractSerializerOperationBehavior>();
if
(oprDesc.Behaviors.Find<DataContractSerializerOperationBehavior>()
!= null)
dcBehavior.DataContractSurrogate = new UreticiSurrogater();
}
}
}
}
} |
Burada Servis uygulaması üzerinde
SurrogaterEkle metodu ile söz konusu işlemler gerçekleştirilmektedir.
Sunucu uygulama bu haliyle çalıştırıldığında ve debug
penceresinde ServiceHost nesnesi Quick Watch ile
izlendiğinde aşağıdaki ekran görüntüsü yakalanabilir.

Bu ekran görüntüsünde, 0 indisli
EndPoint üzerinde tanımlı olan IUrunYonetici sözleşmesine
ait UrunEkle operasyonunun davranışlarına dikkat edilmelidir.
DataContractSerializer tipinden olan davranışın içerisinde yer alan
DataContractSurrogate özelliğinin değerinin, UreticiSurrogater
olarak set edilmiş olduğu açık bir şekilde görülmektedir.
Surrogate kullanımında Microsoft
tarafından önerilen Best Practices ise, bu tip operasyon
davranışı atamaları ve şema export işlemleri için özel olarak yazılmış
bir niteliğin(Attribute) kullanılmasını önermektedir. Yazıda
geliştirilen örnek düşünüldüğü takdirde bu niteliğin servis
sözleşmesinde(Service Contract) kullanılması, IContractBehavior,
IOperationBehavior ve IWsdlExportExtension arayüzlerini
uygulaması gerekmektedir. IContractBehavior ve
IOperationBehavior arayüzlerinin bazı üyeleri kullanılarak
yukarıdaki kod parçasında yapılan davranış tanımlamaları
gerçekleştirilebilmektedir. Diğer taraftan IWsdlExportExtension
arayüzü ile gelen metodlar sayesinde, Metadata yayınlamasının
Surrogate tipine göre yapılabilmesi sağlanabilmektedir. Söz konusu
nitelik aşağıdaki gibi geliştirilebilir.

using System;
using System.Runtime.Serialization;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
namespace UrunYonetim
{
public class
SurrogaterAttribute
: Attribute
,
IContractBehavior
,
IOperationBehavior
,
IWsdlExportExtension
{
#region IContractBehavior Members
public void
AddBindingParameters(ContractDescription description,
ServiceEndpoint endpoint, BindingParameterCollection parameters)
{
}
public void
ApplyClientBehavior(ContractDescription description,
ServiceEndpoint endpoint,
System.ServiceModel.Dispatcher.ClientRuntime proxy)
{
foreach
(OperationDescription oprDesc in description.Operations)
{
SurrogateUygula(oprDesc);
}
}
public
void ApplyDispatchBehavior(ContractDescription description,
ServiceEndpoint endpoint,
System.ServiceModel.Dispatcher.DispatchRuntime dispatch)
{
foreach
(OperationDescription oprDesc in description.Operations)
{
SurrogateUygula(oprDesc);
}
}
public void Validate(ContractDescription description,
ServiceEndpoint endpoint)
{
}
#endregion
#region IWsdlExportExtension Members
public void
ExportContract(WsdlExporter exporter,
WsdlContractConversionContext context)
{
if (exporter == null)
throw new ArgumentNullException("exporter");
object
dataContractExporter;
XsdDataContractExporter xsdDCExporter;
if
(!exporter.State.TryGetValue(typeof(XsdDataContractExporter),
out dataContractExporter))
{
xsdDCExporter = new
XsdDataContractExporter(exporter.GeneratedXmlSchemas);
exporter.State.Add(typeof(XsdDataContractExporter),
xsdDCExporter);
}
else
{
xsdDCExporter = (XsdDataContractExporter)dataContractExporter;
}
if
(xsdDCExporter.Options == null)
xsdDCExporter.Options = new ExportOptions();
if
(xsdDCExporter.Options.DataContractSurrogate == null)
xsdDCExporter.Options.DataContractSurrogate = new
UreticiSurrogater();
}
public void ExportEndpoint(WsdlExporter exporter,
WsdlEndpointConversionContext context)
{
}
#endregion
#region IOperationBehavior Members
public void
AddBindingParameters(OperationDescription description,
BindingParameterCollection parameters)
{
}
public void
ApplyClientBehavior(OperationDescription description,
System.ServiceModel.Dispatcher.ClientOperation proxy)
{
SurrogateUygula(description);
}
public
void
ApplyDispatchBehavior(OperationDescription
description, System.ServiceModel.Dispatcher.DispatchOperation
dispatch)
{
SurrogateUygula(description);
}
public void Validate(OperationDescription description)
{
}
#endregion
private static
void SurrogateUygula(OperationDescription description)
{
DataContractSerializerOperationBehavior dcsOperationBehavior =
description.Behaviors.Find<DataContractSerializerOperationBehavior>();
if
(dcsOperationBehavior != null)
{
if
(dcsOperationBehavior.DataContractSurrogate == null)
dcsOperationBehavior.DataContractSurrogate
= new UreticiSurrogater();
}
}
}
} |
Artık tek yapılması gereken söz konusu
niteliğin servis sözleşmesinde aşağıdaki gibi uygulanmasıdır.
[ServiceContract(Name="UrunServisi",Namespace="http://www.bsenyurt.com/UrunServisi")]
[Surrogater]
public interface IUrunYonetici
{
[OperationContract]
void UrunEkle(Urun urun);
[OperationContract]
Urun UrunGuncelle(Urun urun);
} |
Bu işlemlerin tamamlanması ile birlikte
istemci için gerekli olan proxy ve config üretimleri
gerçekleştirilebilir. Servis uygulaması çalışıyorken svcutil
aracı kullanılırsa, aşağıdaki ekran görüntüsünde olduğu gibi ilgili
üretimlerin başarılı bir şekilde yapıldığı görülebilir.

Bu adımların arından istemci için
üretilen proxy(UrunYonetici.cs) ve
konfigurasyon(output.config) dosyaları örnek bir Console
uygulamasında aşağıdaki kod parçasında olduğu gibi kullanılabilir.
using System;
using UrunYonetim;
namespace Istemci
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Başlamak için bir tuşa basınız");
Console.ReadLine();
UrunServisiClient
client = new UrunServisiClient("UrunServisiTcpEndPoint");
Urun urn = new Urun()
{
Ad = "Mouse",
BirimFiyat = 12,
Id = 1,
StokMiktari = 50,
Ureten =
new Vendor()
{
Id
= 1001,
Ad =
"Adventure 1",
Adres =
"Adventure 1 Yolu Üzeri Minesotta"
}
};
client.UrunEkle(urn);
Urun guncellenen =
client.UrunGuncelle(urn);
Console.WriteLine("{0} guncellendi", guncellenen.Ad);
}
}
} |
UrunServisiClient isimli nesne
konfigurasyonda dosyasından belirtilen ilgili EndPoint noktasına göre
oluşturulduktan sonra, Urun sınıfına ait bir nesne C# 3.0
object initializer ile örneklenmektedir. Bu örnekleme sırasında
Ureten özelliği Vendor isimli tipe ait bir örnek almaktadır.
(Burada Vendor için varsayılan yapıcı metodun var olduğuna, oysaki
serileştirilemeyen Uretici tipinde böyle yapıcının yazılmadığına dikkat
edilmelidir.) Sonrasında ise servis üzerinden önce UrunEkle
ardından UrunGuncelle metodları çağırılmaktadır. Önce servis
uygulaması ardındanda istemci uygulama çalıştırılırsa aşağıdakine benzer
bir ekran çıktısı alınır.

İstemci uygulama için üretilen proxy
dosyası içeriğine bakıldığında ise, aşağıdaki sınıf diagramında(Class
Diagram) görüldüğü gibi Vendor isimli bir tipin üretildiği
farkedilebilir.

Vendor adı tesadüfi değildir nitekim,
UreticiSurrogated sınıfında kullanılan DataContract
niteliğinde, Name özelliğine bu değer verilmiştir. Bu sebepten
dolayı istemci tarafına Metadata aktarımı sırasında taşınan tipin adıda
Vendor olarak set edilmektedir. Vendor isimli sınıf
aslında serileştirilemeyen Uretici tipinin yerine istemci
tarafında kullanılan vekildir. Buraya kadar anlatılanlar ile
serileştirilemeyen bir veri sözleşmesinin, Surrogate teknikleri
sayesinde istemci tarafına nasıl aktarılabileceği ve servis ile olan
iletişimde nasıl kullanılabileceği incelenmiştir. Surrogate
kullanımı ile ilgili olaraktan daha detaylı bilgi için
http://msdn.microsoft.com/en-us/library/ms733064.aspx
adresindeki makaleyi takip etmenizi; ayrıca örneği daha kavrayabilmek
için mutlaka breakpoint' ler ile incelemenizi öneririm. Böylece
geldik bir makalemizin daha sonuna.Bir
sonraki makalemizde görüşünceye dek hepinize mutlu günler dilerim.
Örnek Uygulama için Tıklayın
Burak Selim ŞENYURT
selim@bsenyurt.com