WCF Client Kaynaklarının Elden Çıkarılması

Blog yazılarıma verdiğim uzun bir aradan sonra ısınma amaçlı olarak, geçtiğimiz hafta uğraştığım bir sorun ve çözümü ile yazılarıma tekrar dönmek istiyorum. Yaklaşık 6 senedir kullandığımız bir WCF uygulamamızı windows service olarak host ediyoruz. Uygulama yıllardır gayet performanslı ve sorunsuz çalışrıken son 6 aydır gün aşırı  farklı sebeplerden sorun oluşturmaya başladı. Bir süredir bakımını yaptığımız uygulamada son karşılaştığımız sorunlardan biri servise gelen taleplerin yoğun olduğu anlarda "Thread was being aborted" hatası ile taleplerin kesilmesi ve işlemlerin yarım kalması idi. İlk şüphelendiğimiz nokta, servise aynı sunucudan iki farklı talep oluştuğunda yeni açılan bağlantının önceki aktif bağlantıyı kopartıyor oluşu idi. Konu bir yandan tutarsız gözüküyor, bir yandan da sorunun sebebinin bu olduğunun tam bir kanıtını bulamıyorduk. Stackoverflow'da yaptığımız araştırmalar sorunucunda sorunun genel bir programlama hatasından kaynaklandığını, istemci uygulamada oluşturulan istemci proxy nesnelerinin Close metodu ile kapatılmadan elden çıkarılmaması, yoğun anlarda uygulamanın "Thread was being aborted" hatası atmasına sebep olduğunu gördük. Gerçekten de servis çağrılarında sürekli yeni bir istemci nesne yaratıp, istek sonucu dönünce istemciki kapatmadan işlemi sonlandırıyordu uygulamamız. Doğru kullanım ise aşağıdaki gibi kullanılan kaynakları sağlıklı bir şekilde serbest bırakması :    var client = new WCFServiceProxy(); try { client.DoSomeWork(); client.Close(); } catch (Exception e) { // log... client.Abort(); throw; }   StackOverflow'da karşılaştığım sorun ve çözüm : “Thread was being aborted” in WCF Service Call Bulduğumuz çözüm sorunu çözecek fakat ilerde bu yanlış kullanımın önüne geçmeyi sağlamayacaktı. Yazılımcı servis kullanımı sonrası yarattığı istemciyi kapatmayı unuttuğu takdirde ileriki zamanlarda tekrar sorun ortaya çıkacak. Bundan dolayı istemci proxy'nin yaratılmasını sağlayan bir yardımcı sınıfımız olduğu gibi, bu yaratılan istemcinin olması gerektiği gibi kapatılmasından da sorumlu olmalı idi. Yani tek bir noktada istemci sınıfını yaratıp, hayat döngüsünü yöneterek, kullanan yazılımcıdan encapsule etmeliydik. WCF istemci proxy sınıfını using ile kullanıp gerektiğinde elden çıkarılmasının sağlanması da bir opsiyon fakat bu çözümde yine yazılımcının unutması halinde soruna sebep olabilecek bir durum. Ayrıca Marc Gravell'in şu makalesinde bahsettiği üzere framework'te bulunan bazı sorunlardan dolayı ClientBase sınıfının her zaman düzgün dispose edilemiyor. Marc Gravell makalesinde extension metodlar ile istediğim tarz çözüme bir örnek vermiş. Ancak ben "Indisposable: WCF Gotcha #1" makalesindeki gibi bir çözüm ile proxy istemcisinin yaratılmasını ve sonlandırılmasını sağlayacak komple bir çözümü tercih etmeyi daha uygun görüyorum. İstemciyi yaratıp kullanan bir örnek :   Service<IWCFServiceProxy>.Use(client=> { client.DoSomeWork(); }   Use extension metodu :   public delegate void UseServiceDelegate<T>(T proxy); public static class Service<T> { public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>(""); public static void Use(UseServiceDelegate<T> codeBlock) { IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel(); bool success = false; try { codeBlock((T)proxy); proxy.Close(); success = true; } finally { if (!success) { proxy.Abort(); } } } }   Yukarıdaki metodda görüldüğü gibi UseServiceDelegate delegate'i ile yazılımcının servis çağrısı, Use extension metodu içerisinde oluşturulan istemci sınıfı kullanarak çalıştırılıp, delegate tamamlanınca istemci olması gerektiği gibi kapatılıyor. Bizim kendi örneğimizde olduğu gibi WCF istemcisine geçilen ek konfigurasyon değerleri var ise, ki bu konfigurasyonları uygulamanın config dosyası yerine kodda geçmeyi uygun gördük, metod içersinde tanımlanabilir. Böylece istemci sınıfın yaratılması ve kapatılması ile ilgili tüm detayları kullanıcı yazılımcıdan saklamış ve kod çoklanmasının da önüne geçmiş oluyoruz.