İçeriğe geç

Asp.Net Web API’da Accept-Language ile Localization

Merhaba arkadaşlar.

Yine bir Web API makalesi ile buradayım. Bir süredir ocak ayı içerisinde çıkacak olan Web API kitabi üzerinde yoğun olarak çalışmaktayız. Bu süre zarfında bloğumuda boş bırakmamak adına, Web API içerisinde Localization işlemleri adına bir makale yayınlamak istedim. Haydi bir bakalım nasıl oluyormuş?

Asp.NET Web API’da client’ın Accept-Language header bilgisini kullanarak, server’a göndermiş olduğu language parametrelerini Asp.Net Web API içerisinde nasıl handle edebileceğimizi bir örnek üzerinden inceleyeceğiz.

Öncelikle örneğimizde kullanacağımız Customer model’ini tanımlayalım:

namespace WebAPILocalization.Models
{
    public class Customer
    {
        public string Name { get; set; }
        public string Email { get; set; }
    }
}

Customer model’ini oluşturduktan sonra, örneğimiz için olan statik dil verilerini tutabilmek için solution üzerine App_GlobalResources isimli Asp.Net Folder’ını ekleyeceğiz ve içerisine iki adet “WebApiResource.resx” ve “WebAPIResource.en-US.resx” isimli resource item’larını tanımlıyor olacağız. İlk olarak bizim için default resource bilgisi olarak kabul edeceğimiz Türkçe içeriklerin yer alacağı “WebAPIResource.resx” isimli resource dosyasını ekleyelim ve içeriğini aşağıdaki şekildeki gibi girelim:

webapiresource

Şimdi İngilizce içeriklerin yer alacağı “WebAPIResource.en-US.resx” isimli resource dosyasını ekleyelim ve bununda içeriğini aşağıdaki gibi girelim:

webapiresource-enUS

Statik dilleri tuttuğumuz resource dosyalarını oluşturduktan sonra aşağıdaki gibi bir solution yapısı olacaktır.

solution

Resource’ları tamamladıktan sonra şimdi client üzerinden gelecek olan Accept-Language header bilgisini alıp, API tarafında o dil bilgisi destekleniyor ise, culture bilgisini o dil bilgisine göre güncelleyeceğiz. Bu sayede statik resource’lar güncellenen culture bilgisine göre geriye değer döneceklerdir.

Culture bilgisini handle edebilmek için ise yeni bir MessageHandler oluşturacağız. Oluşturacak olduğumuz handler’ı System.Net.Http.DelegatingHandler’dan türeteceğiz ve SendAsync method’unu override ederek, request üzerinde gönderilen Accept-Language bilgilerine ulaşacağız. Dilerseniz şimdi LocalizationMessageHandler isminde bir handler oluşturalım:

using System.Collections.Generic;
using System.Net.Http;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;

namespace WebAPILocalization.Handlers
{
    public class LocalizationMessageHandler : DelegatingHandler
    {
        private readonly List<string> _supportedLanguages = new List<string>() { "tr-TR", "en-US" };

        protected override async Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request, CancellationToken cancellationToken)
        {
            SetCulture(request);

            var response = await base.SendAsync(request, cancellationToken);
            return response;
        }

        #region Private Methods
        private void SetCulture(HttpRequestMessage request)
        {
            foreach (var loopLanguage in request.Headers.AcceptLanguage)
            {
                // Desteklediğimiz dillerden biri var ise culture bilgisini o dile göre güncelliyoruz.
                if (_supportedLanguages.Contains(loopLanguage.Value))
                {
                    Thread.CurrentThread.CurrentCulture = new CultureInfo(loopLanguage.Value);
                    Thread.CurrentThread.CurrentUICulture = new CultureInfo(loopLanguage.Value);

                    break;
                }
            }
        }
        #endregion
    }
}

Kod bloğunda gördüğümüz gibi SendAsync method’unu override edip, içerisinden private olarak oluşturmuş olduğumuz SetCulture method’unu çağırıyoruz ve tekrardan base’deki SendAsync method’unu çağırarak request’i inner handler’a aktarıyoruz . SetCulture method’u içerisinde ise request’in headers kısmında gönderilen Accept Language listesi üzerinde bir iterate işlemi yaparak, sırasıyla gelen dil bilgisini private olarak yukarıda tanımlamış olduğumuz supportedLanguages” listesi üzerinden kontrol ederek, eğer gelen dil bilgisi “supportedLanguages” listesi içerisinde var ise, culture bilgisini bu dil bilgisine göre güncelliyoruz ve iterate işlemine son veriyoruz.

Bir önceki bölüm olan “Accept-Language Header’ı Anlamak” kısmında bahsettiğimiz gibi client birden fazla dil bilgisi parametresi gönderebilmekteydi. Burada yapmış olduğumuz işlem ise, client’ın istediği ilk dil bilgisine göre geriye response dönebilmektir.

Şimdi oluşturmuş olduğumuz LocalizationMessageHandler’ın pipeline içerisinde devreye girebilmesi için WebApiConfig içerisinde MessageHandlers listesine eklememiz gerekmektedir.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MessageHandlers.Add(new LocalizationMessageHandler());
    }
}

LocalizationMessageHandler’ı pipeline’a register ettikten sonra, örneğimizi deneyebilmek için CustomerController’ı aşağıdaki gibi oluşturalım:

