İlkay İlknur

just a developer...

WCF Serileştirme Problemi ve WCF Tracing

Merhaba Arkadaşlar,

Bu yazımda sizlere WCF Servisleri ile çalışırken karşılaştığım bir sorundan ve sorunun çözümünden bahsetmek istiyorum. Öncelikli olarak senaryodan bahsetmek gerekirse; Geliştirdiğim uygulama gereğince WCF servisinden döndürülen sonuçları tek bir wrapper sınıf içerisinde döndürmeyi ve web servisinin her çağrımında aynı zamanda çağrımla ilgili bir takım bilgileri de bu wrapper tip içerisine koyarak, web servis metotlarından sadece bu wrapper sınıfı döndürmeyi hedefledim. Böylece web servisi sonuç dönüşlerinde ortak bir format yakalaycaktım ve bazı işlemleri daha standart bir şekilde yapacaktım. ServiceResult ismini verdiğim wrapper tipimin gerçekleştirimi ise şu şekilde idi.

public class ServiceResult
{
public bool Completed { getset; }
public object Result { getset; }
public string Message { getset; }
}

Daha sonra web servisi içerisindeki tüm metotlar içerisinde tip içerisindeki alanları uygun bir şekilde doldurduktan sonra aslında web servisinden döndürmem gereken nesneyide ServiceResult tipi içerisinde bulunan Result propertysi içerisine koyarak web servisinden ServiceResult nesnesini döndürmekteyim.

Örnek bir web servisi gerçekleştirimini ise şöyle verebilirim.

    [ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MyService
{
[OperationContract]
public ServiceResult Call(int i)
{
ServiceResult result = new ServiceResult();
if (i == 0)
{
result.Completed = true;
result.Result = new Book()
{
Author="Martin Fowler",
Header = "Domain Spesific Languages"
};
result.Message = "i="+i.ToString()+" değerine göre kitap nesnesi üretildi";
}
else
{
result.Completed = true;
result.Result = new Album()
{
Singer = "Lady Gaga",
SongNumber = 13
};
result.Message = "i="+i.ToString()+" değerine göre albüm nesnesi üretildi";
}
return result;
}

Sizin de farkedebileceğiniz gibi örneğin metot içerisinde verilen parametreye göre ServiceResult içerisindeki Result propertysine parametrenin 0 olmasıyla yeni bir Book nesnesi konulmuş, parametrenin 1 olmasıyla da Album nesnesi konulmuştur.

Buraya kadar olan kısma baktığımızda herşey oldukça normal gözükmekte. O zaman uygulamaya devam ederek bir Silverlight uygulamasına bu web servisini bağlayalım ve ilgili metodu çağıralım.

Silverlight tarafının gerçekleştirimi ise şu şekilde olabilir.

MyServiceNamespace.MyServiceClient proxy = new MyServiceNamespace.MyServiceClient();
private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
proxy.CallCompleted += new EventHandler<CallCompletedEventArgs>(proxy_CallCompleted);
proxy.CallAsync(0);
proxy.CallAsync(1);
}

void proxy_CallCompleted(object sender, CallCompletedEventArgs e)
{
if(e.Result.Completed)
{
dynamic obj = e.Result.Result;
MessageBox.Show(e.Result.Message);
}
}

Herşey güzel ve sorunsuz giderken bir de uygulamayı çalıştıralım ve sonuca bakalım. Smile

Peki bu hata da nereden çıktı. Herşey gayet güzel gidiyordu. Uygulamaları derledik hiçbir sorun da yoktu. Runtime sırasında ne oldu da hata verdi ? Bu şekilde düşündükten sonra "Not Found" sonucuna bakarak hiçbir sonuca ulaşamayız. Onun yerine WCF servisine trace etmemiz çok daha yerinde olacaktır.

WCF Servisleri Nasıl Trace Edilir ?

WCF Servislerini trace etmek için her zaman olduğu gibi yine System.Diagnostics namespace'i içerisindeki tiplerden yararlanmaktayız. Hemen işi uzatmadan MSDN içerisinde de bulunan konfigürasyon kısmını uygulamanızın tipine göre app.config veya web.config dosyaları içerisinde yerleştirerek tracinge  başlayabilirsiniz.

<system.diagnostics> <trace autoflush="true" /> <sources> <source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true"> <listeners> <add name="sdt" type="System.Diagnostics.XmlWriterTraceListener" initializeData= "SdrConfigExample.e2e" /> </listeners> </source> </sources> </system.diagnostics>

Daha sonra servisin çalışması süresi içerisinde elde edilen bilgiler "SdrConfigExample.e2e" dosyası içerisinde oluşacaktır. XML kullanılarak oluşturulan bu dosyayı okumak için bir de yardımcı bir tool olsa hiç fena olmazdı dediğinizi duyar gibiyim. Smile Öyleyse WCF Service Trace Tool tam size göre. WCF Service Trace Tool'a "C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin" uzantısı altından "SvcTraceViewer.exe" isimli uygulamayı çalıştırarak erişebilirsiniz. WCF Service Tracing ile ilgili çok daha detaylı bilgiyi MSDN'den alabilirsiniz.

Konumuza Geri Dönelim :)

Uygulamamızı config dosyasında yaptığımız değişiklikten sonra bir daha çalıştırıyoruz ve oluşturulan dosyayı WCF Service Trace tool yardımıyla açtıktan sonra incelemeye başlıyoruz. Uygulamayı açtıktan sonra sol kolonda bulunan activity bölümüne baktığımızda hata ile karşılaştığımız yer kırmızı olarak bizim karşımıza çıkmakta.

 

Hatanın detaylarına baktığımızda karşımıza nerede hata olduğu çok açık bir biçimde çıkmakta.

 

There was an error while trying to serialize parameter :CallResult. The InnerException message was 'Type 'SilverlightApplication5.Web.Album' with data contract name 'Album:http://schemas.datacontract.org/2004/07/SilverlightApplication5.Web' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'.  Please see InnerException for more details.

Karşımıza çıkan hatanın açıklaması ise şu şekilde :)  Biz developer olarak işin kolayına kaçarak hemen bir object koyduk tipin içerisine ve aklımızca istediğimiz tipten nesneleri bu property içerisine koyarak servisten döndürebileceğimizi düşündük. Ama unuttuğumuz bir nokta var. Bu objectlerin nasıl serileştirileceğini belirtmedik.Smile Yani normalde bu tiplerden birini web servisinden döndürseydik tipi serileştirme konusunda bir problem olmayacaktı. Ancak WCF servisine hangi tipleri koyabileceğimizi bile bildirmeden servisten döndürmeye çalıştık ve hata ile karşılaştık. Serviste kibar bir şekilde bari bu object içerisine koyabileceğin muhtemel tipleri bana söyle ki bende ona göre hazırlıklı olayım mesajını verdi.

Peki bu olayın çözümü nasıl olacak ? Çözüm = KnownType

Yapmamız gereken biraz önce de söyledğim gibi object kısmına muhtemel olarak önceden gelebilecek olan tipleri bildirmek. Bunu da System.Runtime.Serialization isim uzayı içerisinde bulunan KnownType attribute kullanarak gerçekleştiriyor olacağız. ServiceResult tipine yapacağımız muhtemel tip bildirimi ise şu şekilde olacak.

[KnownType(typeof(Book))][KnownType(typeof(Album))]public class ServiceResult

 Tüm bu işlemleri gerçekleştirdikten sonra uygulamayı çalıştırırsak başarılı bir şekilde MessageBox'ları görebiliriz. Smile

 

Herkese Kolay Gelsin,

Görüşmek Üzere,



Yorum Gönder