6 Haziran 2009

Silverlight ile bir WCF Servisi ve Cross Domain Access

Merhaba,
Bu yazımda bir Silverlight 2 uygulamasında, client taraf ile ASP .NET tarafı arasında veri alışverişini sağlayacak uygulama geliştirmek istediğimizde karşımıza çıkması muhtemel olan Cross Domain Restrictions (çapraz etki alanı kısıtlamaları) olayını 2 farklı yöntemle aşmaya çalışacağız.

Resim: Cross-domain erişim yapısı.

Cross Domain Restrictions’dan kısaca bahsetmek gerekirse; bir güvenlik önlemi olarak, Silverlight kendi çalışma alanı (domain) sınırları dışında çalışma izni vermemektedir.

Bu yazımızdaki örneğimizde kendi local bilgisayarımızda oluşturacağımız iki farklı domain ile konuyu ele alacağız.
Cross Domain hatasını elde edebilmek için bir WCF servisi kullanacağız. Farklı domain elde edebilmek için ise bilgisayarımızın wwwroot dizinine test isminde bir dizine domain oluşturacağız.

1. domain : http://localhost:1283 (prolemizin debug modda çalıştığı durum)
2. domain : http://localhost/test (uygulamayı publish ettiğimiz yer)

Amacımız, Silverlight uygulamamızın localhost/test etki alanından, localhost:1283'de bulunan servise erişmeye çalışmak olacak.

ASP.NET tarafında bize veri iletimini sağlaması amacıyla bir Silverlight-enabled WCF Service oluşturalım.

Solution Explorer üzerinde resimdeki gibi bir Silverlight uygulaması üzerinde çalıştığımızı varsayalım.
Server taraftaki (ASP.NET tarafı) SilverWebServiceTestProj.Web projesi üzerine sağ tıklayarak Add New Item penceresinden Silverlight-enabled WCF Service ekleyelim.

Hemen ardından web servisimize artık gelenekselleşmiş olan, standart mesajımız “Hello World” mesajını ekliyoruz. Buradaki amacımız WCF servis yapısını anlatmak olmadığından bu kısımları hızlıca geçiyoruz.
[OperationContract]
public string HelloWorld()
{
return "Hello World";
}

Uygulamamızın Client tarafına ServiceReferance isimli WCF servis referansımızı ekleyelim. ServiceReferance.ClientConfig isimli configurasyon dosyası da projemize eklenecektir.

ServiceReferance.ClientConfig dosyasının içeriğine göz atalım. Endpoint address’in localhost 1283 no’lu port dan çalışacak şekilde otomatik olarak yazıldığı görülecektir.




Şimdi de Page.xaml.cs içine yazacağımız c# kodlarını oluşturalım. Page loaded event’ı çalıştığında ekrana “Hello World” mesajımızı yazdıracağız.

public partial class Page : UserControl
{
private ServiceReferance.Service1Client myService = null;
public Page()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Page_Loaded);
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
myService = new SilverWebServiceTestProj.ServiceReferance.Service1Client();
myService.HelloWorldCompleted += myService_HelloWorldCompleted;
myService.HelloWorldAsync();
}
private void myService_HelloWorldCompleted(object sender, SilverWebServiceTestProj.ServiceReferance.HelloWorldCompletedEventArgs e)
{
if (e.Error == null)
{
MessageBox.Show(e.Result);
}
else {

MessageBox.Show(e.Error.Message);
}
} }

Page.xaml’a hiçbir kod satırı eklemeden F5 ile debug modda projemizi derleyip çalıştırdığımızda herhangi bir hata ile karşılaşmadan “Hello World” mesajı ile karşılaşacağız.
Şimdi uygulamamızı faklı bir etki alanına (localhost/test) publish edelim ve localhost:1283 adresinde bulunan WCF servisimize erişmeye çalışalım.


ASP .NET projemize sağ tıklayarak Publish seçeneğini seçelim. Local makinemizde oluşturacağımız test isimli dizine publish ediyoruz. (wwwroot/test)

