Merhaba Arkadaşlar,
Yukarıdaki resimde, bir ışıklı kavşak görmekteyiz. Işıklar sayesinde araçlar ve yayalar, gidecekleri yere güven içerisinde ulaşabilmektedirler.
Asp.Net Mvc'de Routing yapısını da, aslında bu şekilde değerlendirme imkanına sahibiz. Sitemize giren bir ziyaretçi, talep ettiği sayfaya, bizim kurduğumuz Routing mekanizması ile ulaşabilmektedir.
Asp.Net Web Forms'da bu yapı çok daha zordur. Talep edilen her sayfa, sunucuda fiziksel olarak bulunan bir sayfadır. Biz direkt olarak sayfayı adıyla çağırırız. Bu noktada Seo açısından uyumlu linkler oluşturmamızda oldukça zor olmaktadır. Url Rewrite teknikleri ile bu sorunlar aşılmaya çalışılmaktadır.
Asp.Net Mvc, piyasaya sürüldüğünde, Routing mekanizması çok beğenilmiştir. Asp.Net Mvc'de fiziksel olarak sunucuda barınan sayfalar yoktur. Ziyaretçi bir talepte bulunduğunda, Controller içerisindeki Action'u çağırır. Action istediği sonucu, istediği View parçasını geriye döndürebilir. Bu da bize ekstra güvenlik ve esneklik sağlamaktadır. Biz bunun yanında istersek, bir url'nin istediğimiz bir Action'u çalıştırmasını sağlayabiliriz. Örneğin; haberler/spor şeklinde bir linke talepte bulunulduğunda, NewsController içerisinde bulunan, Sport Action'unu çağırabiliriz. Bu kısımda tamamen özgürüz.
Küçük bir örnek üzerinden gidelim(Önceki derslerimde, yeni proje oluşturma vs. işlemleri çok detaylı, resimli olarak anlatmıştım. İncelemenizde fayda var).;
RouteConfig class'ımızın içerisinde
RegisterRoutes metodu mevcut.RouteConfig Class'ı
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default", //Yönlendirmenin adı
url: "{controller}/{action}/{id}", //Talep olarak gelecek url yapısı
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } //Gelen talebin
//yönlendirileceği, Controller ve Action, varsa parametreler
);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace RoutingDeneme.Models
{
public class News
{
public int Id { get; set; }
//Haberin başlığı
public string Title { get; set; }
//Haberin içeriği
public string Content { get; set; }
//Haberin eklenme tarihi
public DateTime CreatedDate { get; set; }
}
}
using RoutingDeneme.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace RoutingDeneme.Controllers
{
public class NewsController : Controller
{
List<News> news;
public NewsController()
{
news = new List<News>();
news.Add(new News() { Content = "Yapılan seçimlerin sonuçları açıklandı.", CreatedDate = DateTime.Now, Title = "SecimSonuclari", Id = 1 });
news.Add(new News() { Content = "Hükümetin yaptığı yeni düzenleme, cezalarda artış öngörüyor.", CreatedDate = DateTime.Now, Title = "YeniKanunDuzenlemesi", Id = 2 });
news.Add(new News() { Content = "Milli takımımızın aldığı bu galibiyette en büyük pay kalecimizin oldu.", CreatedDate = DateTime.Now, Title = "MilliTakimGalip", Id = 3 });
}
}
}
Yukarıdaki kod bloğunda, öncelikle tüm metodlardan erişebilmek için List<News> news elemanını global olarak
tanımladık. Ardından da, Controller'in initalizer (oluşturucu) metodunda, listemize 3 tane haber ekledik. Böylelikle
elimizde bir veri kaynağı olmuş oldu.
//Tüm haberleri liste halinde getirir.
public ActionResult GetNews()
{
return View(news);
}
ActionResult GetNews()
üzerine sağ tıklayarak Add View diyelim ve ayarlarını aşağıdaki gibi yapalım.

Yeni Route Ekleme
routes.MapRoute(
name: "GetNews",
url: "haberler/tum-haberler",
defaults: new { controller = "News", action = "GetNews" }
);

Parametreli Route Ekleme
//Paramatre olarak gelen id'ye göre haberi getirir.
public ActionResult GetNew(int id)
{
return View(news.Where(i => i.Id == id).SingleOrDefault());
}

@model RoutingDeneme.Models.News
@{
ViewBag.Title = "GetNew";
}
<h2>GetNew</h2>
<div>
<h4>News</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Title)
</dt>
<dd>
@Html.DisplayFor(model => model.Title)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Content)
</dt>
<dd>
@Html.DisplayFor(model => model.Content)
</dd>
<dt>
@Html.DisplayNameFor(model => model.CreatedDate)
</dt>
<dd>
@Html.DisplayFor(model => model.CreatedDate)
</dd>
</dl>
</div>
<p>
@Html.ActionLink("Edit", "Edit", new { /* id = Model.PrimaryKey */ }) |
@Html.ActionLink("Back to List", "Index")
</p>

