CodeGym /Kurslar /C# SELF /Dərin dalış System.Text.Js...

Dərin dalış System.Text.Json-ə

C# SELF
Səviyyə, Dərs
Mövcuddur

1. Giriş

Bu dərsdə biz "mənə sadəcə siyahını saxla" səviyyəsindən çıxıb System.Text.Json ilə elastik, dəqiq və performanslı serialization-a doğru addım atacağıq. Müasir .NET layihələrində JSON — məlumat mübadiləsinin de-facto standartıdır. Əsas çağırışlar Serialize/Deserialize sadədir, amma real tapşırıqlar incə tənzimləmə tələb edir: sahələrin ignorlanması/yenidən adlandırılması, tarix formatlarının idarəsi, dövrlərə qarşı qorunma, böyük həcmli məlumatlarla iş, öz konverterlər və s.

Biz yalnız JsonSerializer metodlarını yox, həm də JsonSerializerOptions vasitəsilə parametrləri, atributları, Stream-lə işi, yaddaşın idarəsini və serialization qaydalarını özəl JsonConverter vasitəsilə necə vurğuladığını görəcəyik.

System.Text.Json-un qısa tarixi və mövqeyi

Uzun müddət .NET-də Newtonsoft.Json (Json.NET) hökmran idi — çevik və yetkin, amma həmişə ən sürətli və asılılıqları ən az olan deyildi. .NET Core 3.0 ilə birlikdə daxili System.Text.Json gəldi: yüksək performans, minimal asılılıqlar (platformaya daxil), ASP.NET Core ilə sıx inteqrasiya və .NET versiyaları ilə davamlı inkişaf.

2. Əsas siniflər və metodlar

Əsas element — statik sinif JsonSerializer, hansı ki iki istiqamət verir:

  • Serialization: obyekt → JSON-sətir (Serialize)
  • Deserialization: JSON-sətir → lazımi tipdə obyekt (Deserialize)

Sadə obyektin serialization nümunəsi

using System.Text.Json;

var person = new Person { Name = "İvan", Age = 30 };
string jsonString = JsonSerializer.Serialize(person);
Console.WriteLine(jsonString); // {"Name":"İvan","Age":30}

Deserialization nümunəsi

var json = "{\"Name\":\"Anna\",\"Age\":22}";
var anna = JsonSerializer.Deserialize<Person>(json);
Console.WriteLine(anna.Name); // Anna

Qeyd: Person tipi əvvəlki mühazirələrdə artıq implementasiya olunub — burada onu istifadə edirik.

3. Serialization-in idarəsi: JsonSerializerOptions

Real layihələrdə demək olar həmişə tənzimləmələr lazımdır: propertilərin adları camelCase, tarix formatları, dövrlərin emalı, default dəyərlər və s. Bütün bunlar JsonSerializerOptions vasitəsilə tənzimlənir.

Nümunə tənzimləmə

var options = new JsonSerializerOptions
{
    WriteIndented = true,    // JSON-ı gözəl formatlamaq (boşluq və sətir fasilələri əlavə edir)
    PropertyNameCaseInsensitive = true, // Deserialization zamanı propertilərin registrini nəzərə almamaq
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase // propertilər üçün camelCase (PascalCase əvəzinə)
};

string json = JsonSerializer.Serialize(person, options);
/*
{
  "name": "İvan",
  "age": 30
}
*/

Niyə bu vacibdir? Çoxlu frontend framework-lər məhz camelCase-i gözləyir, .NET-in standartı olan PascalCase yox.

4. Atributlar: System.Text.Json.Serialization

Bəzən serialization-u modelin üzərindən atributlarla idarə etmək daha rahatdır. Atributlar sahələrə/properties-ə əlavə olunur ki, adlara, daxil edilməyə/çıxarılmağa və dəyərin emalına təsir etsin.

Əsas atributlar

Atribut Necə işləyir
[JsonIgnore]
Property-ni serialization/deserialization-dan çıxarır
[JsonPropertyName("ad") ]
JSON-da başqa ad istifadə edir
[JsonInclude]
Non-public property/field-i serialization-a daxil edir
[JsonNumberHandling]
Rəqəmlərin emalını idarə edir

