Makale Özeti

İlk kez Aralık 2007'de görücüye çıkan resmî ASP.NET MVC kütüphanesinin, her zamanki ASP.NET deneyimimizde neler değiştirdiğini konuşuyoruz.

Makale

Web programlamaya bakışın zaman içerisindeki gelişimi, bu sahadaki ürünlerin de sürekli güncellenmesine neden olurken, yükselmiş sürümler kullanıcılara alternatif yollar açıyor. Çünkü eldeki ürün ne olursa olsun, ne kadar gelişmiş olursa olsun; bir vakit geliyor çıkmaza giriliyor. İşte o anda yeni fikirler türüyor, yeni bakış açıları doğuyor. Model-view-controller de bunlardan birisi.

Model-View-Controller (kısaca MVC), genelde web uygulamalarına tatbik edilen bir mimari kalıp. Bu kalıbın farkını ortaya koymak için öncelikle ASP ve ASP.NET’in kullandığı klasik mimariye bir bakalım.

Geleneksel Usul

Geleneksel web programlamada, kullanıcı istekleri fiziksel olarak diskte yer alan ASP.NET sayfaları (.aspx) tarafından ele alınıp işleniyor. Bu sayfanın ürettiği metin çıktı (HTML) da talep eden noktaya yanıt olarak gönderiliyor.

URL > Sayfa (.aspx)

İş mantığı ise, bu sayfaların ardına konuşlandırılıyor. ASP uygulamalarında iş mantığı ile görsel kodlar bir arada iken ASP.NET’in “Code-Behind” özelliği bu iki kodu birbirinden yalıtmayı mümkün kıldı. Ancak paragrafın ilk yargısı hâlâ geçerli: iş mantığı, görsel unsurlar olan sayfalarla sıkı bir ilişki içerisinde. Gelen isteği ele alan, değerlendiren ve sunucu işlevlerini çalıştıran, tetikleyen mekanizma web sayfasının üzerine kurulu durumda.

Geleneksel usüle itiraz da mimari noktada başladı. İstekleri ele alan unsurların görsel unsurlar olması ve iş mantığını tetiklemesi yerine; görsel unsurların oldukça kabiliyetsiz, basit ve yalın olması gerektiği düşünüldü... ve MVC ortaya çıktı.

MVC Usulü

Bu yaklaşımda isteğin temel parçalarından olan URL, sunucu diskindeki fiziksel bir sayfayı değil, bir işlem başlatacak eylemi işaret ediyor:

URL > Eylem (Controller)

MVC literatüründe eylemler, Controller denen yapılarda tanımlanıyor. Kullanıcı etkileşiminden ve bu etkileşimle tetiklenecek tüm sunucu taraflı görevlerden Controller sorumlu. Tekrar edersek, gelen istek bir görsel sayfa tarafından değil, özel yazılmış ve Controller adı verilen bileşenler tarafından karşılanıyor ve işleniyor.

Model (tanım) ise en açık ifadeyle “veri”yi karşılıyor. Uygulamanın üzerinde çalıştığı ve kalıcılaştırdığı verinin temsili model katmanında gerçekleştiriliyor.

View istemciye dönecek yanıtın biçimlendiği katman. Bu biçimleme mekanizması, model’den ve controller’den bağımsız olduğu için oldukça esnek.

Bu kavramlarla aslında MVC’nin üç katmanlı bir yapı önerdiğini de vurgulamış olduk. Geleneksel usulün web sayfası merkezli yapısına karşın burada controller merkezli bir yapı görüyoruz.

Katmanlı yapıyı şöyle şematize edebiliriz:

http://www.pnp-software.com/eodisp/images/mvc-original.png (*)

Geleneksel Sıkıntılar

ASP.NET bünyesinde, MVC usulünde uygulama geliştirmek için hazır bir destek 2008’e kadar bulunmuyordu. Ancak programcılar geleneksel web uygulamalarında yaşadıkları sıkıntılardan dolayı sürekli arayış içerisinde oldular. Nedir peki geleneksel sıkıntıların kaynağı?

