eray aydoğdu

jQuery and ASP.NET MVC fanatic.

Pro ASP.NET MVC 2 Framework Second Edition Kitabı

MVC 1 i çok başarılı olan kitabın 2 sinin de de gayet iyi anlatılmış bu konuda piyasadaki en iyi kitap diyebilirim. MVC 2 yle birlikte gelen yenilikleri C# 4.0 ı, MVC 2 le MVC 1 kıyasladığınızda işimizi birazcık daha azalttığını kitaptaki örnek kodlar ve anlatım ile görebilirsiniz..

MVC 1 versiyonunu okuyanlar bilir yine SportsStore örneği mevcut diğerinde çok daha detaylı ve daha kalın olan bu versiyonununda pdf i işini görecektir.

MVC 3 e geçmeden önce bu kitaba göz gezdirip bir kaç uygulama yaparsanız. MVC 3 te hiç zorluk çekmezsiniz.

Asp.Net MVC Çoklu Dil Desteği

İki dil site yapımı ya da çoklu dil desteği olan bir site yapımı için session veya cache yöntemi de kullanılabilir fakat profesyonel bir uygulamada bu en iyi çözüm yolu değil. Bunun en güçlü ve pratik yolu dil değişkenini asp.net mvc nin url routing mekanizmasını kullanarak saklamaktır.

Amaç url nin şu şekilde gözükmesini sağlamak : /{culture}/{Controller}/{Action} yani /tr/Home/About

Öncelikle MvcRouteHandler class ını extend etmemiz gerekiyor. Culture parametresi için MultiCultureMvcRouteHandler ve culture parametresi kullanmayacağımız SingleCultureMvcRouteHandler class larımızı oluşturalım.

Custom Route Handlers oluşturalım

public class MultiCultureMvcRouteHandler : MvcRouteHandler
{
    protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        var culture = requestContext.RouteData.Values["culture"].ToString();
        var ci = new CultureInfo(culture);
        Thread.CurrentThread.CurrentUICulture = ci;
        Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(ci.Name);
        return base.GetHttpHandler(requestContext);
    }
}

Base implementation ını çağırmadan önce GetHttpHandler override ederken RouteData collection ından culture parametresini alıyoruz, CultureInfo objesi yaratıp current culture ve current thread özelliklerini ayarladık.

public class SingleCultureMvcRouteHandler : MvcRouteHandler {}

Bu class ı culture yani dil ayarı yapmamızı gerektirmeyen sayfaları için kullanacağız.

Registering Routes (Route larımızı tanımlayalım)

Global.asax dosyasındaki RegisterRoute() methodumuzu açalım. Default route tanımlamasının altına aşağıda ki foreach blogunu ekleyelim.

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
         "Default", // Route name
         "{controller}/{action}/{id}", // URL with parameters
         new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
    );

    foreach (Route r in routes)
    {
        if (!(r.RouteHandler is SingleCultureMvcRouteHandler))
        {
            r.RouteHandler = new MultiCultureMvcRouteHandler();
            r.Url = "{culture}/" + r.Url;

           if (r.Defaults == null)
           {
               r.Defaults = new RouteValueDictionary();
           }
           r.Defaults.Add("culture", Culture.tr.ToString());

           if (r.Constraints == null)
           {
               r.Constraints = new RouteValueDictionary();
           }
           r.Constraints.Add("culture", new CultureConstraint(Culture.en.ToString(),
Culture.tr.ToString()));
        }
   }

}

Culture enum ve CultureConstraint class larımızıda oluşturalım.

public class CultureConstraint : IRouteConstraint
{
    private string[] _values;
    public CultureConstraint(params string[] values)
    {
        this._values = values;
    }

    public bool Match(HttpContextBase httpContext,Route route,string parameterName,
                        RouteValueDictionary values, RouteDirection routeDirection)
    {

        string value = values[parameterName].ToString();
        return _values.Contains(value);

    }

}
    public enum Culture
    {
        tr = 1,
        en = 2
    }

Dil değiştirme İşlemi

Dil değişikliği yapmak için aşağıdaki gibi basit bir Action ımız var. AccountController mıza koyabiliriz. İstersiniz HomeController a da koyabilirsiniz.

public ActionResult ChangeCulture(Culture lang, string returnUrl)
{
     if (returnUrl.Length >= 3)
     {
         returnUrl = returnUrl.Substring(3);
     }
     return Redirect("/" + lang.ToString() + returnUrl);
}

