C# İle Asenkron Veritabanı Bağlantısı Nasıl Yapılır?

C# İle Asenkron Veritabanı Bağlantısı Nasıl Yapılır?
C# İle Asenkron Veritabanı Bağlantısı Nasıl Yapılır?

Ön Hazırlık ve Gereksinimler

Asenkron veritabanı işlemleri için geliştirme ortamınızın güncel olması gerekmektedir. .NET 8 veya üzeri bir sürüm kullanmanız, asenkron kütüphanelerin tam performansla çalışması için kritiktir. Ayrıca, veritabanı sürücülerinizin (SQL Server için Microsoft.Data.SqlClient gibi) en güncel sürümde olduğundan emin olun.

  • SDK: .NET 9 veya .NET 8 SDK.
  • IDE: Visual Studio 2022 veya JetBrains Rider.
  • Kütüphane: Entity Framework Core (EF Core) veya Dapper.
  • Veritabanı: SQL Server, PostgreSQL veya MySQL.

Asenkron Programlama Temelleri: Async ve Await

C# dilinde asenkron işlemler, Task ve Task sınıfları etrafında döner. Bir metodu asenkron hale getirdiğinizde, o metodun tamamlanmasını beklerken ana iş parçacığı (UI veya istek işleyen thread) serbest kalır. Aşağıdaki örnek, basit bir asenkron metot yapısını göstermektedir.

public async Task VeriGetirAsync()
{
    await Task.Delay(1000); // Simüle edilmiş bekleme süresi
    return "Veri başarıyla getirildi.";
}

Burada async anahtar kelimesi metodun asenkron çalışacağını, await ise işlemin tamamlanana kadar bekleyip sonucu alacağını belirtir. Bu yapı, veritabanı sorgularında da aynı şekilde kullanılır.

Entity Framework Core ile Asenkron Sorgulama

Entity Framework Core, asenkron işlemler için yerleşik destek sunar. Sorguları çalıştırırken ToList() yerine ToListAsync(), FirstOrDefault() yerine FirstOrDefaultAsync() metodlarını kullanmalısınız. Bu, veritabanı sunucusundan yanıt gelene kadar uygulamanın askıda kalmasını önler.

public async Task TumUrunleriGetirAsync(UygulamaDbContext context)
{
    // Veritabanı sorgusunu asenkron olarak çalıştırır
    return await context.Urunler.ToListAsync();
}

Bu yöntem, veritabanı bağlantısı sırasında sunucunun meşgul olması durumunda uygulamanızın diğer isteklere yanıt vermeye devam etmesini sağlar.

ADO.NET ile Asenkron Veritabanı Bağlantısı

Daha düşük seviyeli bir kontrol istiyorsanız veya EF Core kullanmıyorsanız, Microsoft.Data.SqlClient kütüphanesi ile doğrudan asenkron bağlantı kurabilirsiniz. OpenAsync() ve ExecuteReaderAsync() metodları burada temel taşlardır.

using (SqlConnection baglanti = new SqlConnection(connectionString))
{
    await baglanti.OpenAsync();
    
    string sorgu = "SELECT Ad, Soyad FROM Kullanicilar WHERE Id = @Id";
    using (SqlCommand komut = new SqlCommand(sorgu, baglanti))
    {
        komut.Parameters.AddWithValue("@Id", 1);
        using (SqlDataReader okuyucu = await komut.ExecuteReaderAsync())
        {
            while (await okuyucu.ReadAsync())
            {
                Console.WriteLine(okuyucu["Ad"]);
            }
        }
    }
}

Bu kod bloğunda, bağlantı açma ve veriyi okuma işlemleri asenkron olarak gerçekleştirilir. await kullanımı sayesinde, veritabanı işlemleri bitene kadar CPU başka işlerle ilgilenebilir.

Asenkron İşlemlerde Güvenlik ve SQL Injection Koruması

Asenkron kod yazmak, güvenlikten ödün vereceğiniz anlamına gelmez. Veritabanı işlemlerinde her zaman parametreli sorgular kullanmalısınız. Asenkron metotlarda da AddWithValue veya SqlParameter kullanarak SQL Injection saldırılarını engelleyebilirsiniz.

Kritik Güvenlik Uyarısı: Asenkron metotlarda asla kullanıcıdan gelen veriyi doğrudan sorgu metnine eklemeyin. Her zaman parametreli (parameterized) sorgu yapısını kullanın. Aksi takdirde, uygulamanız SQL Injection saldırılarına açık hale gelir.

Asenkron ve Senkron Yöntemlerin Karşılaştırılması

Aşağıdaki tablo, senkron ve asenkron yöntemlerin temel farklarını özetlemektedir.

Özellik Senkron (Sync) Asenkron (Async)
Thread Kullanımı İşlem bitene kadar thread'i bloklar İşlem bitene kadar thread'i serbest bırakır
Ölçeklenebilirlik Düşük (Trafik arttıkça tıkanır) Yüksek (Daha fazla eşzamanlı istek)
Kod Karmaşıklığı Basit Biraz daha yüksek (Async/Await yönetimi)

Sıkça Sorulan Sorular

Asenkron metotlarda neden "void" döndürülmemeli?

Asenkron metotlarda void kullanmak, işlemin tamamlanıp tamamlanmadığını takip etmeyi imkansız kılar ve hata yönetimini zorlaştırır. Her zaman Task veya Task döndürmelisiniz.

Her veritabanı sorgusunu asenkron yapmalı mıyım?

