Newtonsoft JsonConvertor’u Özelleştirerek Uygulamada Kolaylıklar Sağlama

Selamlar,

Bugünkü makalede şirketin ihtiyacı olan bir konudan bahsetmek istiyorum. 3th Party bir servisten aldığımız bir endpoint’i Deserialize sırasında Türkçe isimlendirme ile gelen “Konu” property’sini => “Subject”e çevirmemiz gerekti. Ayrica gelen bazı Text dataları, manipule ederek değiştirmemiz gerekiyordu. Bunun için AutoMapper gibi tolların kullanılması ve çekilen datanın Editlenmesi gibi angarya işlemlerden kurtulmak amacı ile Newtonsoft’un

JsonConverter” sınıfını ihtiyaçlarımız doğrultusunda güncelledik. İlk aklınıza neden System.Text.Json değil de Newtonsoft gelebilir :) Nedeni basit, böylesine eski ve büyük projenin heryerinde Newtonsoft kullanılmışdı da ondan :)

Öncelikle “CustomJsonConvertor” adında yeni bir Class Library oluşturuyoruz. Proje .Net 8.0 ile oluşturulmuş ve okuma hızı cok yüksek olan “FrozenDictionary” ve “Primary Constructors” gibi güncel teknolojiler kullanılmıştır.

Custom Serialization

1-) Sınıfımızı => “JsonConvertor” sınıfından inherit ediyoruz. Gelen string içeriklerdeki değişecek keywordleri “key-value” olarak FrozenDictionary ile alıyoruz. Çünkü yazma mağliyeti yüksek olsa da, okuma mağliyeti inanilmaz performanslı. Frozen dictionary hakkında daha detaylı bilgiye(Benchmark Test) burdaki sunumumdan erişebilirsiniz. Ayrıca CustomJsonConvertor için Constructor oluşturmadan ilgili parametreleri default olarak alıyoruz. Buna da Primary Constructor diyoruz.

2-) JsonConvert sınıfının “WriteJson()” methodu override edilir. Bu method Newtonsoft kütüphanesinin Serialize işlemi sırasında kullanılır.

  • İlk önce “JToken.FromObject(value)” ile ilgili gönderilen nesne alınır.
  • “t.Type” ile nesenenin Complex Type mı yoksa string gibi primitive type mi olduğuna bakılır.
  • “t.WriteTo(writer)” complex type değil ise doğrudan yazılır.

3-) Eğer gelen value complex bir type ise yani sınıf ise,

  • “JObject o” ile json object alinir. Bu nesneyi aynı reflection ile olduğu gibi incelememize olanak sağlar.
  • “o.Properties().Select(p=>p.Name).ToList()” ile ilgili sınıfın tüm property isimleri “propertyNames“‘e atanır.
  • “o.Properties().ToList().ForEach” ile tüm property isimleri loop içinde gezilir.

4-) “_replacment.ToList().ForEach()(r=>” Eğer FrozenDictionary ile parametre olarak geçtiğimiz değişecek içerikler null değil ise, yani “_replacment” null değil ise, ilgili dictionary loop içinde gezilir.

  • “p.Value.Type==JTokenType.String” serialize edilecek sınıfın içinde dönülen ilgili propertysi string ise.
  • “p.Value.ToString().ToLower().Contains(r.Key))” Sınıfa ait property’nin value değeri, dictionary içinde geçen string keylerden birini içeriyor ise.
  • “p.Value=p.Value.ToString().ToLower().Replacment(r.Key,R.Value)” Sınıfın ilgili property değeri, dictionary içinde geçen key’in valuesu ile değiştirilir.

Böylece ilgili içerik serialize edilirken, tanımlanan string değerler ile manipule edilmiş olunur.

5-) İçeriklerin manipule edilmesinden başka ayrıca spesifik olarak “Konu” şeklinde gönderilen property ismi, Automapper’a ihtiyaç duyulmadan “Subject” property ismine dönüştürülür. Global bir tool yapılmak istense, bu değişecek property isimleri de aynı property valuelarında olduğu gibi, bir Frozen Dictionary ile paramterik olarak alınabilirdi.

6-) Son olarak tamamen size çarpıcı bir örnek olması adına, serialize edilecek sınıfın tüm property isimleri string içeriğin içine “Keys:” keywordü ile aşağıdaki gibi json ciktiya yazılmaktadır.

BoraJsonConvertor.cs/ Serialize(): Yukarıda anlatilan kodun tamamı.

Örnek SentMail sınıfının Custom Newtonsoft.Serialize çıktısı:

Örnek Kullanım Şekli:

SentMail.cs: Örnek amaçlı, aşağıda görüldüğü gibi SentMail sınıfını yukarıda tanımlanan şekilde bir Controller’a ait Action içinde, Custom Serialize edip geri dönelim.

CustomSerializeController/GetCustomSerialize(): Aşağıda görüldüğü gibi ilgili web servisi içinde SentMail sınıfı propertyleri, örnek bir data ile doldurulmuştur. Bunu, makale başında anlatılan 3th Party bir servis olarak düşünebilirsiniz. Senaryoya uyma amaçlı “Konu” adında türkçe kolon ismi verilmiştir. Serialization’dan sonra ilgili model sisteme dahil edilirken, “Subject” olarak değiştirilecektir. Ayrıca “replaceDic” dictionary ile manupule edilecek içerikler tanimlanmiş ve JsonConvert.SerializeObject() methoduna parametre olarak gönderilmiştir.

Çıktı: Aşağıda görüldüğü gibi içerikteki tüm “Bora“lar => “Bill‘ ve “Kasmer“ler => “Gates” olarak değiştirilmiştir. Ayrıca “Konu” olarak gelen kolon ismi => “Subject” olarak değişitirilmiştir.

Custom Deserialization

String olarak aldığımız bir sınıfı, deserialize ederken kendi modelimize uygun bir hale getirmek isteyebiliriz. Bunu, Automapper gibi toollar kullanmadan Newtonsoft kütüphanesi içinde tamamlayabiliriz. Hatta istersek, propertylere atanan value değerlerini de değiştirebiliriz.

1-) Gelen reader.TokenType yani okunan nesnenin tipi null ise geriye boş string dönülmüştür. Eğer gelen tip string ise, nesne Deserialize edilip geri dönülür.

2-) Eğer reader.Type sınıf ise, ilgili JObject yüklenir ve “Subject” propertysi => “Konu” propertisi olarak tekrardan değiştirilir. Böylece Automapper olmadan gelen property ismi istenen bize uygun bir property ismine çevrilmiş olunur. Burada şuna değinmek istiyorum, aynı Automapperda olduğu gibi maplenecek kolonlar bir config dosyada tanımlanıp bu sınıfa property olarak verilebilir. Bu örnekte, değişecek valuelar, paramtere olarak dictionary şeklinde alınmış ve ilgili küme içinde gezilerek replace işlemi yapılmıştır. Aynı durum propertyler için de geçerlidir.

3-)Değişecek valueları tutan ForzenDictionary yani _replacment değişkeni null değil ise, tüm liste gezilerek, bu örnek için sadece “From” propertisinin içeriği değiştirilmiştir. Kısaca “Bill” => “bora“, “Gates” => “kasmer” olarak değiştirilecektir.

4-) Son olarak üzerinde işlem yapılan “obj” => “Object” belirtilen objectType’a dönüştürülüp geri dönülmektedir.

BoraJsonConvertor.cs/ Deserialize(): Yukarıda anlatilan kodun tamamı.

Örnek Kullanım Şekli:

Gelin önce SentMail bir kaydı Serializa sonra da Deserializa edip, yaptığımız değişikliklerin sonucunu görelim.

 Serialize işlemindn sonra aşağıda görüldüğü gibi tüm “Bora“lar “Bill“‘e dönüşmüştür. Ayrıca “Konu“, “Subject” olarak değişmiştir.=> var result = JsonConvert.SerializeObject(mail, Formatting.Indented, new BoraJsonConvertor(dicReplacment, typeof(SentMail)));

Deserialization

Aşağıda görüldüğü gibi, yukarıdaki Serialize işleminden sonra Deserialize işleminde sadece “from“‘daki Bill => Bora’ya dönmüştür. Ayrıca “Subject” tekrardan “Konu” olmuştur.

Geldik bir makalenin daha sonuna. Bu makalede Custom Serialization ve Deserialization üzerinde durduk. Bir sinifi serialization sirasinda istedigimiz gibi hem datasini hem de filedlarini manipule edebiliyoruz. Bu da bize örneğin gerçekçi bir örnek vermek gerekirse, güvenlik amacı ile sensitive dataları maskelemek ve mesla email alanına * koymak için kullanılabilir. “bo******@***.com” gibi. Ayrıca deserializa sırasında ayrıca bir kütüphen kullanmadan mesle Automapper gibi, bizde karşılığı farklı olan kolon isimlerini değiştirebiliriz. Mesela bu makalede “Konu” => “Subject“‘e çevrilmiştir. Böylece istenen kolon, ayrıca bir tool kullanılmadan sisteme dahil edilmiştir.

Yeni bir makalede görüşmek üzere hepinize hoşçakalın.

Gist:

Source: https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm

 

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.