İkinci dil e geçmek için CultureSwitchControl.ascx adında bir partial view oluşturdum. Bununda kodu aşağıda ki gibi:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<%= Html.ActionLink("eng", "ChangeCulture", "Account",
    new { lang = (int)MvcLocalization.Helpers.Culture.en, returnUrl =
    this.Request.RawUrl }, new { @class = "culture-link" })%>

<%= Html.ActionLink("tr", "ChangeCulture", "Account",
    new { lang = (int)MvcLocalization.Helpers.Culture.tr, returnUrl =
    this.Request.RawUrl }, new { @class = "culture-link" })%>

Tek Dil

Eğer tek dile ihtiyaç duyacağımız sayfalar olursa onuda RouteHandler ını SingleCultureMvcRouteHandler olarak Global.asax ta tanımlamamız gerekecek.

routes.MapRoute(
          "AboutRoute",
          "About",
          new { controller = "Home", action = "About"}
   ).RouteHandler = new SingleCultureMvcRouteHandler();

Localization işlemi bu kadar.

Çok dilli web uygulaması yaparken karşınıza iki sorun daha çıkacak. Telaşlanmayın işin zor kısmını zaten hallettiniz. Geriye sayfa içinde ki sabit yazılar (örn. “Son Yazılar”,”Son Yorumlar”) ve dile göre değişecek resimler bannerler. Bu sorunu Resources Files kullanarak çok basit atlatabilirsiniz. Ancak resimler için tavsiyem 2 ayrı klasör oluşturup (tr ve en) adında dillere ait dosyalarınızı bu klasörlere atmanız ve sayfa içinde kullanacağınız zaman url deki parametreyle aynı olan dosya adınıza yol vermenizdir örneğin;

../../Content/tr/logo.jpg ve ../../Content/en/logo.jpg şeklinde url deki parametreyi sayfa içine taşırsanız(ister class yapın ister ViewData[“dil”] ile taşıyın farketmez) bu sorunu halledebilirsiniz.

Sabit yazılar içinse yine aynı yöntemi kullabilirsiniz fakat çok uzun sürebilir o yüzden tavsiyem Resources Files kullanmanızdır. bu konuda ufak bir araştırma ile çok sayıda dökümana ulaşabilirsiniz, üstelik kullanımı çok kolay

301 Yönlendirmesi Nasıl Yapılır

Bu yazımızda Asp.Net MVC ile 301 yönlendirmesi nasıl yapılacağını göreceğiz. Geçenlerde google da üst sıralarda bulunan bir sitemizin duplicate content ve gereksiz url uzaması yüzünden daha önce mantıklı gelen url yapısını (etiket/{etiketadi}/{etiketid}) değiştirmeye karar verdik. Fakat google indexlerimizin de silinmesi optimizasyon ve sitemizin sırasını etkileyebileceğinden 301 yönlendirmesi yapmaya karar verdik. Şimdi kısaca bunu nasıl yapılacağını göreceğiz. Aslında çok basit bir kaç ufak değişiklik.

Öncelikle site içinde verdiğimiz etiket linklerini yeni yapımızla yani /etiket/{etiketurl} şeklinde yeniden yapılandırıp çalışır hale getirelim. Daha sonra google ‘ın indexlediği yani arama sonuçlarında çıkan url yapısını yeni yapımıza yönlendirmemiz gerekiyor. Bunun için Global.asax dosyasını açıp eski url yapımızı yakalayıp bir Action da bunu 301 Redirect yönlendirmesi yaparak yeni url yapısına yönlendireceğiz.

routes.MapRoute(null,
“etiket/{tagName}”,
new { controller = “Home”, action = “Tags” }
);

routes.MapRoute(null,
“etiket/{tagName}/{id}”,
new { controller = “Home”, action = “TagsResolve” },
new { id = @“\d+” }
);

Yukarıda gördüğümüz route tanımlamalarında üstteki çalışmasını istediğimiz yeni yapı. Alttaki iste google sonuçlarında çıkan eski indexlerimizi yakalayıp TagResolve Action’ında yeni yapıya yönlendirme işlemi yapacağımızı belirttik. Şimdi TagResolve Action’ında nasıl 301 yönlendirmesi yapacağımıza bakalım.

301 Yönlendirmesi (301 Redirect) :

public ActionResult TagsResolve(int id)
{
string url = “/etiket/”;
url += db.Tags.Where(l => l.TagId == id).Single().Url;
Response.StatusCode = 301;
Response.RedirectLocation = url;
return new ContentResult();
}

Bu Action’ımız eski url yapısında gelen ziyaretçimizi yakalayıp yeni url yapımıza 301 Redirect yani 301 Yönlendirmesi yaparak google için yada sitenin sıralaması için endişelenmemize son veriyor.