Nümunə: atributlarla property idarəsi

using System.Text.Json.Serialization;

public class Person
{
    [JsonPropertyName("full_name")]
    public string Name { get; set; }

    [JsonIgnore]
    public int SecretCode { get; set; }

    public int Age { get; set; }
}
var person = new Person { Name = "Pyotr", Age = 45, SecretCode = 123 };
string json = JsonSerializer.Serialize(person);
// {"full_name":"Pyotr","Age":45}

Nəzərə alın: SecretCode JSON-a düşmədi, Name isə "full_name" kimi serialize olundu.

5. Kolleksiyaların və daxili obyektlərin serialization-u

Kolleksiyalar — sadədir

var numbers = new List<int> { 1, 2, 3 };
string json = JsonSerializer.Serialize(numbers); // [1,2,3]

var people = new List<Person> {
    new Person { Name = "Anna", Age = 20 },
    new Person { Name = "Maksim", Age = 40 }
};
string jsonList = JsonSerializer.Serialize(people);
// [{"Name":"Anna","Age":20},{"Name":"Maksim","Age":40}]

Daxili strukturlar

public class Group
{
    public string Name { get; set; }
    public List<Person> Members { get; set; }
}

var group = new Group
{
    Name = "İnkişaf etdiricilər",
    Members = new List<Person>
    {
        new Person { Name = "Sasha", Age = 23 },
        new Person { Name = "Masha", Age = 28 }
    }
};

string jsonGroup = JsonSerializer.Serialize(group, options);
/*
{
  "name": "İnkişaf etdiricilər",
  "members": [
    { "name": "Sasha", "age": 23 },
    { "name": "Masha", "age": 28 }
  ]
}
*/

6. Deserialization: nəyə diqqət etmək lazımdır?

var json = "[{\"Name\":\"İvan\",\"Age\":21}]";
var list = JsonSerializer.Deserialize<List<Person>>(json);
Console.WriteLine(list[0].Name); // İvan

Tez-tez rast gəlinən ssenari: əgər JSON-da hansısa sahə yoxdursa, uyğun property default dəyər alacaq. JSON-da modeldə olmayan əlavə sahələr yox sayılır. Amma tiplər uyğun gəlməzsə (məsələn, sayı gözləyəndə string gəlsə) — deserialization zamanı exception atılacaq.

7. Tarixlərin, zamanın, formatların və ədədi dəyərlərin emalı

public class Meeting
{
    public string Topic { get; set; }
    public DateTime Time { get; set; }
}

var meeting = new Meeting { Topic = "Toplantı", Time = DateTime.Now };
string json = JsonSerializer.Serialize(meeting);
// {"Topic":"Toplantı","Time":"2024-06-06T20:30:00.0000000+03:00"}

Default olaraq DateTime ISO 8601 formatında serialize olunur. Başqa görünüş (məsələn, yalnız tarix) lazımdırsa, ayrı property və ya custom converter istifadə edin (aşağıya bax).

FAQ: Ədədlərin string kimi serialize olunmasını (məsələn, telefon nömrələri və ya böyük ID-lər) istəyirsinizsə, [JsonNumberHandling(JsonNumberHandling.WriteAsString)] atributundan istifadə edin.

8. Stream-lər və fayllarla iş

İş yalnız sətirlərlə deyil, həm də Stream-lərlə aparıla bilər — bu böyük məlumatlar (fayllar, şəbəkə) üçün vacibdir.

Fayla yazmaq nümunəsi

using var fs = File.Create("person.json");
JsonSerializer.Serialize(fs, person);
// Unutmayın fs.Flush() çağırmaq və ya using istifadə etmək!

Fayldan oxuma nümunəsi

using var fs = File.OpenRead("person.json");
var restored = JsonSerializer.Deserialize<Person>(fs);

Stream-lərlə asinxron metodlar da mövcuddur: SerializeAsync/DeserializeAsync — yüksək yüklü servislər üçün faydalıdır.

9. Custom konverterlər

Əgər standart qaydalar uyğun gəlmirsə (qeyri-standart tarix/ədəd formatları, mürəkkəb dəyərlər, öz strukturlar) — JsonConverter yazırsınız.

Nümunə: tarix yalnız "dd.MM.yyyy" kimi

