MVC 4.0 URL Routing Yapısı
Önceki yazılarımda yapısal olarak URL Routing(URL Yönlendirme) sistemine değinmiştim.Bu yazımda ise, farklı özellikleriyle, Asp.NET MVC 4.0 mimarisine uygun bir biçimde URL Routing yapısını irdeleyeceğiz.
Bu makalede, terminolojik terimlerin lugattaki bildiğimiz isimlerinden ziyade açıklamalarını yaparak konuya giriş yapmak istiyorum.
URL Nedir?
Web sayfalarına ulaşabilmek için, serverdaki fiziki dosyasının yolunun yapısallaştırılmış biçimidir.
Aşağıdaki URL yapısını inceleyiniz.
http://www.domainadi.com/Belgeler/Dokuman.aspx?ID=2
Yukarıdaki URL yapısını incelediğinizde, web sitesinin bulunduğu serverdaki dosyanın, fiziki yolunu çok rahat bir şekilde görmekteyiz.
Bir web projesinde URL yapılarının içeriğe uygun, anlamlı ve kullanıcılar tarafından okunabiliyor olmasına özen gösterilmelidir.
Bu şart SEO prensiplerinin temel kurallarındandır.Arama motorları optimizisyonu sırasında okunabilir URL yapıları, sitenizi üst sıralara çıkaracaktır.
URL Routing sistemi sayesinde, yukarıda örneklendirdiğimiz URL yapısı aşağıdaki gibi okunaklı hale getirilip SEO tabanlı link sistemi kurmamızı sağlamaktadır.
http://www.domainadi.com/Belgeler/Dokuman/2
O halde şimdi Routing kelimesini açıklayalım.
Routing(Yönlendirme) Nedir?
Yapısal olarak farklı olan URL kaynaklarını birleştiren bir sistemdir diyebiliriz.Örnek olarak aşağıdaki iki farklı URL yi inceleyiniz.
Standart URL | URL Routing ile Yönlendirilmiş URL |
http://www.bilmemne.com/yazilar/yazi.aspx?id=2 | http://www.bilmemne.com/yazilar/yazi/2 |
Yukarıdaki URL yapılarını incelerseniz eğer, soldaki yapı “yazilar” dizininin içindeki “yazi.aspx” dosyasına erişim sağlamaktadır ve parametre olarak “2” değerini taşımaktadır.Yukarılarda, kullanıcılar tarafından okunaklı link yapısından söz etmiştik.Ancak bu link yapısında “?” gibi karakterler mevcut ve parametre adı olarak “id” ismi bulunmaktadır.Bu link yapısı güvenlik açısından SQL Injection açığına yakalanmamıza sebep olabilir.Ayrıca, “yazilar dizisi içinde, yazi.aspx sayfasına, id değeri 2 olan yazıyı getir” gibisinden bir okuma yapabiliriz.Ama bu hiçte tutarlı değil.
Sağdaki URL yapısını incelersek eğer, “yazilar” dizininin içinde ki “yazi” dizininden “2” değerine sahip olan dosyaya URL Routin mekanizmasıyla erişim sağlanmaktadır.Bu iki link yapısı aynı proje içinde kullanılabilir.Sanmayın ki, URL Routing yapısıyla yönlendirilmiş linki uygulamak için projelerimizde diziler oluşturup içlerine dosyalarımızı koyacağız.Soldaki standart URL yapımız, bu yapımıza URL Routing mekanizması ile yönlendiriliyor ve linksel güvenlik açığı söz konusu olmadan, SEO tabanlı URL oluşturulmuş oluyor.
Gelelim MVC mimarisinde URL Routing mekanizmasına.Asp.NET mimarisinde URL Routing mekanizması yukarıda bahsettiğimiz gibi çalışmaktadır.MVC mimarisinde ise, Standart URL bulunmamaktadır.Bilakis yüzde yüz URL Routing alt yapılı bir mimaridir.Tabi işin içine MVC’de Controller, Action gibi konular girdiğinden dolayı, Routing mekanizmasıyla üretilmiş URL’imizde ki dizi mantığı bu terimlerle birleşmektedir.
MVC mimarisinin sistem işleyişini hatırlarsak eğer, kullanıcı tarafından gelen bir istek üzerine Controller katmanındaki ilgili sınıfımızda ki ilgili Action metodumuz çalışıyordu.Sistem hangi Controller sınıfında hangi Action metodunu çalıştıracağını URL yapısından anlıyordu.Örnek olarak aşağıdaki linki inceleyelim.
http://www.bilmemne.com/Home/Index
Linkte gördüğünüz üzere kırmızı renkle işaretlendirilmiş olan “Home” dizisi ilgili Controller sınıfımızı gösterirken, mor renkle işaretlendirilmiş “Index” dizisi ise, “Home(Controller).cs” sınıfımızdaki Action metodumuzu göstermektedir.Bu link tetiklendiği zaman ilgili Controller sınıfı ve Action metod çalıştırılmış olacaktır
Şimdi Visual Studio 2012 derleyicisinde bir MVC Razor mimarisinde proje oluşturalım.MVC uygulamalarında URL Routing yapısı Global.asax dosyası içerisinde tanımlanmaktadır.Ancak Visual Studio 2012 derleyicisi hiyerarşik bir sistem inşa ederek bu yapıyı farklı katmanlara bölmüştür.Oluşturduğumuz projenin Solution Explorer penceresini incelersek eğer, “App_Start” dizisi bulunmaktadır.Bu dizi altında “RouteConfig.cs” isimli bir sınıf bulunmaktadır.
URL Routing konfigürasyonu bu dosya altında yapılmaktadır.Şimdi bu dosyanın yapısını inceleyelim.
public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } }
Yukarıdaki kod bloğunu incelerseniz eğer, “RouteConfig” isminde bir sınıf bulunmaktadır ve bu sınıf içinde, geriye değer döndürmeyen, “RouteCollection” tipinde parametre alan, static yapıda “RegisterRoutes” isimli metod mevcuttur.Bu metod içinde “routes” isimli parametrenin “MapRoute” metodunu kullanarak URL Routing şeması çizilmiştir.
Bu URL Routing şemasının, adı “Default”, URL yapısı “{controller}/{action}/{id}” ve son olarak default(varsayılan) değerleri ise “controller için ‘Home”, action için ‘Index’ ve parametre için UrlParameter.Optional” olarak tanımlanmış.Burada dikkat etmemiz gereken mühim nokta, süslü parantezler({ }) içine verilen isimlerden “controller” ve “action” ismi sabittir.Değiştirilemezler!!!
Şimdi bu “RouteConfig” sınıfının içinde bulunan “RegisterRoutes” URL yapısını Global.asax dosyasına nasıl entegre edebiliriz, inceleyelim.
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); } }
Yukarıda gördüğünüz kod bloğu, projemizde ki “Global.asax” dosyasının içeriğidir.Dikkat ederseniz eğer, “RouteConfig.RegisterRoutes(RouteTable.Routes)” kodu ile yukarıdaki sınıfımızı entegre etmiş oluyoruz.
Varsayılan URL Routing Ayarları
Visual Studio derleyicisinde, yeni bir MVC uygulaması açarsak eğer, Global.asax dosyasında varsayılan değerlerin atandığını görmekteyiz.(Tabi biz bu makalemizde Visual Studio 2012 modelini kullandığımızdan dolayı, “App_Start” dizini içerisindeki “RouteConfig” sınıfından bahsetmiş oluyoruz.)
routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );
Yukarıdaki kod bloğu, yeni açılan bir MVC projesinin “RouteConfig” sınıfındaki varsayılan içeriklerdir.Gördüğünüz üzere, varsayılan olarak Controller “Home” ve varsayılan olarak Action ise “Index” seçilmiştir.Parametremize varsayılan olarak opsiyonel bir değer atanmış.
Burada örneklendirme yapmak için, üzerinde çalıştığımız projeye “A(Controller).cs” ve “Home(Controller).cs” isimlerinde iki Controller oluşturalım ve oluşturduğumuz “A(Controller).cs” Controller sınıfının içine “Ornek” adında bir Action metod ve “Home(Controller).cs” Controller sınıfının içine de “Index” adında bir Action metod oluşturalım.
public class AController : Controller { public ActionResult Ornek() { return View(); } }
public class HomeController : Controller { public ActionResult Index() { return View(); } }
Şimdi projemizde “A(Controller).cs” Controller sınıfının içindeki “Ornek” isimli Action metoda talep göndermek istiyorsak aşağıdaki gibi bir link yapısını tetiklememiz gerekiyor.
Eğer projemizde bu tarz link yapısı tetiklenirse, “A(Controller).cs” ismindeki Controller sınıfımızın “Ornek” isimli Action metodu çalıştırılmış olacaktır.
Eğer aşağıdaki Global.asax dosyasındaki URL şemasına uygun bir şekilde olmadan, Controller ve Action metodlarının olmadığı URL yapısı tetiklenirse “Home(Controller).cs” adındaki Controller’ımızın içindeki “Index” isimli Action metod çalışacaktır.Örnek olarak;
Yeni Bir URL Yapısı Tanımlarken Dikkat Edilmesi Gereken Kurallar
URL yapısı tanımlarken belli başlı üç tane kural mevcuttur.Bunlardan biri,
Global.asax dosyamızda yeni bir URL yapısı tasarlayacaksak eğer, varsayılan olarak gelen “Default” ismine sahip Route’tan önce tanımlanması gerekmektedir.
routes.MapRoute( name: "OrnekRoute", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); //Doğrusu "Default" Route'tan önce tanımlamaktır. routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );
Bu kural katiyen çok önemlidir.Aksi taktirte “Default” Route çalışacak ve kendi tasarladığımız Route yapısındaki linkler patlayacaktır.
Bir diğer kuralımız ise,
URL yapısında süslü parantezler({..}) ile belirttiğimiz parametreler arada en az bir karakter olmadığı zaman tanımlanamazlar.
{Ogrenci}{ID}
Yanlış bir tanımlamadır.
{Kategori}/{ID} {Kategori}.{ID} {Kategori}kategori{ID} {Kategori}-{ID}
Doğru tanımlamalardır.
Son kuralımız ise,
URL yapısı tanımlanırken, Route adı benzersiz olmalıdır.
Aynı isimde birden fazla URL yapısı tekrarlanırsa proje hata verecektir.
Düzenli İfadeler Kullanarak Kısıtlama Oluşturma
Bu konuyu irdelemek için aşağıdaki örnek Route’u inceleyiniz.
routes.MapRoute( name: "Arsiv", url: "{controller}/{action}/{tarih}", defaults: new { controller = "Tarih", action = "Arsiv", tarih = "" } );
Yukarıdaki Route yapısını incelerseniz eğer, “Tarih” adında bir Controller sınıfımız ve bu Controller içinde “Arsiv” adında bir Action metodumuz olduğu net bir şekilde anlaşılmaktadır.
Varsayalım ki, http://www.bilmemne.com/Tarih/Arsiv/09.05.1992 yapısındaki bir link tetiklendiği anda, doğal olarak “Tarih(Controller).cs” ismindeki Controller sınıfımız ve onun içindeki “Arsiv” ismindeki Action metodumuz tetiklenecektir.İşlevsellik olarak bu sürecin bizlere 09.05.1992 tarihindeki verileri listeleteceğini varsayalım.Yani parametre olarak tarihsel tipte bir değer girmemiz gerektiğinin farkına varmışsınızdır sanırım.
http://www.bilmemne.com/Tarih/Arsiv/14.03.2013 |
Eğer bu link yapısı tetiklenirse sorun yoktur. |
http://www.bilmemne.com/Tarih/Arsiv/ahmet |
Ancak bu link yapısı tetiklendiği zaman, parametre olarak tarihsel bir değer almamış ancak URL yapısı olarak “Arsiv” adındaki Route yapısını çalıştıran bir link olacaktır.Haliyle işlevsel olarak yanlış formatta gelen değer olduğundan dolayı hata verecektir. |
Bu durumu engellemek için düzenleyici ifadeleri kullanmalıyız.Eğer gelen parametrenin değeri tarih formatındaysa, “Arsiv” adındaki Route çalıştırılacaktır.Aksi taktirde çalışmayacak veyahut başka Route yapıları incelenecektir.
routes.MapRoute( name: "Arsiv", url: "{controller}/{action}/Tarih/{tarih}", defaults: new { controller = "Tarih", action = "Arsiv", tarih = "" }, constraints: new { tarih = @"\d{2}.\d{2}.\d{4}" }
Gördüğünüz gibi, düzenli yapılarla hangi formatta değişken değeri alınacağını bildirmiş olduk.
Bu yazımızıda burada sonlandırıyoruz.
Faydalanmanız dileğiyle..
İyi Çalışmalar…
Teşkkürler