MVC SITENIZ ICIN SEO SITEMAP ve RSS HAZIRLAMA
April 2019 (0) Iptv 11/21/2024
MVC ile site geliştrdiniz ve dünyanın bundan haberdar olması isteriz. Yapmamız gereken sitemizi arama motorlarına kaydetmek. Arama motorlarının sitemizde dolaşabileceği ve sitemizin listelerde üst sıralarda çıkarabilecek bir yol sunmalıyız. MVC .NET ile oluşturduğumuz sitede SEO'yu nasıl oluşturabiliriz? İlk olarak yapmamız gereken sitemize gelen sitemap.xml dosya isteğini yakalamamız ve bir action'a yönlendirmemiz gerekmektedir. Uygulamanın başlangıçında (Global.asax Application_Start()) içinde sitemap.xml yönlendirmeyi yapalım: [Code] Sitemize gelen sitemap.xml dosyası isteği RssController.SiteMap() action'a yönledirmiş olduk. RssController.SiteMap() action metotdu stansart bir html yerine sitemap.xml protokolüne uygun çıktı üretmelidir. Böylece arama motorlarının anlayabileceği bir içerik oluşturmuş olunur. XmlWriter kodları aşağıdaki gibi olmalıdır. [Code] Sitemap.xml isteklerini yönlendirdiğimiz RssController.SiteMap() action metodunun SitemapActionResult un isteklere dönmesi için aşağıdaki kodları yazalım. [C#] Böylelikle yayında olan sayfaları listeleyip sitemap.xml protokolüne uygun olarak cevap dönmüş olduk. RSS (Really Simple Syndication) web içeriği abonelik formatıdır. RSS içeriği sabit bir xml yapısıdır. <rss> tagları arasında sitede yer tüm içeriği sunabilmektesiniz. Site haritası'na (sitemap.xml) göre çok daha gelişmiş ve detaylı bir veri yapısına sahiptir. Yorumlar, resimler, yayın tarihi web master bilgisine kadar geniş bir veri yapısı ile besleme oluşturabilirsiniz. Farklı besleme formatlarını destekleyen bir besleme kaynağı oluşturma aracına ihtiyaçımız varsa, SyndicationFeed sınıfı bu ihtiyacımızı karşılamak için en ideal yoldur. SyndicationFeed nesnesi oluşturup site içeriğinizi feed.items altına doldurarak kendi besleme kaynağınızı oluşturabilirsiniz. [C#] Yukarıdaki örnekte bir besleme kaynağı (feed) oluşturduk. Besleme kaynağı içerisine sitenin başlığı, url bilgisi, dil bilgisi, yazar bilgisi gibi bir çok bilgi ekledil. Sayfa içeriğinde adece özet bilgisi gönderdik. Hem içerik özetini hemde linki ekledik. Böylece sitemize ait içeriği webe uygun hale getirdik Rss içeriğimizi oluşturduğumuza göre şimdi sıra içeriklerimizi MVC ile sitemize aktarmaya geldi. Rss içeriğini için aşağıdaki kodlara bakalım. [C#] Yukarıdaki kod bloğunda MVC ContentResult sınıfından türetilen SyndicationFeedResult sınıfı içerik olarak .NET'e ait SyndicationFeed nesnesini Rss formatında dönüştürmektedir. Rss içeriğini CreadFeed() ile webe uygun formata dönüştürecek SyndicationFeedResult sınıfını action metot ile site beslemesine aktaralım. [C#] Arama motorları web üzerinden ki aynı içeriğe birden fazla url ile ulaşılması durumunda tekrarlanan içerik olarak algılamaktadır. Arama motorları sitenizi tararken www'li e www'siz iki ayrı içeriği algılarlar. Yani http://www.siteniz.com/ ve http://siteniz.com/ arama motorları için iki farklı tekrar edilen içeriktir. Bu durumda arama motorları tüm sitenizi tekrar eden içerik olarak algılar ve sitenizin bulunabilirliği azalır. Bunu önlemek için 301 Redirect kullanılır. Yapmanız gereken sitenizin www'li veya www'siz versiyonundan birini seçip gelen istekleri diğer versiyona yönlendirmektir. Genellikle www'li versiyon kullanılmaktadır. Bende örnek olarak www'siz versiyondan gelen istekleri www'li versiyona yönlendireceğim. Yapmamız gereken gelen tüm istekleri kontrol edecek bir MvcHandler yazmak. MvcHandler'ımız gelen istekleri kontrol edecek ve istek adresinde www yoksa isteği www'li versiyona yönlendirecek. MvcHandler'lar Global.asax içinde yaptığımız Route tanımlarına eklenen nesnelerdir. MvcHandler bir Route işlemi çalışırken hangi Controller'ın seçilmesi gerektiğine karar verirler. Bu işlemi yapabilmek için tüm isteklerin başında çalışırlar. Mvc gelen isteğe göre önce hangi Route tanımının çalışması gerektiğine karar verir daha sonra Route içinde tanımlı Handler'larda hangi Controller sınıfının çalışması gerektiğine karar verir. Böyle her hangi bir Router için tüm istekler "Handle" edebileceğiniz yer MvcHandler'dır. MvcHandler‘ımız aşağıdaki gibidir. [cs] Route tanımlarımıza yazdığımız RedirectHandler ile çalışarak gerekli Controller'ı seçmesini söylemeliyiz. [cs] RouteHandler sınıfı MvcHandler sınıflarını Route listelerine ekleyebilecek yardımcı bir sınıfdır. [cs]MVC sitemap.xml
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("robots.txt");
routes.MapRoute("sitemap", "sitemap.xml", new { controller = "Rss", action = "SiteMap" });
public class SitemapActionResult : ActionResult
{
private readonly string _siteUrl;
private readonly List<Page> _pages;
public SitemapActionResult(string siteUrl, List<Page> pages)
{
_siteUrl = siteUrl;
_pages = pages;
}
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.ContentType = "text/xsl";
using (XmlWriter writer = XmlWriter.Create(context.HttpContext.Response.Output))
{
writer.WriteStartElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9");
writer.WriteStartElement("url");
writer.WriteElementString("loc", _siteUrl);
writer.WriteElementString("lastmod", DateTime.Now.ToString("yyyy-MM-dd"));
writer.WriteElementString("changefreq", "daily");
writer.WriteElementString("priority", "1.0");
writer.WriteEndElement();
foreach (var page in _pages)
{
writer.WriteStartElement("url");
writer.WriteElementString("loc",
string.Format("{0}/{1}/{2}/{3}", _siteUrl, page.Published.Year,
page.Published.Month, page.Slug));
writer.WriteElementString("lastmod", page.LastChanged.ToString("yyyy-MM-dd"));
writer.WriteElementString("changefreq", "daily");
writer.WriteElementString("priority", "0.5");
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.Flush();
writer.Close();
}
}
}
public ActionResult SiteMap()
{
return new SitemapActionResult(
_settingRepository[SiteSettingKey.SiteUrl],
_pageRepository.Query()
.Where(c => c.IsPublish && c.Published < DateTime.Now)
.OrderByDescending(c => c.Published).ToList());
}
RSS Nedir, Neden Kullanılmalıdır ?
RSS ve MVC .NET
public SyndicationFeed CreateFeed()
{
var pages = _pageRepository.Query();
var feed = new SyndicationFeed(
_settingRepository[SiteSettingKey.SiteTitle],
_settingRepository[SiteSettingKey.SiteSlogan],
new Uri(_settingRepository[SiteSettingKey.SiteUrl]));
feed.Categories.Add(new SyndicationCategory("Blog"));
feed.Language = "tr-TR";
feed.Copyright = new TextSyndicationContent(
string.Format("{0} {1}", DateTime.Now.Year, _settingRepository[SiteSettingKey.SiteTitle]));
feed.LastUpdatedTime = DateTime.Now;
feed.Authors.Add(
new SyndicationPerson
{
Name = _settingRepository[SiteSettingKey.SiteTitle],
Email = _settingRepository[SiteSettingKey.Email]
});
var feedItems = new List<SyndicationItem>();
foreach (var item in pages)
{
var sItem =
new SyndicationItem(
item.Title,
null, /*content*/
new Uri(string.Format("{0}/{1}/{2}/{3}",
_settingRepository[SiteSettingKey.SiteUrl],
item.Published.Year,
item.Published.Month,
item.Slug)))
{
Summary = new TextSyndicationContent(item.Summary),
Id = item.Slug,
PublishDate = item.Created
};
sItem.Links.Add(
new SyndicationLink
{
Title = item.Title,
Uri =
new Uri(string.Format("{0}/{1}/{2}/{3}",
_settingRepository[SiteSettingKey.SiteUrl],
item.Published.Year,
item.Published.Month,
item.Slug)),
Length = item.ContentHtml.Length,
MediaType = "html"
});
feedItems.Add(sItem);
}
feed.Items = feedItems;
return feed;
}
RSS ve MVC
public class SyndicationFeedResult : ContentResult
{
public SyndicationFeedResult(SyndicationFeed feed)
{
using (var memstream = new MemoryStream())
using (var writer = new XmlTextWriter(memstream, System.Text.Encoding.UTF8))
{
feed.SaveAsRss20(writer);
writer.Flush();
memstream.Position = 0;
Content = new StreamReader(memstream).ReadToEnd();
ContentType = "application/rss+xml";
}
}
}
public SyndicationFeedResult Feed()
{
var feed = CreateFeed();
return new SyndicationFeedResult(feed);
}
301 Redirect
public class RedirectHandler : MvcHandler
{
public RedirectHandler(RequestContext requestContext)
: base(requestContext) { }
protected override IAsyncResult BeginProcessRequest(
HttpContext httpContext,
AsyncCallback callback, object state)
{
if (!httpContext.Request.Url.AbsoluteUri.Contains("://www."))
{
httpContext.Response.Status = "301 Moved Permanently";
httpContext.Response.StatusCode = 301;
httpContext.Response.AppendHeader(
"Location",
httpContext.Request.Url.AbsoluteUri
.Replace("://", "://www.")
);
}
return base.BeginProcessRequest(
httpContext, callback, state);
}
}
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("Content/{*pathInfo}");
routes.MapRoute(
"DefaultController",
"{controller}/{action}/{id}",
new {controller = "Home", action = "Index",id=UrlParameter.Optional});
RouteHandler<RedirectHandler>.Assign(RouteTable.Routes);
public class RouteHandler<THttpHandler> : MvcRouteHandler
where THttpHandler : MvcHandler
{
public RouteHandler(IControllerFactory controllerFactory)
: base(controllerFactory) { }
public static void Assign(RouteCollection routes)
{
using (routes.GetReadLock())
{
var routeHandler
= new RouteHandler<THttpHandler>(
ControllerBuilder.Current.GetControllerFactory());
foreach (var route in routes
.OfType<Route>()
.Where(r => (r.RouteHandler is MvcRouteHandler)))
{
route.RouteHandler = routeHandler;
}
}
}
}