Çok hızlı gerçekleşen (örneğin bellek içi işlemler) sorgular için asenkron yapı kurmak ek yük (overhead) getirebilir. Ancak veritabanı bağlantısı gibi dış kaynaklı işlemler için asenkron yapı her zaman tercih edilmelidir.

"ConfigureAwait(false)" nedir ve neden kullanılır?

Kütüphane geliştirirken veya UI thread'ine bağımlı olmayan kodlarda ConfigureAwait(false) kullanarak, işlemin orijinal context'e dönmesini engelleyebilir ve performans artışı sağlayabilirsiniz.

Asenkron kodda hata yönetimi nasıl yapılır?

Asenkron metotları try-catch blokları içerisine alarak, standart senkron kodlardaki gibi hataları yakalayabilir ve yönetebilirsiniz.

C# 12/13 ve sonrası asenkron yenilikleri nelerdir?

Yeni sürümlerde asenkron akışlar (IAsyncEnumerable) ile veritabanından büyük veri setlerini parça parça ve belleği yormadan çekmek çok daha kolay hale gelmiştir.

Sorumluluk Reddi: Bu makaledeki kod örnekleri eğitim amaçlıdır. Üretim ortamında (production) veritabanı şifrelerinizi kod içerisinde saklamayın; mutlaka Environment Variables veya Azure Key Vault gibi güvenli yönetim araçlarını kullanın.

Asenkron Veritabanı İşlemlerinde Performans İzleme ve Profilleme

Asenkron programlama, uygulamanın yanıt süresini iyileştirse de, yanlış yapılandırılmış bir asenkron akış "thread pool starvation" (iş parçacığı havuzu tükenmesi) gibi ciddi performans sorunlarına yol açabilir. Veritabanı işlemlerinizin gerçek dünya performansını ölçmek için izleme araçlarını (APM) kullanmak kritik öneme sahiptir.

Özellikle Task.WhenAll kullanımı sırasında çok sayıda veritabanı sorgusunu aynı anda tetiklemek, veritabanı bağlantı havuzunuzun (connection pool) hızla dolmasına neden olabilir. Bu durumu yönetmek için SemaphoreSlim kullanarak eşzamanlı istek sayısını sınırlayabilirsiniz.

// Eşzamanlı veritabanı isteğini 5 ile sınırlayan örnek
private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(5);

public async Task ProcessDataAsync(List ids)
{
    var tasks = ids.Select(async id =>
    {
        await _semaphore.WaitAsync();
        try
        {
            return await _dbContext.Users.FindAsync(id);
        }
        finally
        {
            _semaphore.Release();
        }
    });

    await Task.WhenAll(tasks);
}

Asenkron Kodlarda Birim Test (Unit Testing) Stratejileri

Asenkron metotların test edilmesi, senkron metotlara göre daha fazla dikkat gerektirir. Özellikle Task döndüren metotlarda, testin tamamlanmasını beklemek için await anahtar kelimesini test metotlarınızda da kullanmalısınız. Modern test kütüphaneleri (xUnit, NUnit gibi) artık async Task dönüş tipine sahip test metotlarını doğrudan desteklemektedir.

Veritabanı bağımlılıklarını test ederken, gerçek bir veritabanı yerine InMemory sağlayıcıları veya Moq kütüphanesi ile sahte (mock) nesneler kullanmak, testlerinizi izole ve hızlı tutmanızı sağlar.

[Fact]
public async Task GetUserById_ShouldReturnUser_WhenExists()
{
    // Arrange
    var options = new DbContextOptionsBuilder()
        .UseInMemoryDatabase(databaseName: "TestDb")
        .Options;

    using var context = new AppDbContext(options);
    context.Users.Add(new User { Id = 1, Name = "Test User" });
    await context.SaveChangesAsync();

    // Act
    var service = new UserService(context);
    var result = await service.GetUserAsync(1);

    // Assert
    Assert.NotNull(result);
    Assert.Equal("Test User", result.Name);
}

Testlerde Dikkat Edilmesi Gereken İpuçları

  • Timeout Yönetimi: Asenkron testlerinizde CancellationTokenSource kullanarak, veritabanı sorgusunun sonsuza kadar takılı kalmasını engelleyen zaman aşımı süreleri tanımlayın.
  • State Temizliği: Her test metodundan sonra EnsureDeletedAsync() veya benzeri yöntemlerle veritabanı durumunu sıfırlayarak testler arası bağımlılığı ortadan kaldırın.
  • Exception Testleri: Asenkron metotların fırlattığı hataları yakalamak için Assert.ThrowsAsync yapısını kullanın.

Sonuç

C# ile asenkron veritabanı bağlantısı kurmak, uygulamanızın ölçeklenebilirliği ve performansı için vazgeçilmez bir yetkinliktir. async ve await anahtar kelimelerini doğru kullanarak, kaynakları verimli tüketen ve kullanıcıya hızlı yanıt veren uygulamalar geliştirebilirsiniz. Bir sonraki adım olarak, veritabanı işlemlerinizde IAsyncEnumerable kullanarak büyük veri setlerinin asenkron olarak nasıl işleneceğini araştırmanızı öneririm.

Bu yazıya tepkinizi paylaşın:
Selin Korkmaz

Kendin yap (DIY) projeleri ve sürdürülebilir yaşam ipuçları üzerine odaklanıyorum. Okuyucularıma bütçe dostu ve yaratıcı çözüm önerileri sunmaktan keyif alıyorum.

Yorumlar (0)

Yorum Yaz