routes.MapRoute(
name: "GetNew",
url: "haberler/haber-detay/{id}",
defaults: new { controller = "News", action = "GetNew", id = "" }
);

Bu noktada parametreler ile çeşitli kombinasyonlar yapabiliriz. Örneğin /{alt-kategori}/{id} gibi tanımlamalar yaparak, çok esnek Route'ler tanımlayabiliriz. Bu kısım tamamen ihtiyaçlarımıza göre şekillenecektir.
ROUTE'LERDE KISITLAMALAR
Regular Expressions (Düzenli İfadeler) ile Kısıtlama
Güvenlik ve doğru Route eşleşmeleri tanımlayabilmek için, Route'lerimize kısıtlamalar, filtreler tanımlayabiliriz. Böylelikle tam bir eşleşme sağlayarak, ayrıca güvenlik katmanımızın da daha sağlam olmasını sağlayabiliriz.
Title formatında özel bir eşleşme isteğimiz olduğunu varsayarak, NewsController'imize bir Action yazalım.//Parametre olarak gelen id değerine göre haberi getirir.
public ActionResult GetNewByTitle(string id)
{
return View(news.Where(i => i.Title == id).SingleOrDefault());
}
Burada gelen parametreye göre Title ile eşleşen haber ekran getirilecektir.
Not : Parametre ismine title yerine id vermemizin sebebi, sistemde tanımlı halde gelen Default Route'sinde id parametresi tanımlı durumdadır. Buradan, Route tanımlamamız gerekliliği de, açıkça ortaya çıkmaktadır. Biz bu parametreyi Route tanımlayarak daha mantıklı hale getireceğiz.



Şimdi burada biraz düşünelim. Az evvel tam olarak ne oldu?
Adres çubuğunda Title kısmına rakamsal bir giriş yapıldı. Metod çalıştı ve veri kaynağımızda Title=5 eşleşmesini araştırdı. Bulamadı ve ekrana veri boş geldi.
Oysa ki biz, sadece metinsel giriş yapılmasını istiyor olabiliriz. Böylelikle hatalı girişleri daha önceden engelleme imkanına sahip oluruz. Ayrıca her girilen veri, veritabanında sorgulanmayacağı için hem performans, hem de güvenlik avantajını filtreleme sayesinde sağlayacağız. Regular Expression (Düzenli İfadeler), bu konuda bizim en büyük yardımcımız olacaktır.
routes.MapRoute(
name: "GetNewByTitle",
url: "haberler/haber-detay-baslik/{title}",
defaults: new { controller = "News", action = "GetNewByTitle", title = "" },
constraints: new { title = @"[a-zA-Z]+" } //Burada yönlendirmenin yapılabilmesi için
//title verisinin yalnızca metinsel olmasını şart koştuk.
);
//Parametre olarak gelen title değerine göre haberi getirir.
public ActionResult GetNewByTitle(string title)
{
return View(news.Where(i => i.Title == title).SingleOrDefault());
}

Bu ve buna benzer şekilde, çeşitli Regular Expressions'lar vasıtasıyla çok kullanışlı filtreler tanımlayabiliriz. Regular Expressions ile ilgili internette pek çok hazır kalıplar, eğitimler mevcut.
Http Metodu ile Kısıtlama
Gelen sayfa taleplerinin, Get, Post vs. olduğunda eşleşmesini sağlamak için, Http metodunu kullanabiliriz.
//Burada listeye bir kayıt yapılmakta.
public ActionResult SaveNew()
{
//id olarak listemizdeki en son eklenen id'nin sayısı bir arttırlıp kayıt yapılmaktadır.
int id = (news.OrderByDescending(i => i.Id).SingleOrDefault().Id+1);
news.Add(new News()
{
Content = "Hava olaylarındaki anormallikler dikkat çekici olmaya başladı",
CreatedDate = DateTime.Now,
Title = "Hava Olaylarındaki Anormallikler",
Id = id
});
return View();
}

