https://www.buraksenyurt.com/Burak Selim Şenyurt - WCF 4.0 Beta 12017-01-26T12:36:11+00:00Matematik Mühendisi Bir Bilgisayar Programcısının NotlarıBurak Selim SenyurtBlogEngine.Net Syndication Generatorhttps://www.buraksenyurt.com/opml.axdBurak Selim SenyurtMatematik Mühendisi Bir Bilgisayar Programcısının Notlarıtr-TRBurak Selim Şenyurt0.0000000.000000https://www.buraksenyurt.com/post/WCF-40-Yenilikleri-DataContractResolver-ile-Dynamic-Type-ResoluitonWCF 4.0 Yenilikleri - DataContractResolver ile Dinamik Tip Çözümleme(Dynamic Type Resolution) [Beta 1]2009-09-26T16:30:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p>Hatırlayacağınız üzere bir önceki yazımızda, WCF serileştirme işlemlerinde <strong>Known Types </strong>sorunsalını değerlendirmeye çalışmıştık. Bu sorunsalın giderilmesinde ele alınan tekniklerden biriside <strong>KnownType</strong> <strong>niteliğinin(Attribute)</strong> kullanılmasıyıdı. Ama istersek servise uygulanacak <strong>ServiceKnownType</strong> niteliği ve başka diğer teknikleri de değerlendirebileceğimizden bahsetmiştik. Ne varki tüm bu teknikler <strong>static</strong> bir model sunmaktadır. <strong>WCF 4.0 </strong>ile birlikte, <strong>tip çözümlemelerinin(Type Resolution)</strong> <strong>dinamik</strong> olarak ele alınmasını sağlayan <strong>DataContractResovler</strong> isimli <strong>abstract</strong> bir sınıfın geldiği görülmektedir. Bu sınıf <strong>System.Runtime.Serialization.dll</strong> <strong>assembly' </strong>ının <strong>.Net Framework 4.0 </strong>versiyonunda yer almaktadır. Abstract bir sınıf olması, <strong>türetmede(Inheritance)</strong> kullanıldığı takdirde anlam kazanacak bir tip olduğunu ifade etmektedir.</p>
<p>Aslında teori basittir. <strong>DataContractResolver</strong> sınıfı iki <strong>abstract</strong> metod tanımlaması içerir. <strong>ResolveType </strong>ve <strong>ResolveName</strong>. Bu metodlar tahmin edileceği üzere, tip çözümlemesinde <strong>serileştirme(Serialization)</strong> ve <strong>ters-serileştirme(DeSerialization) </strong>işlemlerinde bir veya daha fazla <strong>Known Type' </strong>ın ele alınması gerektiği durumlarda devreye girmektedir. Çok doğal olarak metodların uygulanması için bir sınıfın <strong>DataContractResolver</strong> tipinden türetilmesi gerekir. O halde <strong>"türetilen ve tip çözümlemesi işlerini üstlenen sınıf nerede kullanılır?"</strong> sorusu da ortaya çıkmaktadır <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> Bunun için farklı teknikler olmasına rağmen belkide en basiti, <strong>DataContractSerializer</strong> nesne örneği oluşturulurken yapılan bildirimdir.</p>
<p>Böylece, <strong>DataContractSerializer</strong> nesne örneğinin uygulayacağı serileştirme ve ters-serileştirme işlemleri sırasında karşılaşılabilecek olası <strong>Known Type</strong> sorunlarında başvurulabilecek bir yardımcı belirlenmiş olmaktadır ki bu yardımcı, <strong>DataContractResolver</strong> türevi olan bir sınıftır. İşe bu açılardan bakıldığında, <strong>DataCotractResolver</strong> sayesinde <strong>dinamik tip çözümleme yeteneğine(Dynamic Type Resolution)</strong> sahip olduğumuzu görebiliriz. Aslında kafalarımızı dahada karıştırmadan önce dilerseniz bir önceki yazımızda ele aldığımız ve Known Type sendromuna neden olan örneğimizi ele alıp ilerlemeye çalışalım. <em>(Örneklerimizi Visual Studio 2010 Beta 1 ve .Net Framework Beta 1 üzerinde geliştirdiğimizi hatırlatmak isterim. Yani bir sonraki sürümde Beta 1 pek çok farklılık olabilir <img title="Undecided" src="/editors/tiny_mce3/plugins/emotions/img/smiley-undecided.gif" alt="Undecided" border="0" />)</em></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Runtime.Serialization;
using System.Xml;
namespace UsingDataContractResolver
{
[DataContract]
class Product
{
[DataMember]
public object Information { get; set; }
}
[DataContract]
class ProductInformation
{
[DataMember]
public string Summary { get; set; }
[DataMember]
public int Id { get; set; }
}
class Program
{
static void Main(string[] args)
{
XmlObjectSerializer serializer = new DataContractSerializer(typeof(Product));
serializer.WriteObject(new XmlTextWriter(Console.Out) { Formatting = Formatting.Indented }
, new Product { Information = new ProductInformation { Id = 1000, Summary = "Özet bilgi" } });
}
}
}</pre>
<p>Hatırlayacağınız üzere object tipinden tanımlanmış olan Information özelliğine, ProductInformation tipinden bir nesne örneği atandığında ve Known Type ile ilişkili bir bildirimde bulunmadığımızda, çalışma zamanı hatası almaktaydık. Bu sefer örneğimizi<strong> .Net Framework 4.0</strong> tabanlı olarak derleyip çalıştıracağız. Çok doğal alarak <strong>SerializationException</strong> tipinden bir istisna mesajı almayı bekliyoruz. Ancak bu sefer, <strong>SerializationException</strong> mesajı içerisinde <strong>DataContractResolver</strong> kullanılmasının da önerildiği görülmektedir.</p>
<p><img src="/pics/2009%2f9%2fblg85_Exception.gif" alt="" /></p>
<p>Peki ya çözüm?</p>
<p>Zaten <strong>.Net 3.5</strong> sürümünde <strong>KnownType</strong> niteliği gibi materyalleri kullanarak bu sorunu aşabilmekteyiz. Ancak <strong>WCF 4.0</strong> ile birlikte sunulan <strong>DataContractResolver </strong>abstract sınıfı sayesinde, söz konusu sorunu çalışma zamanında dinamik olarak değerlendirme şansına sahibiz. Şimdi örneğimizi buna göre revize edeceğiz. İlk yapmamız gereken <strong>DataContractResolver</strong> türevli bir sınıfın tasarlanması olacaktır. Aynen aşağıda görüldüğü gibi.</p>
<p><img src="/pics/2009%2f9%2fblg85_ClassDiagram.gif" alt="" /></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">class ProductInformationResolver
:DataContractResolver
{
public override Type ResolveName(string typeName, string typeNamespace, DataContractResolver knownTypeResolver)
{
if (typeName == "ProductInfo"
&& typeNamespace == "http://www.adventure.com/resolver/productInformationType")
return typeof(ProductInformation);
else
return knownTypeResolver.ResolveName(typeName, typeNamespace, null);
}
public override void ResolveType(Type dataContractType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
{
if (dataContractType == typeof(ProductInformation))
{
XmlDictionary dictionary = new XmlDictionary();
typeName = dictionary.Add("ProductInfo");
typeNamespace = dictionary.Add("http://www.adventure.com/resolver/productInformationType");
}
else
{
knownTypeResolver.ResolveType(dataContractType, null, out typeName, out typeNamespace);
}
}
}</pre>
<p>Güzel...<img title="Laughing" src="/editors/tiny_mce3/plugins/emotions/img/smiley-laughing.gif" alt="Laughing" border="0" /> Şimdi bir kaç noktayı açıklığa kavuşturmaya çalışalım. Öncelikli olarak <strong>DataContractResolver </strong>tipine ait iki metodun <strong>ezildiğini(override)</strong> görmekteyiz. <strong>ResolveType</strong> metodu serileştirme işlemi sırasında devreye girmektedir ve içeride kontrol edilen tipin <strong>XML'</strong> de nasıl ifade edileceğini belirtmektedir<strong><em>(xsi:type tanımlaması)</em></strong>. Metodda ilk olarak <strong>dataContractType</strong> parametresinin çalışma zamanında <strong>ProductInformation</strong> olup olmadığı kontrol edilir. Eğer <strong>ProductInformaion</strong> tipindense yeni bir <strong>XmlDictionary</strong> nesnesi örneklenir ve <strong>typeName</strong> ile <strong>typeNamespace </strong>değerleri bu nesne üzerine <strong>Add </strong>metodu ile set edilir.</p>
<p>Zaten <strong>typeName</strong> ve <strong>typeNamespace </strong>parametrelerinin <strong>out </strong>tipinden oldukları gözden kaçmamalıdır. Bir başka deyişle bu parametre değerleri, <strong>ResolveType </strong>metodunun çağırıldığı ortama aktarılmaktadır.<strong><em>(Out ve Ref parametrelerini hatırlıyorsunuz değil mi ? <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> ) </em></strong>Kısacası, serileştirme işlemi sırasında eğer <strong>ProductInformation</strong> tipi ile karşılaşılırsa, tip çözümlemesinin nasıl yapılacağı geliştiricinin isteği doğrultusunda tanımlanabilmektedir. Burada yer alan <strong>typeName</strong> veya <strong>typeNamespace </strong>değerlerinin herhangibir dış ortamdan alınabileceğini<strong><em>(örneğin parametrik bir XML tablosu birden fazla tipin çözümlenmesi sırasında değerlendirilebilir) </em></strong>belirtmekte yarar olduğu kanısındayım.</p>
<p><strong>ResolveName</strong> metodu ise tahmin edileceği üzere <strong>ters serileştirme(DeSerialization) </strong>işlemi sırasında devreye girmektedir. Metod içerisinde ilk olarak <strong>typeName</strong> ve <strong>typeNamespace </strong>değişkenleri kontrol edilir ve buna göre geriye döndürülecek <strong>tip(Type)</strong> belirlenir. Bu metod içerisinde de <strong>nesne tipi(Object Type) </strong>ve <strong>xsi:type </strong>eşleştirmeleri için bir referans veri kaynağı<em>(örneğin bir XML içeriği)</em> kullanılabilir.</p>
<p>Peki ya bundan sonrası? <strong>Çalışma zamanı ProductInformationResolver tipini kullanacağını nereden bilecek? </strong>İşte cevap...</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">XmlObjectSerializer serializer = new DataContractSerializer(typeof(Product),null,Int32.MaxValue,false,false,null,new ProductInformationResolver());
serializer.WriteObject(new XmlTextWriter(Console.Out) { Formatting = Formatting.Indented }
, new Product { Information = new ProductInformation { Id = 1000, Summary = "Özet bilgi" } });</pre>
<p>Dikkat edileceği üzere <strong>DataContractSerialiazer</strong> nesne örneği oluşturulurken son parametre olarak <strong>ProductInformationResolver</strong> örneği verilmektedir. Buna göre <strong>serializer </strong>nesnesinin yapacağı serileştirme ve ters-serileştirme işlemleri sırasında, <strong>ProductInformationResolver </strong>nesne örneği devreye girecektir. Örneğimizi bu haliyle deneyecek olursak, çalışma zamanında aşağıdaki sonuçların üretildiğini görebiliriz.</p>
<p><img src="/pics/2009%2f9%2fblg85_Runtime.gif" alt="" /></p>
<p>Görüldüğü üzere <strong>Information</strong> elementi içerisinde, <strong>DataContractResolver </strong>türevli olan <strong>ProductInformationResolver </strong>nesne örneğine ait <strong>ResolveType </strong>metodu içerisinde belirlenen, <strong>typeName </strong>ve <strong>typeNamespace </strong>değerleri yer almaktadır. Elbetteki serileştirilen nesnenin ters-Serileştirme işlemi sırasında da işlemlerin başarılı bir şekilde yürütüldüğü gözlemlenebilir. Ama yinede kodumuzu aşağıdaki gibi revize edip ters serileştirme işleminin çalıştığından emin olmalıyız.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">static void Main(string[] args)
{
FileStream fs=new FileStream("Product.xml",FileMode.Create,FileAccess.Write);
serializer.WriteObject(fs
, new Product { Information = new ProductInformation { Id = 1000, Summary = "Özet bilgi" } });
fs.Close();
Product product=(Product)serializer.ReadObject(new FileStream("Product.xml",FileMode.Open,FileAccess.Read));
ProductInformation information=(ProductInformation)product.Information;
Console.WriteLine("{0} {1}",information.Id,information.Summary);
}</pre>
<p>Bu kez <strong>Product.xml </strong>dosyası içerisinde serileştirme işlemini yaptıktan sonra <strong>ReadObject </strong>metodu yardımıyla <strong>XML </strong>kaynağından okuma işlemini gerçekleştirmekteyiz. <strong>ReadObject </strong>metodu geriye <strong>object </strong>türünden bir referans döndürdüğü için, <strong>bilinçli bir tür dönüşümü(Explicitly Type Cast) </strong>yapılmaktadır. Sonrasında ise <strong>product </strong>nesne örneği üzerinden <strong>Information </strong>özelliğine gidilmekte ve <strong>ProductInformation </strong>tipine dönüştürülen referansın, <strong>Id </strong>ve <strong>Summary </strong>değerlerine bakılmaktadır. İşte çalışma zamanı sonucu.</p>
<p><img src="/pics/2009%2f9%2fblg85_SecondRun.gif" alt="" /></p>
<p><strong>WCF 4.0</strong> son sürümü ile gelmesi muhtemel olan bu yenilik sayesinde,<strong> Known Type</strong> durumlarının çalışma zamanında dinamik olarak değerlendirilmesi sağlanmaktadır. Bu özelliğin geliştiricilere daha büyük bir esneklik sunduğuda ortadadır. Böylece geldik WCF 4.0 ile ilgili bir yeniliğin daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2009-09-26T16:30:00+00:00wcfwcf 4.0bsenyurtHatırlayacağınız üzere bir önceki yazımızda, WCF serileştirme işlemlerinde Known Types sorunsalını değerlendirmeye çalışmıştık. Bu sorunsalın giderilmesinde ele alınan tekniklerden biriside KnownType niteliğinin(Attribute) kullanılmasıyıdı. Ama istersek servise uygulanacak ServiceKnownType niteliği ve başka diğer teknikleri de değerlendirebileceğimizden bahsetmiştik. Ne varki tüm bu teknikler static bir model sunmaktadır. WCF 4.0 ile birlikte, tip çözümlemelerinin(Type Resolution) dinamik olarak ele alınmasını sağlayan DataContractResovler isimli abstract bir sınıfın geldiği görülmektedir. Bu sınıf System.Runtime.Serialization.dll assembly' ının .Net Framework 4.0 versiyonunda yer almaktadır. Abstract bir sınıf olması, türetmede(Inheritance) kullanıldığı takdirde anlam kazanacak bir tip olduğunu ifade etmektedir.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=1b0d53cb-b287-4107-a47c-a966c228f1000https://www.buraksenyurt.com/trackback.axd?id=1b0d53cb-b287-4107-a47c-a966c228f100https://www.buraksenyurt.com/post/WCF-40-Yenilikleri-DataContractResolver-ile-Dynamic-Type-Resoluiton#commenthttps://www.buraksenyurt.com/syndication.axd?post=1b0d53cb-b287-4107-a47c-a966c228f100https://www.buraksenyurt.com/post/WCF-40-Yenilikleri-HTTP-Cache-DestegiWCF 4.0 Yenilikleri - HTTP Cache Desteği [Beta 1]2009-09-22T13:07:00+00:00bsenyurt<p><img style="float: right;" src="/pics/2009%2f9%2fblg77_Performance.jpg" alt="" />Merhaba arkadaşlar,</p>
<p>Performans pek çok uygulama geliştirme ortamında önem arz eden konuların başında gelmektedir. Özellikle Web tabanlı uygulamalarda performans arttırmak adına göz önüne alınan kriterlerden biriside farklı tipteki <strong>önbellekleme(Caching) </strong>işlemleridir.</p>
<p>En basit ve popülerlerinden birisi olan<strong> Output Caching,REST </strong>tabanlı <strong>WCF </strong>servisleri içinde kullanılabilmektedir. WCF' in önceki sürümünde <strong>WebOperationContext</strong> tipinden yararlanılarak ekstra kod eforu ile ele alınabilen <strong>Output Cache</strong> özelliği, <strong>4.0</strong> sürümünde tamamen <strong>dekleratif</strong> olarak değerlendirilebilmektedir. Aslında bu yenilik bilindiği üzere <strong>WCF Rest Starter Kit Preview 2</strong> ile birlikte <strong>.Net Framework 3.5 </strong>üzerinde de uygulanabilmektedir. <strong>Output Cache</strong> özelliği performans için önemli bir kriter olduğundan, <strong>WCF 4.0</strong> versiyonunda doğrudan ele alınmaktadır.</p>
<p>Bu yazımızda ön bellekleme işleminin <strong>WCF 4.0</strong> içerisinde, <strong>REST</strong> tabanlı servisleri için nasıl geliştirilebileceğini ele almaya çalışacağız. İşe ilk olarak bir <strong>WCF Service Application</strong> projesi oluşturarak ve içerisine aşağıdaki servis sözleşmesi ve uygulayıcı tipi ekleyerek başlayabiliriz.</p>
<p><strong>Servis Sözleşmesi(Service Contract)</strong></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Web.Caching;
namespace Calculus
{
[ServiceContract(Namespace="http://calculus/BasicMathService")]
public interface IBasicMathService
{
[AspNetCacheProfile("ShortCache")] // Config dosyasındaki outputCacheProfile girdilerinden parametre olarak verilen isimdekini işaret eder
[OperationContract]
[WebGet]
string Sum(double x, double y);
}
}</pre>
<p><strong>Uygulayıcı tip;</strong></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.ServiceModel.Activation;
namespace Calculus
{
[AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed)]
public class BasicMathService
: IBasicMathService
{
public string Sum(double x, double y)
{
return string.Format("{0} zamanlı hesaplama {1}+{2}={3}", DateTime.Now.ToLongTimeString(), x, y, x + y);
}
}
}</pre>
<p><strong>Servisimize ait svc içeriği;</strong></p>
<pre class="brush:html;auto-links:false;toolbar:false" contenteditable="false"><%@ ServiceHost Language="C#" Debug="true" Service="Calculus.BasicMathService" CodeBehind="BasicMathService.svc.cs" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %></pre>
<p><strong>IBasicMathService</strong> isimli servis sözleşmesi içerisinde yer alan <strong>Sum</strong> metoduna <strong>WebGet</strong> ve <strong>OperationContract</strong> dışında <strong>AspNetCacheProfile </strong>isimli bir niteliğin(attribute) daha uygulandığı görülmektedir. Bu nitelik parametre olarak <strong>string</strong> bir bilgi alır. Bu bilgi ise biraz sonra yazacağımız <strong>Web.config</strong> dosyası içerisindeki bir <strong>Cache</strong> profilini işaret etmektedir. Dolayısıyla bir operasyonun çıktısının ön belleklenmesi için gerekli özellikler, konfigurasyon dosyasında tanımlanır. Servis kodunda dikkat çekici noktalardan biriside, <strong>BasicMathService</strong> tipinin, <strong>AspNetCompatibilityRequirements</strong> isimli niteliği uygulamış olmasıdır. Bu durumu biraz sonra değerlendiriyor olacağız nitekim uygulanmadığı hallerde başımıza iş açacaktır <img title="Undecided" src="/editors/tiny_mce3/plugins/emotions/img/smiley-undecided.gif" alt="Undecided" border="0" /></p>
<p>Tabikide üzerinde durmamız gereken en önemli kısım config dosyası içeriğidir.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><?xml version="1.0"?>
<configuration>
<system.web>
<compilation targetFrameworkMoniker=".NETFramework,Version=v4.0" debug="false"/>
</system.web>
<system.web>
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<!-- Süreleri farklı olan iki ayrı Cache profili tanımlanmıştır -->
<add name="ShortCache" duration="20" varyByParam="none"/>
<add name="LongCache" duration="600" varyByParam="none"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
</system.web>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<!--WebServiceHostFactory tipini kullandığımız için aşağıdaki davranışı eklememize gerek kalmamıştır-->
<!--<behaviors>
<endpointBehaviors>
<behavior>
<webHttp enableHelp="true" />
</behavior>
</endpointBehaviors>
</behaviors>-->
<services>
<service name="Calculus.BasicMathService">
<endpoint binding="webHttpBinding" contract="Calculus.IBasicMathService"/>
</service>
</services>
</system.serviceModel>
</configuration></pre>
<p>Görüldüğü üzere <strong>outputCacheSettings</strong> elementi içerisinde iki farklı önbellekleme profili tanımlanmıştır. Buna göre, <strong>Sum</strong> isimli operasyonumuz <strong>20</strong> saniyelik ön bellekleme yapan ve <strong>Querystring</strong> parametrelerini hesaba katmayan bir yapı sunmaktadır.<em> (Tabiki önbellekleme profilini oluştururken farklı özellikleride değerlendirebiliriz. </em><em>Örneğin ön bellekleme lokasyonunu değiştirebilir sunucu tarafı, istemci tarafı veya her iki taraf gibi değerler verilebilir.)</em> <strong>Config</strong> dosyasında <strong>bold</strong> olarak işaretlediğimiz diğer kısımlarda önemlidir. <strong>WCF 4.0</strong> tarafına getirilen <strong>Output Cache</strong> özelliği aslında <strong>Asp.Net</strong> ortamının hazır olarak sahip olduğu <strong>Output Cache</strong> kabiliyetlerini kullanmaktadır. Bu nedenle Asp.Net uyumluluğu önemlidir.</p>
<p>Uygulama basit bir kaç ayarlamaya sahip olmasına rağmen geliştirme ve testler sırasında beklenmedik pek çok hata ile karşılabiliriz. <img title="Sealed" src="/editors/tiny_mce3/plugins/emotions/img/smiley-sealed.gif" alt="Sealed" border="0" /> İşte karşılaşabileceğimiz bir kaç hata ve önerilen çözümler<em>(ki bu çözümlerin bir kısmı must olarak görülmelidir)</em></p>
<ul>
<li><strong>Web.config</strong> dosyasında <strong>targetFrameworkMonikor</strong> değerinin set edildiğinden emin olmalıyız. Edilmediği takdirde çalışma zamanında alınacak hata mesajı : <strong>"The application domain or application pool is currently running version 4.0 or later of the .NET Framework. This can occur if IIS settings have been set to 4.0 or later for this Web application, or if you are using version 4.0 or later of the ASP.NET Web Development Server. The <compilation> element in the Web.config file for this Web application does not contain the required 'targetFrameworkMoniker' attribute for this version of the .NET Framework (for example, '<compilation targetFrameworkMoniker=".NETFramework,Version=v4.0">'). Update the Web.config file with this attribute, or configure the Web application to use a different version of the .NET Framework."</strong></li>
<li><strong>aspNetCompatibilityEnabled</strong> niteliğinin değeri <strong>true</strong> olmadığı sürece, <strong>AspNetCacheProfile</strong> özelliğini kullanamayız. Alınacak çalışma zamanı hata mesajı : <strong>"AspNetCacheProfileAttribute is supported only in AspNetCompatibility mode. "</strong></li>
<li><strong>aspNetCompatibilityEnabled</strong> niteliğinin <strong>true</strong> olarak atamış olması yeterli olmayacaktır. Nitekim servis sınıfı için <strong>AspNetCompatibilityRequirements</strong> niteliğinin de set edilmesi gerekir. Edilmediği takdirde alınacak çalışma zamanı hata mesajı : <strong>"The service cannot be activated because it does not support ASP.NET compatibility. ASP.NET compatibility is enabled for this application. Turn off ASP.NET compatibility mode in the web.config or add the AspNetCompatibilityRequirements attribute to the service type with RequirementsMode setting as 'Allowed' or 'Required'"</strong></li>
<li><strong>Asp.Net Development Server</strong> üzerinden geliştirme yapıldığında <strong>Output Cache</strong> özelliği test edilememektedir. <strong>Output Cache</strong> özelliğinin çalışabilmesi için, servis uygulamasının <strong>IIS</strong> üzerine dağıtılması gerekmektedir.</li>
<li><strong>IIS</strong> üzerine atılan WCF servis uygulamasının özelliklerinden <strong>Target Framework'</strong> ün <strong>4.0</strong> versiyonunu işaret edecek şekilde değiştirilmesi gerekir. <em>(Örneği geliştirdiğim zamanda 4.0.20506 versiyonu idi)</em></li>
<li>Güvenlik ile ilişkili bir sıkıntı yaşanabilir. Özellikle varsayılan olarak <strong>Anonymous Access</strong> ve <strong>Integrated Windows Authentication</strong> modlarından her ikiside seçili gelebilir. Bu noktada WCF çalışma zamanı sadece bir tanesinin seçili olmasını isteyebilir. Bu durumda sadece <strong>Anonymous Access</strong> seçeneğini işaretleyerek testleri yapabiliriz. Yapılan değişiklik sonrası yinede hata mesajı alınıyorsa, IIS' in bir kere reset edilmesi gerekebilir.</li>
<li><strong>varyByParam</strong> değerini kullanmıyorsak bile <strong>none</strong> olarak atamalıyız<em>(Asp.Net tarafından bildiğimiz bir kural)</em>. Yapmadığımız takdirde alacağımız çalışma zamanı hata mesajı : <strong>"The cache profile, 'ShortCache', must include value for 'VaryByParam'. "</strong></li>
</ul>
<p>Gelelim çalışma zamanı sonuçlarına. <strong>IIS</strong> üzerine atılan <strong>WCF</strong> servisimizi çalıştırdıktan sonra <strong>Sum</strong> operasyonu için yapılan ilk <strong>HTTP GET</strong> talebi sonrası aşağıdaki örnek ekran görüntüsü elde edilmiştir.</p>
<p><img src="/pics/2009%2f9%2fblg77_Runtime1.gif" alt="" /></p>
<p>Görüldüğü gibi ilk talep karşılanmıştır. Hemen zaman bilgisine dikkat edelim ve <strong>20</strong> saniyelik <strong>Output Cache </strong>süresi dolmadan önce ikinci bir talepte bulunduğumuzu hatta x ve y değerlerini farklı olarak verdiğimizi düşünelim. Bu durumda aşağıdaki sonuçlar alınacaktır.</p>
<p><img src="/pics/2009%2f9%2fblg77_Runtime2.gif" alt="" /></p>
<p>Görüldüğü gibi istemciye gönderilen içerik değişmemiştir. Nitekim şu andaki cevap, <strong>Asp.Net Output Cache</strong> mekanizması tarafından karışlanmış bir önceki talep için üretilen hazır çıktıdır. Ancak <strong>Output Cache</strong> süresini aştıktan sonra tekrar talepte bulunursak ikinci talep için güncel sonuçları aşağıdaki örnek çıktıda görüldüğü gibi alabiliriz.</p>
<p><img src="/pics/2009%2f9%2fblg77_Runtime3.gif" alt="" /></p>
<p>Böylece sistemin çalıştığını ispat etmiş olduk <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> <strong>Output Cache</strong> özelliği <strong>REST</strong> tabanlı <strong>WCF</strong> servislerinde, perfomansı arttırıcı bir unsur olarak görülebilir. Nitekim sunucu ve istemci arasındaki gidiş gelişlerde, sürekli hesaplanması gerekmeyen ve çoğunlukla sabit olan içeriklerin tekrardan üretilmesi yerine belirli zaman dilimleri boyunca ön bellekten karşılanması hem servisin işlem yükünü azaltacak hem de hızlı cevap verme sürelerini doğuracaktır. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://www.buraksenyurt.com/pics/2009%2f9%2fRESTSupport.rar">RESTSupport.rar (37,47 kb)</a></p>2009-09-22T13:07:00+00:00wcfwcf 4.0bsenyurtEn basit ve popülerlerinden birisi olan Output Caching,REST tabanlı WCF servisleri içinde kullanılabilmektedir. WCF' in önceki sürümünde WebOperationContext tipinden yararlanılarak ekstra kod eforu ile ele alınabilen Output Cache özelliği, 4.0 sürümünde tamamen dekleratif olarak değerlendirilebilmektedir.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=5887dcf2-7096-43a1-a0f8-48b7ba2055e70https://www.buraksenyurt.com/trackback.axd?id=5887dcf2-7096-43a1-a0f8-48b7ba2055e7https://www.buraksenyurt.com/post/WCF-40-Yenilikleri-HTTP-Cache-Destegi#commenthttps://www.buraksenyurt.com/syndication.axd?post=5887dcf2-7096-43a1-a0f8-48b7ba2055e7https://www.buraksenyurt.com/post/WCF-40-Yenilikleri-Automatic-Help-PageWCF 4.0 Yenilikleri - Automatic Help Page [Beta 1]2009-09-16T16:02:00+00:00bsenyurt<p><img style="float: right;" src="/pics/2009%2f8%2fblg76_Giris.jpg" alt="" />Merhaba Arkadaşlar,</p>
<p><strong>WCF 4.0</strong> tarafında beklenen gelmesi yüksek olan yenilikleri sizlere aktarmaya çalıştığım yazılarımızın yavaş yavaş sonlarına gelmekteyiz. Elbette incelemeyemediğimiz bir çok detay var. Bunları ilerleyen dönemlerde ürün son halini alırken tartışma ve araştırma fırsatımız olacak. Bu yazımızda <strong>WCF 4.0 </strong>tarafına entegre olarak gelen <strong>REST </strong>geliştirme modeline yönelik yeteneklerden bahsedeceğiz. </p>
<p>Aslında bu yeniliklerin çoğunu <strong>WCF Rest Starter Kit </strong>ile birlikte, <strong>.Net Framework 3.5 </strong>platformu üzerinde kullanabiliyoruz. Ne varki, ek bir pakete ihtiyaç duyulmadan kullanılabilen iki özellik, <strong>WCF 4.0</strong> içerisine entegre edilmiş durumda. Bunlardan birisi otomatik yardım sayfaları<strong>(Automatic Help Page)</strong>. <strong>WCF 4.0</strong> içerisindeki <strong>WebServiceHost </strong>fabrikasını kullandığımızda otomatik olarak her <strong>RESTful </strong>servis için gelen ve varsayılan olarak açık olan yardım sayfaları, istenirse konfigurasyon dosyasındaki bir nitelik yardımıyla kapatılabilirde.</p>
<p>Yardım sayfaları özellikle <strong>HTTP</strong> protokolünün <strong>GET,POST,PUT </strong>veya <strong>DELETE </strong>gibi metodları yardımıyla erişilen <strong>RESTful </strong>servis operasyonlarının tüketiciler tarafından kolayca anlaşılmasını hedeflemektedir. Nitekim, tüketici tarafını yazan geliştiricilerin bu modelindeki bir servisin operasyonlarını çağırırken, <strong>HTTP</strong> metoduna göre nasıl bir paket içeriği veya <strong>URL</strong> hazırlayıp göndermeleri gerektiğini bilmeleri gelmektedir. Otomatik olarak üretilen yardım sayfalarının tek ve yegane amacı bu ihtiyacı karşılamaktır.</p>
<p>Şimdi bu konuyu basit bir örnek üzerinden değerlendirmeye çalışarak sonuçları görmeyi hedefleyeceğiz. Bu amaçla <strong>Visual Studio 2010 Beta 1</strong> ortamında ve <strong>.Net</strong> <strong>Framework 4.0 Beta 1 </strong>odaklı olarak hazırlayacağımız bir <strong>WCF Service Application</strong> üzerinden ilerliyor olacağız. Bu örnekte <strong>System.ServiceModel.Web.Activation </strong>isim alanında yer alan <strong>WebServiceHostFactory</strong> fabrikasından yararlanmayacağız<em>(Bir sonraki konumuz olan HTTP Cache desteğine ait örnekte ise kullanacağız)</em>. Servisimize ait sözleşmemizi<strong>(Service Contract)</strong> aşağıda görüldüğü gibi geliştirdiğimizi düşünelim.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.ServiceModel;
using System.ServiceModel.Web;
namespace GeoService
{
[ServiceContract(Namespace="http://GeoServices/LocationService")]
public interface ILocationService
{
[OperationContract]
[WebGet]
string FindLocation(string gsmNumber);
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
string FindLocationInJson(string gsmNumber);
[OperationContract]
[WebInvoke(Method = "DELETE")]
string Delete(string location);
[OperationContract]
[WebInvoke(Method="POST")]
bool Insert(Customer customer);
[OperationContract]
[WebInvoke(Method = "PUT")]
bool Move(Customer customer);
}
}</pre>
<p>Servis sözleşmesinde örnek olarak <strong>HTTP GET, POST, PUT</strong> ve <strong>DELETE</strong> metodlarına göre kullanılabilen bazı operasyonlar tanımlanmıştır. <strong>FindLocationInJson</strong> operasyonu, <strong>JSON</strong> formatında <strong>cevaplar(Response)</strong> üretmektedir. Bilindiği üzere <strong>WebGet</strong> metodu için yapılan çağrılarda <strong>URL</strong> satırından gelen talepler söz konusudur. <strong>WebInvoke</strong> niteliği ile imzalanmış operasyonlarda ise HTTP içeriğinin paket olarak gönderilmesi söz konusudur. Bu operasyonlardan <strong>Insert</strong> ve <strong>Move </strong>metodları, parametre olarak serileştirilebilir bir tip kullanmaktadır. Dolayısıyla, servisi <strong>REST</strong> modele göre kullanmak isteyen geliştiricilerin bu kritik noktalara göre paket içeriği veya URL bilgilerini nasıl hazırlayacaklarını bilmeleri son derece yararlı olacaktır. Gelelim servis sözleşmesini uygulayan tipimize;</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
namespace GeoService
{
public class LocationService
: ILocationService
{
public string FindLocation(string gsmNumber)
{
return String.Format("({0}:{1})-({2}:{3})", 36, 42, 26, 45);
}
public string FindLocationInJson(string gsmNumber)
{
return String.Format("({0}:{1})-({2}:{3})", 36, 42, 26, 45);
}
public string Delete(string location)
{
return string.Format("{0} ----> {1}",location);
}
public bool Insert(Customer customer)
{
return false;
}
public bool Move(Customer customer)
{
return true;
}
}
public class Customer
{
public string GsmNo { get; set; }
public string Name { get; set; }
public string Location { get; set; }
}
}</pre>
<p>Operasyonalrın uygulanışında herhangibir özel durum söz konusu değildir aslında. Asıl üzerinde duracağımız nokta <strong>Web.config </strong>dosyasının içeriğidir. <strong>Web.config </strong>dosyasında yer alan <strong>system.ServiceModel</strong> element içeriğini aşağıdaki gibi düzenleyebiliriz.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><system.serviceModel>
<services>
<service name="GeoService.LocationService">
<endpoint address="" binding="webHttpBinding" contract="GeoService.ILocationService"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp enableHelp="true"/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel></pre>
<p><strong>Bağlayıcı tip(Binding Type)</strong> olarak <strong>webHttpBinding </strong>kullanmamızın sebebi elbetteki servisimizin <strong>RESTful </strong>özelliklerine göre hizmet vermesinin sağlanmasıdır. Diğer yandan <strong>endPoint </strong>noktasına eklenen <strong>webHttp </strong>isimli davranışın <strong>enableHelp </strong>özelliğine <strong>true</strong> değeri atanmıştır. Buna göre çalışma zamanında <strong>help</strong> takısı ile servis talep edildiğinde aşağıdaki çıktı ile karşılaşılır.</p>
<p>URL : http://localhost:2166/LocationService.svc/<strong>help</strong></p>
<p><img src="/pics/2009%2f8%2fblg76_Runtime.gif" alt="" /></p>
<p>Görüldüğü üzere tüm operasyonlar için nasıl çağırılacaklarına, ne tür cevaplar döndüreceklerine dair bilgiler ve hatta kullanılan serileştirilebilir tipler varsa bunların şemalarına ait detaylar bu yardım sayfasında yer almaktadır. Tabi şu anda help sayfası için, <strong>Internet Explorer'</strong> ın <strong>Feed </strong>özelliğine göre bir çıktı elde edilmektedir. Normal şartlarda kaynağa baktığımızda aslında varsayılan olarak <strong>ATOM</strong> formatında bir <strong>feed</strong> içeriğinin üretildiği görülebilir.</p>
<p><img src="/pics/2009%2f8%2fblg76_RuntimeAtom.gif" alt="" /></p>
<p>Hemen hatırlalatım örneğimizde <strong>WebServiceHostFactory</strong> kullanmadığımızdan, yardım sayfaları <strong>enableHelp</strong> niteliğine <strong>true</strong> değerini atamadığımız sürece çalışmayacaktır. <strong>GET</strong> metodlarının çağrıları dikkat edileceği üzere doğal olarak bir <strong>URL</strong> formatındadır. Diğer taraftan örneğin <strong>Insert </strong>operasyonunu çağırmak istediğimizi göz önüne alalım. Bu durumda geliştirici olarak tek yapmamız gereken <strong>Request</strong> ve örnek talep formatı için <strong>Example</strong> isimli bağlantılardan elde edilen sonuçlara bakmak olacaktır. Insert operasyonu için üretilen şema aşağıdaki gibidir.</p>
<p>URL : http://localhost:2166/LocationService.svc/<strong>help/request/schema</strong></p>
<p><img src="/pics/2009%2f8%2fblg76_InsertSchema.gif" alt="" /></p>
<p>Dikkat edileceği üzere şema bilgisinden yararlanılarak operasyona parametre olarak nasıl bir tip gönderilmesi gerektiği, üyelerinin ne olacağı açık bir şekilde görülmektedir. <strong>Insert</strong> operasyonu için <strong>Example</strong> linkine tıkladığımızda ise örnek bir <strong>POST</strong> çağrısının içeriğinin nasıl olması gerektiğinin örneklendiği görülecektir.</p>
<p>URL : http://localhost:2166/LocationService.svc/<strong>help/Insert/request/example?format=Xml</strong></p>
<p><img src="/pics/2009%2f8%2fblg76_InsertExample.gif" alt="" /></p>
<p>İşte bu kadar. Son derece basit bir özellik olmakla birlikte otomatik yardım sayfaları aslında tüketiciyi yazan geliştiriciler için bulunmaz bir nimettir. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://www.buraksenyurt.com/pics/2009%2f8%2fHelpSupport.rar">HelpSupport.rar (18,55 kb)</a></p>2009-09-16T16:02:00+00:00wcfwcf 4.0bsenyurtWCF 4.0 tarafında beklenen gelmesi yüksek olan yenilikleri sizlere aktarmaya çalıştığım yazılarımızın yavaş yavaş sonlarına gelmekteyiz. Elbette incelemeyemediğimiz bir çok detay var. Bunları ilerleyen dönemlerde ürün son halini alırken tartışma ve araştırma fırsatımız olacak...https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=6e9f6f47-5fa2-415b-8989-f1ed8054f0880https://www.buraksenyurt.com/trackback.axd?id=6e9f6f47-5fa2-415b-8989-f1ed8054f088https://www.buraksenyurt.com/post/WCF-40-Yenilikleri-Automatic-Help-Page#commenthttps://www.buraksenyurt.com/syndication.axd?post=6e9f6f47-5fa2-415b-8989-f1ed8054f088https://www.buraksenyurt.com/post/WCF-40-Yenilikleri-Routing-Service-MatchAll-FiltresiWCF 4.0 Yenilikleri - Routing Service - MatchAll Filtresi [Beta 1]2009-09-13T21:00:00+00:00bsenyurt<p><img style="float: right;" src="/pics/2009%2f8%2fblg75_Giris.jpg" alt="" />Merhaba Arkadaşlar,</p>
<p>Bundan önceki yazılarımızda<strong> WCF 4.0</strong> için <strong>yönlendirme servislerinin(Router Service)</strong> nasıl yazılabileceğini incelemeye çalışmıştık. Fark edeceğiniz üzere yönlendirme servislerinin en önemli noktaları arasında filtreleme tablosu ve filtrelerin olduğunu gördük. Bununla birlikte sadece <strong>Action</strong> tipinde bir filtreleme kullanıp, istemciden gelen <strong>SOAP</strong> paketinin <strong>Action</strong> kısmından yararlanılarak bir yönlendirme yapılmasını inceledik.</p>
<p>Oysaki filtreleme tipi olarak <strong>Action</strong> dışında, <strong>Address, AddressPrefix, StrictAnd, EndpointName, MatchAll, XPath </strong>gibi seçeneklerimiz de bulunmaktadır. İşte bu yazımızda <strong>MatchAll</strong> seçeneğini incelemeye çalışıyor olacağız. <strong>MatchAll</strong> seçeneğine göre, istemciden gelen mesajın içeriği ne olursa olsun, söz konusu talebin tanımlanan birden fazla <strong>DownStream</strong> servise yönlendirilmesi mümkündür. Ancak önemli bir kısıtlama vardır.</p>
<p>Bu kısıtlamaya göre sadece <strong>One-Way </strong>veya <strong>Duplex </strong>modeldeki <strong>iletişim(Communication)</strong> desteklenir. Dolayısıyla <strong>Request/Reply</strong> modelde olan iletişimi ele alan tipleri yönlendirme servisi üzerinde kullanamayız. Bu kısıtlamaya rağmen bazı senaryolarda<em>(örneğin asenkron modellerde),</em> istemciden gelen talebin birden fazla <strong>DownStream' </strong>e aktarılmasının <strong>WCF 4.0</strong> ile gelen özellikler sayesinde kolaylaştırılmış olması, geliştiriciler açısından oldukça heyecan vericidir.<img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> </p>
<p>Öyleyse vakit kaybetmeden basit bir örnek üzerinden ilerlemeye ne dersiniz. Ben yazıyı gecenin geç bir vaktinde yazdığım için yanımda bir adet sıcak kahveyi bulundurmayı ihmal etmedim. <img title="Cool" src="/editors/tiny_mce3/plugins/emotions/img/smiley-cool.gif" alt="Cool" border="0" /> Örnek senaryomuzda aynı <strong>servis sözleşmesini(Service Contract)</strong> implemente eden 3 farklı alt servisimiz bulunmaktadır. <strong>Router Service</strong>, istemciden gelen talebi alıp ne olduğu ile ilgilenmeden doğrudan bu 3 servise aktarma işlemini üstlenmektedir. Dolayısıyla ispat etmemiz gereken noktalardan birisi, istemciden gelen talebin sonrasında operasyonun 3 servis üzerinde de çalışıyor olmasıdır. <strong>OneWay</strong> veya <strong>Duplex</strong> kısıtlamasından dolayı biz örneğimizde <strong>OneWay</strong> olarak imzalanmış basit bir servis operasyonu kullanıyor olacağız. Öncelikle örneğimize ait mimari modelimize bir göz atalım.</p>
<p><img src="/pics/2009%2f8%2fblg75_Architecture.gif" alt="" /></p>
<p>Görüldüğü üzere sadece <strong>Endpoint</strong> tanımlamaları açısından farklı olan<em>(ve gerçek hayat senaryolarında istenirse farklı makinelerde bulunabilecek olan)</em> ama aynı sözleşmeyi uygulayan<strong> 3 Downstream</strong> servisimiz bulunmaktadır. Servislerimizin uyguladığı sözleşme aşağıdaki kod parçasında olduğu gibidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.ServiceModel;
using System.Runtime.Serialization;
namespace AdventureContracts
{
[ServiceContract(Namespace="http://adventure/productService")]
public interface IAdventureContract
{
[OperationContract(IsOneWay=true)]
void ProcessProduct(Product product);
}
[DataContract]
public class Product
{
[DataMember]
public int ProductId { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public double ListPrice { get; set; }
[DataMember]
public int Amount { get; set; }
}
}</pre>
<p>Servislerimizin üçünün kodlarını burada ayrı ayrı yazmamıza gerek olmadığını düşünüyorum. Nitekim hem odaklanmamız gereken nokta <strong>Router</strong> servis tarafıdır hemde yazımızın okunurluğunun zorlaşmaması gerekmektedir. Tabiki örneği indirip incelemenizi şiddetle öneririm. Gelelim yönlendirme servisimize. Yönlendirme servisimizin <strong>App.config</strong> dosyası içeriği aşağıdaki gibidir.</p>
<p><strong>Router Service konfigurasyon içeriği(App.config);</strong></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<routing routingTableName="RTable"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<client>
<endpoint address="net.tcp://localhost:60001/Adventure/BackendMirror/ProductService1" binding="netTcpBinding" contract="*" name="ProductServiceEndpoint1" />
<endpoint address="http://localhost:60002/Adventure/Backend/ProductService2" binding="wsHttpBinding" contract="*" name="ProductServiceEndpoint2"/>
<endpoint address="http://localhost:60003/Adventure/Internal/ProductService3" binding="wsHttpBinding" contract="*" name="ProductServiceEndpoint3" />
</client>
<services>
<service name="System.ServiceModel.Routing.RoutingService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:60005/Adventure/ProductService"/>
</baseAddresses>
</host>
<endpoint binding="wsHttpBinding" contract="System.ServiceModel.Routing.ISimplexSessionRouter"/>
</service>
</services>
<routing>
<filters>
<filter filterType="MatchAll" name="ProductFilter"/>
</filters>
<routingTables>
<table name="RTable">
<entries>
<add endpointName="ProductServiceEndpoint1" filterName="ProductFilter"/>
<add endpointName="ProductServiceEndpoint2" filterName="ProductFilter"/>
<add endpointName="ProductServiceEndpoint3" filterName="ProductFilter"/>
</entries>
</table>
</routingTables>
</routing>
</system.serviceModel>
</configuration></pre>
<p>Dikkat edileceği üzere <strong>fiterType</strong> niteliğine <strong>MatchAll</strong> değeri verilmiştir. Bu değere göre, istemciden gelecek olan <strong>talep(Request)</strong> <strong>name</strong> niteliğine atanan değere eş düşen <strong>endPoint</strong> noktalarına iletilmelidir ki bu bildirimlerde yine <strong>entries</strong> elementi içerisinde yapılmaktadır. <strong>entries</strong> elementi içerisindeki <strong>filterName</strong> niteliğinin değeri ile, <strong>filter</strong> elementi içerisindeki <strong>name</strong> niteliğinin değerlerinin aynı olduğuna lütfen dikkat edelim.</p>
<p>Konfigurasyon dosyasında önem arz eden noktalardan bir diğeride, yönlendirme servisi için kullanılan sözleşme tipidir<strong>(ISimplexSessionRouter)</strong>. Hatırlayacağınız gibi,<strong> Request/Reply</strong> modelin desteklenmediğinden bahsetmiştik. Bu nedenle daha önceki örneklerimizde kullandığımız <strong>IRequestRepyleRouter</strong> built-in sözleşme tipini bu senaryoda kullanamayız.</p>
<p>Örneğimizi test ettiğimizde çalışma zamanında aşağıdaki ekran görüntüsüne benzer sonuçları alırız.</p>
<p><img src="/pics/2009%2f8%2fblg75_Runtime.gif" alt="" /></p>
<p>Görüldüğü gibi tüm <strong>DownStream </strong>servisleri, istemciden gelen <strong>Product</strong> tipini ele almış ve basit bir şekilde kullanmıştır. Biz örneğimizde sadece gelen bilgiyi ekrana yazdırıyoruz. Aynı istemci paketinin, n sayıda <strong>DownStream </strong>servisi tarafından değerlendirilip üzerlerinde farklı şekillerde işlemler uygulanması söz konusu olduğunda, <strong>MatchAll</strong> filtereleme modelini göz önüne alabiliriz. Tabiki <strong>Request/Reply</strong> kısıtlamasını unutmamak gerekir. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://www.buraksenyurt.com/pics/2009%2f8%2fRouter+Project+3.rar">Router Project 3.rar (249,84 kb)</a></p>2009-09-13T21:00:00+00:00wcfwcf 4.0bsenyurtBundan önceki yazılarımızda WCF 4.0 için yönlendirme servislerinin(Router Service) nasıl yazılabileceğini incelemeye çalışmıştık. Fark edeceğiniz üzere yönlendirme servislerinin en önemli noktaları arasında filtreleme tablosu ve filtrelerin olduğunu gördük...https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=5603f061-828e-4988-ad42-378f1a82ec322https://www.buraksenyurt.com/trackback.axd?id=5603f061-828e-4988-ad42-378f1a82ec32https://www.buraksenyurt.com/post/WCF-40-Yenilikleri-Routing-Service-MatchAll-Filtresi#commenthttps://www.buraksenyurt.com/syndication.axd?post=5603f061-828e-4988-ad42-378f1a82ec32https://www.buraksenyurt.com/post/WCF-40-Yenilikleri-Routing-Service-Hata-YonetimiWCF 4.0 Yenilikleri - Routing Service - Hata Yönetimi [Beta 1]2009-09-09T13:02:00+00:00bsenyurt<p><img style="float: right;" src="/pics/2009%2f8%2fblg74_Giris.jpg" alt="" />Merhaba Arkadaşlar,</p>
<p>Bir önceki <a title="WCF 4.0 - Route Service Geliştirmek" href="https://www.buraksenyurt.com/post/WCF-40-Yenilikleri-Routing-Service-Gelistirmek-Hello-World" target="_blank">blog yazımızda </a><strong>WCF 4.0</strong> ile basit bir <strong>yönlendirme servisinin(Router Service) </strong>nasıl yazılabileceğini incelemeye çalışmıtık. Tabi bu tip bir sistemde dikkat edilmesi gereken vakalardan biriside, <strong>Downstream</strong> servislerde <strong>istisnaların(Exceptions)</strong> oluşması halinde nasıl davranılacağıdır. Peki ne gibi durumlardan bahsediyoruz? Örneğin, Router servisine gelen paketin yönlendirildiği bir alt servis çalışmıyor olabilir. </p>
<p>Bu durumda bir <strong>TimeoutException</strong> oluşması muhtemeldir. Benzer şekilde <strong>CommunicationException</strong> ve türevi olan istisna tiplerinin fırlatılmasıda söz konusudur. Bu gibi istisnaların ortaya çıkması halinde en azından işleyişin devamlılığını sağlamak ve sistemin çökmesini engellemek için, WCF 4.0 tarafı konfigurasyon dosyasında <strong>Alternatif Endpoint </strong>tanımlamaları yapılmasına izin vermektedir.</p>
<p>Buna göre <strong>Downstream</strong> servislerinden bahsedilen tipteki istisnalardan birisi alınırsa, istemciden gelen talebin karşılanmak üzere alternatif olarak tanımlanmış olan bir servise yönlendirilmesi sağlanmış olunur. Bu alternatif servise olan yönlendirme tamamen çalışma zamanında ve router servisin yönetimi altında gerçekleşmektedir. Konuyu daha net kavrayabilmek adına bir önceki blogumuzda yazdığımız örneği aşağıdaki vakaya göre test ettiğimizi düşünelim.</p>
<p>İlk etapta Router Servisimiz ile tüm DownStream servislerimiz çalıştırılır. Sonrasında istemci uygulama açıkken ve henüz taleplerini iletmeden önce Downstream servislerinden herhangibiri kapatılır. Örneğin <strong>UserService</strong> servisinin kapatıldığını düşünebiliriz. Bu durumda istemci tarafının bir <strong>CommunicationException</strong> istisnası ile sonlanması gerekmektedir.</p>
<p>Örneği kolay bir şekilde canlandırabilmek için Router servisimizde <strong>includeExceptionDetailInFaults</strong> özelliğine <strong>true</strong> değeri atayıp, istemci tarafındaki kod içeriğini ise aşağıdaki gibi güncelleştirmemiz yerinde olacaktır.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.ServiceModel;
using ClientApp.MemberManagementSpace;
namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("İstemci hazır...Başlamak için tuşa basınız");
Console.ReadLine();
try
{
MemberManagementServiceClient client = new MemberManagementServiceClient();
User burak = new User { Name = "Burak Selim Şenyurt" };
string registerResult = client.RegisterUser(burak);
Console.WriteLine(registerResult);
string updateResult = client.UpdateUserName(burak, "Burki");
Console.WriteLine(updateResult);
Console.ReadLine();
client.Close();
}
catch (CommunicationException excp)
{
Console.WriteLine(excp.Message);
}
}
}
}</pre>
<p>Test sonrasında aşağıdaki gibi bir sonuçla karşılaşmamız muhtemeldir. </p>
<p><img src="/pics/2009%2f8%2fblg74_Case.gif" alt="" /></p>
<p>Görüldüğü gibi <strong>RegisterService</strong> üzerinden yapılan kullanıcı kayıt operasyonu başarılı bir şekilde çalışmış ancak, <strong>UserService</strong> üzerinden yapılan çağrı için ortama bir <strong>CommunicationException</strong> döndürülmüştür. Bu son derece doğaldır, nitekim söz konusu servis kapalıdır. <img title="Sealed" src="/editors/tiny_mce3/plugins/emotions/img/smiley-sealed.gif" alt="Sealed" border="0" /> Peki alternatif bir yolumuz var mıdır? Yazımızın başındada belirttiğimiz gibi, <strong>Downstream</strong> servislerinden birisinin çökmesi halinde en azından istemci talebinin bir başka yedek servis üzerine pas edilmesi sağlanabilir. İlk önce bu <strong>yedek servisi(Backup Service)</strong> geliştireceğiz. Sonrasında ise, <strong>Router</strong> servisimize ait konfigurasyon dosyasında bazı değişiklikler yapmamız gerekmektedir. Örneğimizin yeni modeli grafiksel olarak aşağıdaki gibi düşünülebilir.</p>
<p><img src="/pics/2009%2f8%2fblg74_Architecture.gif" alt="" /></p>
<p><strong>UserBackupService</strong> isimli yedek servisimizin konfigurasyon dosyası ve kod yapısı aşağıdaki gibidir.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="UserBackupService.UserService">
<endpoint address="" binding="wsHttpBinding" contract="ContractLibrary.IManagementContract" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:3446/UserBackupService" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration></pre>
<p>ve kod içeriği;</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using ContractLibrary;
using System.ServiceModel;
namespace UserBackupService
{
class UserService
: IManagementContract
{
public string RegisterUser(User newUser)
{
throw new NotImplementedException();
}
public string UpdateUserName(User oldUser, string newName)
{
Console.WriteLine("UpdateUserName metodu başlatıldı...");
return String.Format("{0} isimli kullanıcı adı {1} olarak değiştirildi", oldUser.Name, newName);
}
public UserService()
{
Console.WriteLine("UserBACKUPService nesnesi örneklendi");
}
}
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(UserService));
host.Open();
Console.WriteLine("UserBACKUPService hazır...");
Console.ReadLine();
host.Close();
}
}
}</pre>
<p>Aslında <strong>UserService'</strong> in bire bir kopyası olan sadece farklı bir port üzerinden sunulan bir servis geliştirmiş bulunuyoruz. Elbetteki bu servisi farklı bir makine üzerinde farklı <strong>Endpoint</strong> kuralları ilede sunabilir ve alternatif Endpoint olarak kullanabiliriz. Gelelim bu yazının en can alıcı noktasına. Router servisine ait konfigurasyon dosyasının içeriği...<img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<routing routingTableName="RTable"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<client>
<endpoint address="http://localhost:3445/UserService" binding="wsHttpBinding" contract="*" name="UserServiceEndpoint" />
<endpoint address="http://localhost:3446/UserBackupService" binding="wsHttpBinding" contract="*" name="UserBackupServiceEndpoint"/>
<endpoint address="net.tcp://localhost:4001/RegisterService" binding="netTcpBinding" contract="*" name="RegisterServiceEndpoint" />
</client>
<services>
<service name="System.ServiceModel.Routing.RoutingService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:6501/User/Management/RouterService"/>
</baseAddresses>
</host>
<endpoint binding="basicHttpBinding" contract="System.ServiceModel.Routing.IRequestReplyRouter"/>
</service>
</services>
<routing>
<filters>
<filter name="RegisterFilter" filterType="Action" filterData="http://www.azon.com/Registration"/>
<filter name="UpdateUserFilter" filterType="Action" filterData="http://www.azon.com/UpdateUser"/>
</filters>
<routingTables>
<table name="RTable">
<entries>
<add filterName="RegisterFilter" endpointName="RegisterServiceEndpoint"/>
<add filterName="UpdateUserFilter" endpointName="UserServiceEndpoint" alternateEndpoints="alternateEndpointList"/>
</entries>
</table>
</routingTables>
<alternateEndpoints>
<list name="alternateEndpointList">
<endpoints>
<add endpointName="UserBackupServiceEndpoint"/>
</endpoints>
</list>
</alternateEndpoints>
</routing>
</system.serviceModel>
</configuration></pre>
<p>İlk etapta, <strong>Backup</strong> servisi içinde bir <strong>Endpoint</strong> bildirimi yapıldığı ve yedek servisin işaret edildiği farkedilmektedir. Diğer yandan <strong>routingTables </strong>içerisinde yapılan <strong>entries</strong> bildirimlerinden <strong>UpdateUserFilter</strong> isimli olanında <strong>alternateEndpoints</strong> isimli bir <strong>nitelik(attribute)</strong> dikkati çekmektedir. Bu nitelik, dosyanın ilerleyen kısımlarında yer alan <strong>alternateEndpoints</strong> elementi altındaki listeyi işaret etmektedir.</p>
<p>Bu liste içerisinde <strong>n</strong> sayıda alternatif <strong>endPoint</strong> ismi belirtilebilir. Bir başka deyişle bir <strong>endPoint'</strong> in karşılayamadığı istekleri, birden fazla <strong>endPoint</strong> noktasına denenmek üzere aktarabiliriz. Tabi bu durumu henüz test etme şansım olmadı. Ki beklenen sırasıyla servislerin denenmesi ve başarılı olandan sonrakilere geçilmemesi yönünde olmalıdır. Ancak entries/add elementi içerisinde priority isimli bir nitelikte bulunmakta ve öncelik seviyesini belirlemektedir. İşte size bir garajda araştırma ödevi.<img title="Cool" src="/editors/tiny_mce3/plugins/emotions/img/smiley-cool.gif" alt="Cool" border="0" /> </p>
<p>Artık vakamızı tekrardan test edebiliriz. Yine tüm servisleri(Backup servisimiz dahil) çalıştıracak, ancak istemci talepte bulunmadan önce <strong>UserService'</strong> ini <span style="text-decoration: underline;">kapatacağız</span>. İşte sonuçlar;</p>
<p><img src="/pics/2009%2f8%2fblg74_Result.gif" alt="" /></p>
<p>Görüldüğü gibi, <strong>UserService'</strong> in kapalı olması ve <strong>Exception</strong> üretmesi durumunda, <strong>Router</strong> servisimiz talebi bu kez alternatif <strong>endPoint</strong> listesinde belirtilen UserBackupService isimli yedek servise doğru yönlendirmiş ve istemcinin talebinin buradan karşılanmasını sağlamıştır. Tabiki burada ele alınan <strong>alternatif Endpoint' </strong>lerin işaret ettiği servisler farklı makinelereden, farklı <strong>bağlayıcı tiplerle(Binding Types)</strong>, farklı iletişim protokolleri ile dağıtılabilir. Bu tamamen yedek servis stratejimize bağlıdır. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://www.buraksenyurt.com/pics/2009%2f8%2fRouter+Project+2.rar">Router Project 2.rar (128,25 kb)</a></p>2009-09-09T13:02:00+00:00wcfwcf 4.0bsenyurtBir önceki blog yazımızda WCF 4.0 ile basit bir yönlendirme servisinin(Router Service) nasıl yazılabileceğini incelemeye çalışmıtık. Tabi bu tip bir sistemde dikkat edilmesi gereken vakalardan biriside, Downstream servislerde istisnaların(Exceptions) oluşması halinde nasıl davranılacağıdır.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=351c09b0-7bf9-4d6e-adc1-bed582f939cf1https://www.buraksenyurt.com/trackback.axd?id=351c09b0-7bf9-4d6e-adc1-bed582f939cfhttps://www.buraksenyurt.com/post/WCF-40-Yenilikleri-Routing-Service-Hata-Yonetimi#commenthttps://www.buraksenyurt.com/syndication.axd?post=351c09b0-7bf9-4d6e-adc1-bed582f939cf