·         Web Formları, hızlı uygulama geliştirme (RAD) gayesiyle tasarlanmış bir alt sistem. Visual Basic formlarının web üzerine tatbik edilmiş hâli diyebiliriz. Aynen VB deneyiminde olduğu gibi, tuşların arkasına yazılan kodlar ve size tepki veren sayfalar (ekranlar). Kısaca, kullanıcıyla etkileşimi en hızlı biçimde kurup istediği sonucu verme fikri üzerine kurulmuş. Bu yaklaşım, görsel unsur ile iş mantığı kodlarının hâlâ iç içe olması demek oluyor. “Code-Behind” sadece fiziksel bir ayrım sağlıyor. Ama mantıksal bağımlılık devam ediyor.

·         Web Formları, gerçeklediği olay-güdümlü mekanizmayı ViewState adlı form elemanı üzerine kurmuş durumda. Bu özel eleman, sayfaya eklenmiş kontroller arttıkça inanılmaz boyutlarda büyüyor ve istemci-sunucu arası geliş gidişlerdeki yükü artırıyor. Kapatılması mümkün olan bu özelliğin eksikliği de öntanımlı olarak beklenen birçok davranışı da pasifleştiriyor.

·         ASP.NET için yazılan kontroller ve tüm sayfa, programcının idare edemeyeceği karmaşıklıkta HTML çıktısı üretiyor ve bunlardan kurtulmak bu mimaride mümkün değil. Kimi zaman mümkün olsa bile bu da kısıtlı düzeyde olabiliyor.

·         Bir diğer sıkıntı konusu da görsel çıktıyı üretirken Page Life Cycle - sayfa hayat çevrimine mahkum olmak. Meselâ Page sınıfı olmadan, Control sınıfı olmadan çalışabilmeyi kastediyoruz.

·         Her türlü isteği sayfaların karşılaması, Web Formlarının test edilmesini de güçleştiriyor. Oysa ki programcılar, iş mantığını test etmek istiyor. Görsel katmanın ve iş katmanının sıkı bağlılığı işte burada can yakıyor.

Bu sıkıntıların en güzel tarafı, diğer web programlama ürünlerinde denenmiş olan MVC mimarisinin ASP.NET’e taşınmasına öncülük etmesi oldu. Şimdi ASP.NET ve MVC ilişkisinin serüvenini paylaşalım.

ASP.NET – MVC Buluşması

MVC mimarisinde ASP.NET uygulamaları geliştirme fikri henüz çok yeni. Özel HttpHandler yazma yöntemleriyle MVC’ye yakın gerçekleştirimler yapılageldiyse de tam anlamıyla MVC motoru Castle projesinin bir ayağı olarak 2006’da MonoRail adıyla yayımlandı.