Publish işlemi tamamlandıktan sonra yeni bir browser açarak uygulamızı çalıştıralım.
Uygulama adresini yazıp çalıştırdığımızda aşağıdaki cross domain hatası ile karşılaşacağız.

Alınan Hata Mesajı: "An error occured while tyring to make a request to URI http: //localhost:1283/Service1.svc. This could be due to attemting to access a service in a cross-domain way without a proper cross domain policy in place, ..." şeklinde uzayıp giden bir hata mesajı.
Yukarıdaki hatayı almamızın sebebi, localhost/test etki alanından, localhost:1283 etki alanında bulunan WCF servisine erişmeye çalışmamızdır. Bu hatayı almamız son derece normal.

Buradaki hatayı almamak için 2 farklı yöntem ele alacağız.
İlk yöntemimiz de erişmeye çalışacağımız etki alanının çağrımıza izin vermesi. Bunun için Server taraftaki projemize clientaccesspolicy.xml isimli dosyayı ekleyelim. İçeriğini aşağıdaki gibi hazırlayalım.

clientaccesspolicy.xml












İstemciden gelen bir çağrı durumunda, clientaccesspolicy.xml dosyası eğer var ise, bu dosyadaki içeriğe göre gelen çağrıya izin verilir ya da verilmez. Clientaccesspolicy.xml dosyasını özelleştirerek yalnızca belirli alan adlarının erişmesini de sağlayabiliriz. Bu dosya hakkındaki detay bilgilere buradan erişilebilir.














İkinci yöntemimiz, client uygulamamızın çağrıda bulunmadan önce erişmek isteyeceğimiz WCF servisin etki alanını önceden bilmesi durumudur. Öncelikle bu etki alanını elde edip yeni bir http binding oluşturacağız ve ardından servis referansımızı da yeniden oluşturup çağrıda bulunacağız.

Ele alacağımız örneğimizde farklı bir domain'e geçmeden içinde bulunduğumuz domain'i konrol ederek kendi domain yapımız içinde yer alan servise erişmiş olalım. Böylelikle uygulamamız içinde kullandığımız servisleri her hangi bir IIS' e publish ederken de farklı bir domain de olup olmaması gibi bir problemle de karşılaşmayız.
Aşağıdaki örnek c# kodunu farklı domain'de bulunan bir servis için de gerçekleştirebiliriz.
Artık sözü c#'a bırakalım.
public partial class Page : UserControl
{
private ServiceReferance.Service1Client myService = null;
public Page()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Page_Loaded);
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{

int lastIndex = HtmlPage.Document.DocumentUri.AbsoluteUri.LastIndexOf("/");
string basePath = HtmlPage.Document.DocumentUri.AbsoluteUri.Substring(0, lastIndex);
string serviceAddress = string.Concat(basePath, "/Service1.svc");

myService =
new SilverWebServiceTestProj.ServiceReferance.Service1Client(new BasicHttpBinding(),
new EndpointAddress(serviceAddress));
myService.HelloWorldCompleted += myService_HelloWorldCompleted;
myService.HelloWorldAsync();
}
private void myService_HelloWorldCompleted(object sender, SilverWebServiceTestProj.ServiceReferance.HelloWorldCompletedEventArgs e)
{
if (e.Error == null)
{
MessageBox.Show(e.Result);
}
else {
MessageBox.Show(e.Error.Message);
} } }
Kolay gelsin.
Kaynak:

29 Mayıs 2009

29 Mayıs 2009 Cuma Başlangıç

Merhabalar,

Uzunca süre blog ya da benzeri kişisel web sitelerinden uzak kaldığımı farkettim. Bilgi paylaşımına bir yandan da web ortamından (buradan) devam edeceğim.

Bu bloğumda bilgisayar yazılımı ağırlıklı olmak üzere, buradan paylaşmaya değer bulduğum tüm konuları zaman buldukça aktaracağım.
Görüşmek üzere...