public class CustomDateConverter : JsonConverter<DateTime>
{
    public override DateTime Read(
        ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return DateTime.ParseExact(reader.GetString(), "dd.MM.yyyy", null);
    }

    public override void Write(
        Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString("dd.MM.yyyy"));
    }
}

var options = new JsonSerializerOptions();
options.Converters.Add(new CustomDateConverter());

var dt = new DateTime(2024, 6, 1);
string json = JsonSerializer.Serialize(dt, options); // "01.06.2024"

Custom konverterlər koordinatlar, vektorlar, rənglər, qeyri-standart tarixlər və valyutalar, müxtəlif ID-formatlar və s. üçün faydalıdır.

10. Faydalı nüanslar

Dövri istinadların və dərin iyerarxiyaların emalı

var options = new JsonSerializerOptions
{
    ReferenceHandler = ReferenceHandler.Preserve, // Bütün obyektləri $id/$ref ilə saxlayır
    WriteIndented = true
};

Vacib: JSON-a xidmətçi property-lər $id və $ref əlavə olunacaq. Xarici sistemlərlə mübadilədə onlar başa düşülməyə bilər.

System.Text.Json və Newtonsoft.Json arasındakı fərqlər

System.Text.Json artıq kifayət qədər güclüdür, amma hələ Newtonsoft.Json-un bəzi ssenarilərini tam əhatə etmir (məsələn, private konstrukturlar, mürəkkəb dynamic obyektlər və s.). Əksər standart tapşırıqlar üçün daxili serializer-i tövsiyə edirəm — o daha sürətlidir və əlavə asılılıqlara ehtiyac yoxdur.

JSON-la interaktiv iş: DOM API

Tam model olmadan JSON üzərində gəzmək lazım gəldikdə, JsonDocument və JsonElement-dən istifadə edin.

using var doc = JsonDocument.Parse(jsonString);
JsonElement root = doc.RootElement;

if (root.TryGetProperty("Name", out var nameProperty))
{
    Console.WriteLine(nameProperty.GetString());
}

11. Faydalı opsiyalar və onların effektləri

Property Dəyər/Təyinat
WriteIndented
true — indent-lə formatlama
PropertyNameCaseInsensitive
true — deserialization zamanı properti adlarının registrini nəzərə almamaq
PropertyNamingPolicy
JsonNamingPolicy.CamelCase
DefaultIgnoreCondition
null/dəyərlər üçün ignore qaydaları
ReferenceHandler
Preserve
,
IgnoreCycles
AllowTrailingCommas
true — array-ın sonunda vergülü icazə ver
NumberHandling
Ədədlərin string-ə/əksinə çevrilməsi (və s.)
Converters
Custom konverterlərin siyahısı

12. Tez-tez rastlanan səhvlər və praktik məsləhətlər

Səhv №1: deserialization zamanı yanlış tip. Əgər siyahını serialize etmisinizsə, mütləq siyahıya deserialize edin: List<T>, tək obyektə yox.

Səhv №2: properti adlarının registi ilə bağlı problem. Registrə həssaslıq olmadan propertilər "tapılmaya" bilər. PropertyNameCaseInsensitive-dən istifadə edin və ya PropertyNamingPolicy-u tənzimləyin.

Səhv №3: tarixlərin düzgün emal olunmaması. Default format ISO 8601-dir. Başqa format lazımdırsa — JsonConverter<DateTime> yaradın və tətbiq edin.

Səhv №4: private/static sahələrin serialize olunacağını gözləmək. Default olaraq public propertilər götürülür. Nadir hallarda atributlar (məsələn, [JsonInclude]) istifadə edin.

Səhv №5: default dəyərlərin anlaşılmaması. JSON-da olmayan sahə → property üçün default dəyər. Bu məntiqdə nəzərə alınmalıdır.

Səhv №6: stream-lərin səhv idarə olunması. Resursları using və ya await using ilə bağlayın ki, leak və bloklanma olmasın.

2
Tapşırıq
C# SELF, səviyyə, dərs
Bağlanıb
JsonSerializerOptions ilə obyektin seriyalaşdırılması
JsonSerializerOptions ilə obyektin seriyalaşdırılması
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION