Bu yazımızda MVC projelerinde nasıl seo (arama motoru dostu linkler) bağlantı oluşturacağımızı anlatmaya çalışacağım. Bu oluşturduğumuz web sitelerinin google, bing, yandex gibi arama motorlarında aranabilir olması için önemli bir konu. Örneğin bir film sitemiz olduğunu düşünelim.
Sitemizde film bağlantılarının .../FilmDetay/5 şeklinde olması yerine .../FilmDetay/demir-adam-3 şeklinde olması hem sitemizin arama motarları tarafından kolayca taranıp bulunabilmesini sağlar hem de iyi bir kullanıcı deneyimi oluşturur.
Okurken ne dinlemeli ?
Çok basit ve sade bir şekilde seo url oluşturmaya çalışalım.İlk olarak bir MVC projesi oluşturalım.
Projede zaten var olan bootstrap.css ve bootstrap.js front-end framework'ünü sitemizi biçimlendirmek için kullanacağız. Diğer css ve js 'leri dilerseniz silebilirsiniz. Senaryomuz şöyle ilerleyecek bir film listesi sayfamız olacak bu Index.cshtml ve buradan film detaylarına gittiğimiz Detail sayfamız olacak.
İlk olarak Film class'ını oluşturarak başlayalım.
public class Films
{
public int Id { get; set; }
public string Title { get; set; }
}
Index sayfamızın aşağıdaki gibi html 'ini oluşturalım.
@model List<SeoFriendly.Models.Films>
@{
ViewBag.Title = "Home Page";
}
<div
class="row">
<table style="border-collapse:separate;border-spacing: 2px 5px" width="100%">
@foreach (var item2 in Model)
{
<tr>
<td
width="13%">
<a class="pull-left" href='@Url.FilmSeoLink(item2)'>
<img class="media-object" src="http://placehold.it/400x200/" alt="">
</a>
</td>
<td
width="72%"><p>@item2.Title</p></td>
<td
width="5%"></td>
</tr>
}
</table>
</div>
[Route("~/")]
[Route("Home")]
public ActionResult Index()
{
List<Films> filmlist = new List<Films>();
filmlist = GetFilms();
return View(filmlist);
}
public List<Films> GetFilms()
{
List<Films> filmlist = new List<Films>();
filmlist.Add(new Films { Id = 1, Title = "Iron Man 3" });
filmlist.Add(new Films { Id = 2, Title = "Batman Begins" });
filmlist.Add(new Films { Id = 3, Title = "Superman vs Batman
Dawn of Justice"
});
filmlist.Add(new Films { Id = 4, Title = "Amazing
Spiderman"
});
return filmlist;
}
routes.MapMvcAttributeRoutes();
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Diğer dikkat etmemiz gereken nokta ise href='@Url.FilmSeoLink(item2)' peki bu nasıl olacak? a html elementinin linkini MVC'nin URL sınıfını override ederek özelleştirmiş oluyoruz. Bunun için aşağıdaki sınıfı ve metodları oluşturuyoruz. Aslında seo url 'leri üreten sınıf da bu sınıf olmuş olacak.
public static class SeoFriendlyLink
{
public static string FilmSeoLink(this UrlHelper urlHelper, Films entity)
{
string title = entity.Title;
title = FriendlyURLTitle(title);
return string.Format("/Detail/{0}/{1}", entity.Id.ToString(),
title);
}
public static string FriendlyURLTitle(string pTitle)
{
pTitle = pTitle.Replace(" ", "-");
pTitle = pTitle.Replace(".", "-");
pTitle = pTitle.Replace("ı", "i");
pTitle = pTitle.Replace("İ", "I");
pTitle = String.Join("", pTitle.Normalize(NormalizationForm.FormD) // türkçe karakterleri
ingilizceye çevir.
.Where(c => char.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark));
pTitle = HttpUtility.UrlEncode(pTitle);
return System.Text.RegularExpressions.Regex.Replace(pTitle, @"\%[0-9A-Fa-f]{2}", "");
}
}
Aslında FilmSeoLink metodumuz ile film item 'ini alarak başlığından dilediğimiz standartta bir bağlantı oluşturuyoruz. Bu metodda dikkat etmemiz gereken nokta ise FrinedlyURLTitle metodu çünkü browserler url isteği yaparken özel karakterleri boşluk , . gibi veya türkçe karakterleri(ç,ş) kabul etmiyor ve istek yapılırken hata oluyor. İşte bu method başlığı ingilizceleştiriyor ve özel karakterleri url(bağlantı)'den siliyor.
Örneğin FilmDetay/pi'nin yaşamı gibi bir bağlantı geçersiz olacağında bunu FilmDetay/pinin_yasami haline getiriyor.
Şimdi detay sayfamızın önce View sonra da Contoller'ını oluşturalım.
@model SeoFriendly.Models.Films
@{
ViewBag.Title = "Detail";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div
class="row">
<div class="col-lg-12">
<h1 class="page-header">
@Model.Title
</h1>
<img class="img-responsive" style="padding: 20px 0px;" src="http://placehold.it/700x400/" alt="">
<p>Film info created by
SeoFriendly</p>
</div>
</div>
Contoller:
[Route("Detail/{Film_Id}/{seo_text}")]
public ActionResult Detail(int Film_Id,string seo_text)
{
Films film = new Films();
film = GetFilms().Where(x =>
x.Id == Film_Id).FirstOrDefault();
if
(SeoFriendlyLink.FriendlyURLTitle(film.Title)
!= seo_text)
{
return HttpNotFound();
}
return View(film);
}
Detail Controller'ın Route'ını oluştururken FimSeoLink metodunda oluşturduğumuz standartın aynısı olmasına dikkat edelim ve de Detail ActionController'ın parametre isimlerinin Route'deki ile aynı olmasını sağlayalım.
Detay sayfasının işleyişinde fark ettiğiniz üzere filmi Id'sinden buluyoruz ve bu ID'yi de bağlantıda içeriyoruz. Eğer basit düşünüp Id yeterli diyip seo url bağlantı linki ile sistemde kayıtlı olan (id 'den bulunan) filmin başlığı ile karşılaştırma yapmazsanız güç durumlar yaşayabilirsiniz.
if (SeoFriendlyLink.FriendlyURLTitle(film.Title) != seo_text)
Örneğin : FilmDetay/5/DemirAdam-3 linkini sadece Id =5 'i kontrol edersek aşağıdaki şu link de çalışır, aynı sayfaya gider.
FilDetay/5/DemirAdamvsBatman_filmi_vizyonda
İşte bunu önlemek için DemirAdamvsBatman_filmi_vizyonda titlesi ile Id'sı 5 olan filmin title'sini karşılaştırmak faydalı olacaktır.
Şimdi projemizi derleyip çalıştıralım.
Herhangi bir filmin detayına tıklayalım.
Okuduğunuz için, teşekkürler, tam projeyi buradan indirip inceleyebilirsiniz.
Sağlıkla kalın, huzurlu olun :)
Çok teşekkür ederim Sağolasın beni büyük bir dertten kurtardın
YanıtlaSilFaydalı olabildiysem ne mutlu :) okuduğunuz için teşekkürler.
YanıtlaSilMerhaba Sema Hanım,
YanıtlaSilMakaleniz gerçekten çok faydalı oldu. Teşekkür ederim.
Ben adres çubuğundan detail ve id yi kaldırmak istiyorum. Yani sadece site adı ve sonrasında detayı görüntülenen sayfanın seolinki görünsün istiyorum. Bu mümkün olur mu acaba? Yardımcı olabilir misiniz?
Merhaba,
Silİlginiz için teşekkür ederim, tabii ki mümkündür fakat dikkat ederseniz burada detail sayfayı id 'den bulup getiriyor ,id yi kaldırır iseniz , detay sayfayı title 'den getirebilirsiniz. Title'lerin unique olmasına da dikkat edersiniz.Teşekkürler.
Projemizde id,ürünad ve ürünboyut var.id gelsin istemiyoruz ama title ları kişi girdiği için uniq yapamıyoruz.Nasıl yapılabilir yardımcı olur musunuz?
SilMerhaba, linkde unique bir alan olmalı başka türlü istenilen veriye ulaşamazsınız, unique alanı şifreleyip, maskeleyip linkte tutabilirsiniz.
SilÖncelikle bu güzel örnek için teşekkür ederim.
YanıtlaSilAma Ben aşağıdaki gibi bir hata aldım.Sebebi nedir.?
Derleme Hatası
Açıklama: Bu isteği yerine getirmek için gereken kaynak derlenirken bir hata oluştu. Lütfen aşağıdaki özel hata ayrıntılarını gözden geçirin ve kaynak kodunuzu uygun biçimde değiştirin.
Derleyici Hata İletisi: CS1617: /langversion için '6' seçeneği geçersiz; ISO-1, ISO-2, 3, 4, 5 veya Default olmalıdır
Kaynak Hatası:
[İlişkili kaynak satırı yok]
Merhaba,
SilFramework versiyonu ile ilgili hata almışsınız aşagıdaki linkte answer 5 'i deneyebilir misiniz ?
https://stackoverflow.com/questions/31868803/error-invalid-option-6-for-langversion-must-be-iso-1-iso-2-3-4-5-or-defa
Evet dediğiniz gibi WebConfig dosyasındaki langversiyon:6 değil 5 yapınca çalıştı. ozaman Mvc de yapılan örneklerin framework versiyonları önemli değil mi?
yani eski versiyon bir örneği yeni versiyona aktarırken hata alabilir mi????
Merhaba,
SilVisua Studio genellikle kendisi convert ediyor. Ama bazen böyle hatalar olabiliyor.
Merhaba, FilmSeoLink ve FriendlyURLTitle metodlarını nereye oluşturuyoruz.
YanıtlaSil'@Url.FilmSeoLink(item2) burada hata alıyorum. Teşekkürler.
Silclass oluşturup içine yazıyorsunuz makalede yazıyor dikkatli okuyun
SilMerhabalar,
YanıtlaSilBunu gerekli olan entityler için yapma şansım var mıdır ? Yani gerekli olan her entity için bunu yazmak yerine Generic olarak yapabilir miyim ? Class static olduğu için olmuyor diye biliyorum ama.
Merhaba Haluk ne demek istediğini tam anlamadım , örnek verebilir misin ?
SilMerhabalar,
SilSiz metoda Films entitysini göndermişsiniz. Yani metod Films entitysini alıyor.Buradaki gelen entity kısmı generic olabilir mi ? Entity tipi belirtmeden yani.
evet, elbette yapabilirsin, örnek bir makaleyi paylaşıyorum : http://www.gokhan-gokalp.com/generic-repository-ve-unit-of-work-kullanarak-basic-infrastructure-tasarlamak/
SilMerhaba projeniz için teşekkürler.
YanıtlaSil@Url.FilmSeoLink forech içinde fonksiyona gitiyor hata veriyoru forech dışına alıp string gönderdiğimde çalışıyor.
Birde performans açısından veri tabanında bir alan oluşturup seo-link adında kayıt öncesi hazır link tutmam mı daha iyi olur.
Merhaba, okuduğunuz için teşekkürler. Projeyi tekrar indirip çalıştırıdım bir hata alamadan çalıştı. @Url.FilmSeoLink 'de aldığınız hatayı google'de aratıp çözmenizi tavsiye ederim. Seo linki veri tabanında tutarsanız örneğin editör içerik başlığını güncellediğinde veri tabanını da güncellemeniz gerekir. İstek anında url'in oluşması performans sıkıntısı yaratmaz.
YanıtlaSilMerhaba, makalenizi okuyup işlemleri tamamladım sona geldim. herşey sorunsuz görüntüleniyor fakat benim aklıma takılan bir soru var:
YanıtlaSilBen çoklu dil seçeneği olan bir site yapıyorum. tüm haberlerin listelendiği sayfada dil menüsünden ingilizce veya herhangi bir dilin üzerine geldiğimde çeviri oluyor.yani : deneme.com/haberler, deneme.com/en/news oluyor. fakat yukarıdaki detay sayfası örneğinizde bu nasıl olacak bilemedim. aslında çalışıyor. yani haberler sayfasında dili ingilizceye çevirip ilerleyince : deneme.com/haberler/yeni-filmler-geldi, deneme.com/en/news/incoming-new-films oluyor. benim isteğim herhangi bi haberin içindeykende haberler sayfasına geri dönmeden başka dildeki sayfasını çağırabileyim.
MVC'de Çoklu dil seçenekli aynı zamanda SEO Route kullanıp Detay sayfası örneği bulamadım. Sizin bu konu hakkında fikriniz vardır ve umarım problemi doğru anlatabilmişimdir :)
Merhaba, okuduğunuz için teşekkürler. Bildiğim kadarı ile SEO Url'i dile göre otomatik çevirisini yapılamıyor. İnglizce url'leri ve content'i hazırlayıp. deneme.com/en ise ingilizce içerik oluşturduğunuz veri tabanından ya da tablodan verileri getirmeniz gerekiyor.
YanıtlaSil