MonoRail, henüz emekleme aşamalarındayken ve kararlı bir yapıya ulaşmamışken, konuyla ilgili Microsoft’un en yetkili ağzı ASP.NET için MVC Framework’ünün geliştirildiği ilân etti [http://weblogs.asp.net/scottgu/archive/2007/10/14/asp-net-mvc-framework.aspx, 14 Ekim 2007]. Bu haber, web formları kalıbının dışına çıkmak isteyen tüm geliştiriciler tarafından memnuniyetle karşılandı ve ilk sürümün beklentisi başladı.

9 Aralık 2007’de ASP.NET MVC Framework eklentisi, “ASP.NET 3.5 Extensions Preview” başlıklı, bir takım güncellemeler içeren paketle birlikte geliştiricilerin kullanımına sunuldu. Sunulan eklenti, adından da anlaşılacağı gibi ASP.NET motoruna kattığı ilâvelerle, zahmetsizce MVC tarzı uygulamalar yazmayı mümkün kılıyor. Bu sürüm kararlı değil elbette, sadece bir önizleme. Buna rağmen temel özelliklerin sunulduğu bir paket.

Son haberlere göre, MVC eklentisinin MIX08 etkinliği için yeni bir önizleme sürümü çıkacak. Herkesin indirebileceği bu sürümde bir öncekine göre hayli fazla gelişme mevcut. Yeri geldiğinde değineceğiz.

Şimdi isterseniz MVC eklentisinin web programlama deneyimimize ne katacağını, neleri değiştireceğini adım adım görelim. Yazımız bundan sonrasında, çalışabilir bir örnek uygulama geliştireceğiz ve teorik olarak sarfettiğimiz cümlelerin pratiğe yansımasını göreceğiz.

Nereden Başlayacağız?

Geliştirme ortamımız için aşağıdaki uygulamalar gerekiyor:

·         Visual Web Developer 2008 Express veya Visual Studio 2008

·         ASP.NET 3.5 Extensions Preview (İndirebilirsiniz)

Geliştirme aracı olarak, bedava dağıtılan Visual Web Developer 2008 Express sürümü işimizi göreceği için yazımızda onu baz alacağız.

Visual Web Developer 2008 ile standart ASP.NET uygulamaları geliştirebiliyorduk. Yüklemiş olduğumuz eklenti paketi, Visual Web Developer’e yeni proje tipleri ekliyor. Bunun yanında gerekli assembly’leri de Global Assembly Cache’e alarak çalışacağımız MVC ortamını hazırlıyor.

Yeni Bir Proje

“New Web Site” ekranında, öncekilerden farklı olarak -gözümüze çarpan- eklentili siteyi seçiyoruz:

Başlangıç için oluşan proje ağacımız şöyle:

Bu iki dosyalı projede öncekilerden farklı olan nedir? Fark, web.config’te mahfuz duruyor. Web.config dosyasını incelediğinizde birçok ilâve göreceksiniz. Bunların hepsi MVC ile ilgili değil elbette. Eklenti paketinden çıkan AJAX, SilverLight, Dynamic Data eklentilerini de kapsıyor.

MVC ile ilgili olan kısım işte tam şurası:

Bu kısımda, UrlRoutingModule adlı bir HttpModule bileşeni ASP.NET motoruna kaydediliyor. ASP.NET mimarisinde HTTP modülleri, istek boyunca çalışan bileşenler demek. Sistemin birçok bünyesel özelliği, yazılan gömülü modüllerle sağlanıyor: örneğin Session State (oturum vaziyeti) modülü.

UrlRoutingModule, adıyla işini ifşa eden modüllerden. Yazımızın ilk kısımlarında bahsettiğimiz, isteklerin Controller katmanı tarafından karşılanmasını temin ediyor. Basit bir ifadeyle, gelmiş isteğin URL’ini inceliyor ve Routing kurallarıyla bağdaştırabilirse ilgili Controller’i ayağa kaldırıyor; yok bir şey bulamazsa yapacak tek iş uygun hatayı vermek.

Peki kalın harflerle vurguladığımız Routing kuralları nasıl tanımlanır?

URL Yönlendirme Kuralları

URL yönlendirme kurallarının, System.Web.Mvc’nin RouteTable sınıfına eklenmesi gerekiyor. MVC Framework, şu an için sadece programatik eklemeyi mümkün kılmış. Beklentiler, bir sonraki sürümde bu kuralların bildirimsel yolla da (web.config’ten) verilebilmesi istikametinde.

Bu yönlendirme tablosuna kuralları eklemek için en uygun zaman, uygulamanın başladığı an. Bu da global.asax’tan Application - Start “olay”ını yakalayacağız demek. Projeye bir Global Application Class ekleyerek kodunu aşağıdaki şekle getirelim:

C# 3.0’ın Anonim Tipler denen özelliğini ve sözdizimsel şekerlerinden birini (nesne hazırlayıcı) gördüğümüz bu kod parçasında iki yönlendirme kuralı ekliyoruz.

Url özelliği, istek yapılan URL’in kök adresten sonraki bizi ilgilendiren kısmı için yazdığımız deseni ifade ediyor. İlk kuralda, [controller]/[action]/[id] şeklinde parametrik bir desen verilirken ikincisinde sadece Default.aspx kalıcı olarak tanımlanmış. İlk kuraldan anlaşılacağı gibi URL’leri “/” (taksim) ile anlamlı parçalara ayırıyoruz ve hangi parçanın ne anlama geldiğini de burada belirliyoruz. İlk parça “controller” olacak, ikinci parça “action” ve üçüncü de “id”. Eğer “Default.aspx” gelirse de saydığımız üç değeri varsaydığımız değerlerle değiştireceğiz. (“Default.aspx” için ayrı tanım yapmamızın nedeni, web sunucunun kök dizine (“/”) gelen istekler için otomatik olarak Default.aspx araması. Bundan dolayıdır ki projemizdeki “default.aspx” dosyasını da muhafaza ettik. Eğer bu dosya olmasa, kök dizin istendiğinde sayfa bulunamadı hatası (404) oluşur.)

Kuralın Defaults kısmına URL’de tanımladığımız parametrelere karşılık gelen özelliklerle anonim bir tip veriyoruz. İlk kuralda, “action” parçası hiç verilmemişse varsayılan değerimiz “Index”; “id” verilmemişse “null”.

RouteHandler ise bileşenlerine ayrılmış ve işlenmiş URL’nin hangi Handler tarafından kontol edileceğini belirliyor. Her isteği MVC isteği olarak kabul etmeyebiliriz. MVC dışı istekler için ilgili Handler’i buraya vermemiz gerekiyor.

Gelin bu kuralların hangi URL’ler için ne değerler ürettiğini örnekleyelim:

URL

controller

action

id

/makale

Makale

Index

(null)

/

Home

Index

(null)

/makale/duzenle/1

Makale

Duzenle

1

/makale/liste

Makale

liste

(null)

/home

Home

Index

(null)

/home/about

Home

About

(null)

Bu değerler, bu isimde Controller’ler olduğunu ve bu bileşenlerde Index, Duzenle, vs. gibi action’lar bulunduğunu garantilemiyor. Sistem bu bilgilerle doğru eylemi çalıştırmak üzere işe koyuluyor.

Bu demek oluyor ki bizim buradaki istekleri karşılayan Controller’leri ve Action’ları yazmamız lazım.

Controller Yazıyoruz

Controller ismi MVC literatüründen geliyor. Bizim için bir sınıf (class) yazmaktan fazlası değil. Sınıfı yazmak için projede App_Code özel klasörünü ekleyip, içine MVC âdeti olduğu üzere ilk kontrolörümüzü ekleylim: HomeController.cs.

Sınıfımızın kodu da şu şekilde olsun:

Dikkat etmemiz gereken noktaları işaretlerle belirttik. İlki en yukarı eklediğimiz System.Web.Mvc isim uzayı. Bu uzayın mensubu Controller adlı bir sınıf da bizim için ata sınıf olmuş. MVC Framework’ünde, tüm kontrolör sınıfların bu sınıftan türemesi gerekiyor.

Sınıf bünyesinde Index ve About metodları, üstlerindeki ControllerAction niteliğiyle farkediliyor. Bu nitelik de onların birer “eylem” (action) olduğunu bildiriyor. Gövdelerinde sadece birer satırlık kod var ve tahmin edebileceğiniz üzere, kullanıcıya verilen isimde bir “view” üretip gönderiyor.

Neden bu sınıfın adı HomeController? Çünkü sistem kontrolör adından sonra Controller ifadesiyle eşleştiriyor URL’i. İsim eşleme üzerine kurulduğu için böyle.

Sabredin. Ürünü görmeye az kaldı: bir katmancık daha. RenderView’e (Controller sınıfından gelen bir metod) parametre olarak verilen görünümleri tanımlamaya geldi sıra.

View ya da Vitrin

MVC mimarisinde Controller katmanı, kullanıcıya çıktılanacak üründen tümüyle habersiz. Bu meseleyle ilgisiz. Çünkü bu mevzu “View” katmanının himayesinde.

“View” katmanı, görev kendisine emanet edildiğinde uzmanlık olanı olan görsel ürünü çıkartmakla yükümlü. Projemize, “index” ve “about” komutları verdiğimizde görüntülenecek “view” birimlerini ekleyeceğiz şimdi.

“View”ları eklemek için özel bir dizin adı gerekiyor: Views. Bu gerekli mi; şimdilik evet. Neden olduğunu ispatlamak için f5’e basmanız yeterli:

Hadi bekleneni yapalım. (“Home” klasörünün adının da Controller ile ilişkili olduğuna dikkatinizi çekerim.)

İki “view”in kodu da şu şekilde:

İki sayfa da ViewPage’den türemiş. Bu da bir zorunluluk. Öntanımlı “view” motoru, sadece ASP.NET sayfalarını (web formları) kullanıyor ve bu sayfaların ViewPage’den türemiş olduğunu farzediyor. Sevindirici haber şu ki bir sonraki MVC sürümünde dört farklı görünüm motoru seçeneği sunulacak.

Sayfada dikkatinizi çekeceğimiz bir nokta da bağlantının URL’i. Uzantı kullanmadan, home/about şeklinde bir ifadeyle, Home kontrolörün About eylemine işaret ediyoruz hyperlink’imizi.

Artık yaptığımız işin semeresini internet tarayıcıda görmenin vaktidir.

İşte Netice

Projeyi bu hâliyle derleyip çalıştırırsak, tarayıcımızda ASP.NET MVC Framework’ü üzerinden sunulmuş sitenin görüntülendiğine şahit oluruz:

Bu basit görüntü için bunca zahmete değer miydi?

Burada gösterdiğimiz MVC’nin isteği ne tarzda ele aldığını açıklayan bir örnekti. Bu fikri benimsedikten sonra, web uygulama geliştirme mantalitetinizi MVC’ye uyarlamanız ve uygulama mimarisini katmanlara bölerek, görünümü son noktaya koymanız gerekiyor.

MVC ile geliştirme konforu, CodePlex adresindeki MvcToolkit ve MvcContrib projeleriyle hızla ilerliyor. Arada üzerinden geçtiğimiz kısıtlanmış kurallar, bu geliştirmelerle beraber esniyor ve yapı daha güçlü hâle geliyor. Karmaşık ve büyük çaptaki uygulamaların da arkasında durabilecek düzeye gelmesine az kaldığını söyleyebiliriz.

ASP.NET MVC’nin Geleceği

Bu eklenti, web formları mimarisini geliştiricilerin önündeki tek seçenek olmaktan çıkarmak için geliştirilmiş. İşin başındaki kişilerin beyanına göre, MVC hiçbir zaman Web Formlarının yerini almayacak; sadece bir tercih / yol olacak. İsteyen uygulamasını web formları ile geliştirirken isteyen MVC mimarisine yönelecek. MVC mimarisine yönelen kişi, görünüm katmanında ister web formları ister Nvelocity ister Brail ister NHaml ya da bir başkasının yazacağı bambaşka bir görünüm motorunu tercih edebilecek. Seçebilme özgürlüğü gibisi yok.

Klasik web formu mimarisinin dışına çıkabildiği için ASP.NET MVC, bir takım istemci taraflı kütüphanelerle de daha arkadaşça çalışabilecek. Meselâ Jquery ile MVC birlikteliği şimdiden popülerleşmeye başladı.

Test yönelimli geliştirme de son dönemlerde önemini oldukça artırdı.ASP.NET MVC, bu konu da akılda tutularak geliştirildi ve mimari olarak birim testlerin kolayca uygulanabileceği yapıda.

Gelecek sürümde ASP.NET MVC’yi biraz daha olgunlaşmış göreceğiz. Kısaca geleceği parlak ve ona katkı verecek, kullanım deneyimlerini ilerletecek geliştiricilerin katılımını bekliyor.

Aşağıdaki kaynakları da ileri okumalar için istifadenize sunuyoruz:

·         ASP.NET MVC’ye Katkı Projesi: http://www.codeplex.com/MVCContrib

·         Türkçe ASP.NET MVC makaleleri: http://www.evcil.net/tag/mvc

·         Scott Guthrie’nin MVC makaleleri: http://weblogs.asp.net/scottgu/archive/tags/MVC/default.aspx

·         Dino Esposito’dan MVC’nin mimari kritiği: http://dotnetslackers.com/articles/aspnet/AnArchitecturalViewOfTheASPNETMVCFramework.aspx

·         Phil Haack’ten ASP.NET MVC’nin test-yönelimli tarafı: http://haacked.com/archive/2007/12/07/tdd-and-dependency-injection-with-asp.net-mvc.aspx

Kolay gelsin.

Örnek MVC Projesi