routes.MapRoute(
name: "SaveNew",
url: "haberler/yeni-haber",
defaults: new { controller = "News", action = "SaveNew" },
constraints: new { method = new HttpMethodConstraint("POST") }
//Yalnızca Post taleplerinde eşleşecek
);
Böylelikle gelen isteklerin yalnızca Post olaması durumunda eşleşmeyi sağlamış olduk. Bu noktada Action metodunun
üzerine [HttpPost], [HttpGet] vs. Attribute'ler ekleyerek de daha kolay bir şekilde bu kısıtlamayı sağlayabiliriz.
Aşağıdaki gibi;
[HttpPost]
//Burada listeye bir kayıt yapılmakta.
public ActionResult SaveNew()
{
//id olarak listemizdeki en son eklenen id'nin sayısı bir arttırlıp kayıt yapılmaktadır.
int id = (news.OrderByDescending(i => i.Id).SingleOrDefault().Id+1);
news.Add(new News()
{
Content = "Hava olaylarındaki anormallikler dikkat çekici olmaya başladı",
CreatedDate = DateTime.Now,
Title = "Hava Olaylarındaki Anormallikler",
Id = id
});
return View();
}
Gelişmiş Kısıtlamalar
Çok daha gelişmiş sınamalar yapabilmek için kullanabileceğimiz IRouteConstraint Interface'si mevcuttur. Bu Interface'den alacağımız Implementation ile bir Class yazıp, gelişkin sınamalar yapabiliriz.
Hemen inceleyelim.
using System.Web;
using System.Web.Routing;
namespace RoutingDeneme.RouteConstraint
{
public class TestConstraint : IRouteConstraint //Burada IRouteConstraint'ten Implemantation alıyoruz.
{
//Match metodu, istediğimiz şekilde doğrulamalrı yapıp, geriye True ya da False döndürüyor,
//dönen sonuca göre Url eşleşmesi sağlanıyor, ya da sağlanmıyor.
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values,
RouteDirection routeDirection)
{
//Örneğimizde, kullanıcının oturum açıp, açmadığını kontrol edeceğiz.
if (httpContext.Request.IsAuthenticated)
{
return true;
}
else
{
return false;
}
}
}
}
//Bu alana yalnızca üyelerin girmesini istiyoruz.
public ActionResult MemberArea()
{
return View();
}
routes.MapRoute(
name: "MemberArea",
url: "uyelik",
defaults: new { controller = "News", action = "MemberArea" },
constraints: new { test = new TestConstraint() }
//Test Constraint'ten yeni bir örnek çağırıp, bağlıyoruz.
);
localhost:...(burası sizde farklıdır)/uyelik adresine gitmek istediğimizde, eşleşme olmayacaktır. Ancak oturum açtıysak, eşleşme olacaktır.
404 Sayfa Bulunamadı Oluşturmak
Route'lerimizde (*) parametresini kullanarak, her türlü eşleşmeyi sağlayabilmekteyiz. (*)'ın yerine ne gelirse gelsin, eşleşme sağlanacaktır.
Şimdi bir 404 sayfası oluşturulım.
//Eğer eşleşme olmazsa bu Action çalışacaktır.
public ActionResult NotFound()
{
return View();
}

@{
ViewBag.Title = "NotFound";
}
<h2>Sayfa Bulunamadı</h2>
using System.Web;
using System.Web.Routing;
namespace RoutingDeneme.RouteConstraint
{
public class NotFoundConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext.Request.RawUrl == "/")
{
return false;
}
else
{
return true;
}
}
}
}
routes.MapRoute(
name: "NotFound",
url: "{*.}",//Yıldız her ne olursa anlamına geliyor.
//Yukarıdaki eşleşmeleri deneyip, olmadığını gördükten sonra, NotFound'a yönelecektir.
defaults: new { controller = "News", action = "NotFound" },
constraints: new { notFound = new NotFoundConstraint() }
);
Route Pas Geçme
Bazı statik dosyalarımıza talep geldiğinde, bu talebin Controller - Action bazlı karşılanmasını istemeyebiliriz. Böylelikle direkt dosyaya ulaşım sağlanacaktır. Bunun için IgnoreRoute metodu kullanılmaktadır.

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
hemen sonra aşağıdaki metodumuzu ekleyelim.
routes.IgnoreRoute("robots.txt");
Artık, sitemize robots.txt talebi geldiğinde, direkt dosyamıza erişim sağlanabilecektir.
AREA'LAR İÇİN ROUTE
Sitemizde, eğer Area sistemini kullanıp parçalara ayırıyorsak, her eklediğimiz Area için ...(area adı) AreaRegistration şeklinde dosya otomatik olarak oluşturulmaktadır. Biz her Area için bu dosyalara metodlar ekleme şansına sahibiz. En sonunda tüm eklediğimiz metodlar, Global.asax dosyasında çağırılan, * AreaRegistration.RegisterAllAreas()* metodu ile birleştirilerek, sistemde aktif hale getirilmektedir.
ASP.NET MVC 5 ROUTE YENİLİKLERİ
Asp.Net Mvc5 ile gelen bir takım yeniliklerin yanında, Route konumuza uygun olarak işleyeceğimiz, Route yeniliğine bakalım. Normalde her Action için Route yazıp, RouteConfig dosyasına ekliyoruz. Mvc 5 ile bu işlem daha da kolaylaştı ve kullanışlılığı arttırıldı.
Bundan sonra artık direkt olarak Action'un üzerine yazacağımız bir Attribute ile Route yapabiliyoruz. Bu sistemi aktif etmek için öncelikle,
//Asp.Net Mvc5 Route sistemini aktif ediyoruz.
routes.MapMvcAttributeRoutes();
satırını ekliyoruz.
public ActionResult Mvc5()
{
return View();
}
@{
ViewBag.Title = "Mvc5";
}
<h2>Mvc5</h2>
<h3>Burada Mvc5 Yeniliklerini Test Ettik</h3>
[Route("mvc5-test")]
public ActionResult Mvc5()
{
return View();
}

Böylelikle çok detaylı bir şekilde, Asp.Net Mvc konusunda Route'yi inceledik.
Proje dosyasını buradan indirebilirsiniz.
Hepinize kolaylıklar diliyoruz.