public class CustomerController : ApiController
{
    public Customer Get()
    {
        return new Customer()
        {
            Name = Resources.WebAPIResource.NameField,
            Email = Resources.WebAPIResource.EmailField
        };
    }
}

Controller’ıda hazırladık ve şimdi Fiddler üzerinden test işlemine başlayabiliriz. Fiddler üzerinden göndereceğimiz Accept-Language header bilgisine göre controller üzerinden Customer objesinin Name ve Email alanlarının istenilen dil bazında resource üzerinden gelmesini beklemekteyiz.

Fiddler üzerinden API’nin Get method’unu Accept-Language header bilgisini “tr-TR” şeklinde girerek aşağıdaki gibi çağıracağız:

accept-language

API’nin Get method’unu Fiddler üzerinden execute etmeden önce LocalizationMessageHandler’ın SetCulture method’una breakpoint koyup sonrasında ise execute ettiğimizde henüz request, controller’a iletmeden önce LocalizationMessageHandler’ın SetCulture method’unun devreye girdiğini ve AcceptLanguage property’sininde “tr-TR” olarak set edildiğini aşağıdaki ekranda görebiliriz.

message-handler

Request, LocalizationMessageHandler’dan çıktıktan sonra CustomerController’a gelip, Get method’una düşmektedir.  LocalizationMessageHandler içerisinde kullanıcının göndermiş olduğu Accept-Language bilgisine göre Thread üzerindeki Culture bilgisini güncellediğimiz için, CustomerController’ın Get method’u içerisindeki Resource’lar değerlerini getirirken, istenilen culture bilgisine göre getirmektedirler ve aşağıdaki gibi bir response oluşmaktadır:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?YzpcdXNlcnNcZ8O2a2FscFxkb2N1bWVudHNcdmlzdWFsIHN0dWRpbyAyMDE1XFByb2plY3RzXFdlYkFQSUxvY2FsaXphdGlvblxXZWJBUElMb2NhbGl6YXRpb25cYXBpXGN1c3RvbWVyXA==?=
X-Powered-By: ASP.NET
Date: Thu, 19 Nov 2015 20:48:34 GMT
Content-Length: 87

{"Name":"Bu bir isim alanıdır. (tr-TR)","Email":"Bu bir e-posta alanıdır. (tr-TR)"}

Client Accept-Language bilgisinde “tr-TR” yerine “en-US” olarak bir header bilgisi gönderirse eğer, response aşağıdaki gibi oluşacaktır:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?YzpcdXNlcnNcZ8O2a2FscFxkb2N1bWVudHNcdmlzdWFsIHN0dWRpbyAyMDE1XFByb2plY3RzXFdlYkFQSUxvY2FsaXphdGlvblxXZWJBUElMb2NhbGl6YXRpb25cYXBpXGN1c3RvbWVyXA==?=
X-Powered-By: ASP.NET
Date: Thu, 19 Nov 2015 21:05:29 GMT
Content-Length: 81

{"Name":"This is a name field. (en-US)","Email":"This is a email field. (en-US)"}

JSON result’lara baktığımızda ise gelen verinin client’ın istemiş olduğu dil bilgisi doğrultusunda geldiğini görebilmekteyiz. Umarım faydalı bir makale olmuştur. Bu konunun devamına ve daha detaylı incelemesine, çıkacak olan Web API kitabımız üzerinden erişebiliyor olacaksınız. 🙂

Uygulamaya aşağıdan ulaşabilirsiniz.

WebAPILocalization

 

Kategori:Asp.Net Web API

6 Yorum

  1. serdar serdar

    handle etmek demek 🙂

  2. Onur Onur

    Merhaba Gokhan Bey,

    Daha once yazdiginiz ‘token based authentication’ yazisindan yararlanarak admin authentication’i gerektiren bir web api projesi uzerinde calisiyorum. Bugun proje’ ye buradaki paylasiminizi da okuyarak resource dosyalari ekledim. Resource dosyalarim butun controller class’larim icin sorunsuz calisirken, authentication alirken sadece Turkce mesaj donuyor. Resource dosyalarini defalarca incelememe ve test etmeme ragmen bir sorun goremedim. Acaba authentication class’ina eklemem gereken bir kod parcasi veya benim gozden kacirdigim bir nokta mi var? Gerekli arastirmalari yaptim ancak tatmin edici bir sonuca ulasamadigim icin size yazmaya karar verdim.

    Ilginiz ve paylasimlariniz icin tesekkurler,
    Onur

    • Onur Onur

      Ayni sekilde WebApiConfig class’ina da bir degisiklige gitmem gerekebilir. Son not olarak projemde Odata’ yi kullaniyorum

    • Merhaba, sorununuzu şuan deneyebilecek bir ortamım yok fakat, GrantResourceOwnerCredentials method’unu override ettiğinizde, orada context üzerinde “SetError” method’u kısmında hata mesajını resource’dan aldınız mı ve Header üzerinden Accept-Language bilgisi geliyor mu?

  3. ibrahim ibrahim

    merhaba,
    localresources dil dosyaları oluşturdum fakat sayfaların her session için cache den yüklenmesini istiyorum. nasıl yapabilirim?

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.