Ledbim.Redis 1.0.0

dotnet add package Ledbim.Redis --version 1.0.0
                    
NuGet\Install-Package Ledbim.Redis -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Ledbim.Redis" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Ledbim.Redis" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Ledbim.Redis" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Ledbim.Redis --version 1.0.0
                    
#r "nuget: Ledbim.Redis, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Ledbim.Redis@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Ledbim.Redis&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Ledbim.Redis&version=1.0.0
                    
Install as a Cake Tool

Ledbim.Redis

Versiyon: 1.0.0  |  Target: .NET 10  |  Bağımlılık: Ledbim.Core bağımlılığı yok — bağımsız paket

Tipleştirilmiş Redis erişimi için sade ve profesyonel entegrasyon kütüphanesi. StackExchange.Redis'in bağlantı yönetimi, JSON serializasyon, key prefix, TTL zorunluluğu ve toplu operasyon altyapısını tek satır DI kaydıyla sunar. Tüketen proje IRedisService inject eder ve iş mantığına odaklanır.


İçindekiler

  1. Paket Amacı
  2. Paket Kapsamı
  3. Bağımlılıklar
  4. Önemli Yapılar
  5. RedisOptions
  6. IRedisService
  7. Key Prefix
  8. TTL Yönetimi
  9. IncrementAsync ve Fixed-Window Davranışı
  10. Toplu Operasyonlar
  11. Entegrasyon ve DI Kaydı
  12. Kullanım Örnekleri
  13. Mimari Notlar
  14. Dikkat Edilmesi Gerekenler
  15. Hızlı Başlangıç

1. Paket Amacı

Bu paket ne işe yarar?

Ledbim.Redis, StackExchange.Redis üzerine inşa edilmiş sade bir entegrasyon katmanıdır:

  • Tipleştirilmiş API: GetAsync<T> ve SetAsync<T> generic metodları JSON serializasyonu otomatik yönetir; tüketen proje byte[] veya RedisValue ile hiç muhatap olmaz.
  • Zorunlu TTL: Her SetAsync ve IncrementAsync çağrısı TTL gerektirir. Yanlışlıkla süresiz yazma ve bellek sızıntısı riski tasarım gereği önlenir.
  • Key prefix: RedisOptions.KeyPrefix ile tüm key'lere otomatik ön ek eklenir. Farklı ortam veya uygulamalar aynı Redis instance'ını güvenle paylaşabilir.
  • Bağlantı yönetimi: ConnectionMultiplexer singleton lifecycle'ıyla doğru şekilde oluşturulur ve DI'ya kaydedilir.
  • Fail-fast yapılandırma: Eksik veya hatalı ConnectionString ile uygulama ayağa kalkmaz; hata açık mesajla bildirilir.

Hangi problemi çözer?

Her projede sıfırdan yazılan StackExchange.Redis bağlantı kurulumu, serializasyon yönetimi, key adlandırma kuralları ve TTL disiplinini ortadan kaldırır.

Ne zaman kullanılmalıdır?

Redis'i cache, session yönetimi, rate limiting veya sayaç olarak kullanan her .NET projesinde. Ledbim ekosistemi dışı projelerde de bağımsız olarak kullanılabilir.


2. Paket Kapsamı

Bu pakette neler var?

Alan İçerik
Kontrat IRedisService — tipleştirilmiş 8 metotlu public API
Yapılandırma RedisOptions, RedisOptionsValidator
DI Uzantısı AddLedbimRedis(IConfiguration), AddLedbimRedis(Action<RedisOptions>)
Serializasyon System.Text.Json tabanlı internal RedisSerializer
Key Yönetimi Internal KeyBuilder — prefix birleştirme ve doğrulama
Bağlantı IConnectionMultiplexer singleton kaydı — escape hatch

Neler bu paket dışında tutulmuştur?

Alan Neden dışarıda Alternatif
Pub/Sub Farklı kullanım deseni, subscriber lifecycle yönetimi gerektirir IConnectionMultiplexer escape hatch
Distributed Lock RedLock algoritması ayrı dikkat gerektirir Gelecekte Ledbim.Redis.Locking
Lua scripting Düşük kullanım, yüksek hata riski IConnectionMultiplexer escape hatch
Redis Streams Consumer group yönetimi farklı abstraction gerektirir IConnectionMultiplexer escape hatch
Bulk scan / pattern delete SCAN operasyonu production'da dikkatli kullanım gerektirir IConnectionMultiplexer escape hatch
Health check Opsiyonel altyapı, tüketen proje kendi ekler services.AddHealthChecks().AddRedis(...)

3. Bağımlılıklar

NuGet Bağımlılıkları

Paket Versiyon Kullanım Amacı
StackExchange.Redis 2.8.24 Redis bağlantısı ve tüm komutlar
Microsoft.Extensions.DependencyInjection.Abstractions 10.0.0 IServiceCollection
Microsoft.Extensions.Configuration.Abstractions 10.0.0 IConfiguration binding
Microsoft.Extensions.Options 10.0.0 IOptions<T>, IValidateOptions<T>
Microsoft.Extensions.Options.ConfigurationExtensions 10.0.0 OptionsBuilder.Bind()
Microsoft.Extensions.Logging.Abstractions 10.0.0 ILogger<T> — hata loglama

System.Text.Json .NET 10 framework'ünde yerleşik gelir, ayrıca eklenmez.

Ledbim Bağımlılıkları

Yok. Ledbim.Redis, Ledbim ekosistemine bağımlı değildir. Diğer Ledbim paketleri olmadan da kullanılabilir.


4. Önemli Yapılar

Public Tipler

Tip Tür Açıklama
IRedisService Interface Ana kontrat; tüketen proje bu tipi inject eder
RedisOptions Sınıf ConnectionString, KeyPrefix, Database yapılandırması
AddLedbimRedis(...) Extension DI kayıt metotları

Internal Tipler

Tip Açıklama
RedisService IRedisService implementasyonu
RedisOptionsValidator Fail-fast yapılandırma doğrulama
KeyBuilder Prefix birleştirme ve key doğrulama
RedisSerializer System.Text.Json tabanlı serialize/deserialize

Escape Hatch

IConnectionMultiplexer DI'ya singleton olarak kaydedilir. Paketin desteklemediği gelişmiş senaryolar (pub/sub, Lua scripting, süresiz sayaç) için doğrudan inject edilebilir.

public class AdvancedService(IConnectionMultiplexer multiplexer)
{
    public async Task<long> IncrementForeverAsync(string key)
    {
        var db = multiplexer.GetDatabase();
        return await db.StringIncrementAsync(key); // TTL yok, süresiz
    }
}

5. RedisOptions

public sealed class RedisOptions
{
    public const string SectionName = "Redis";

    // Zorunlu — boş bırakılırsa uygulama başlamaz
    public string ConnectionString { get; set; } = string.Empty;

    // Opsiyonel — tüm key'lere otomatik ön ek
    public string KeyPrefix { get; set; } = string.Empty;

    // Opsiyonel — hedef veritabanı numarası, varsayılan 0
    public int Database { get; set; } = 0;
}

Yapılandırma Doğrulama

RedisOptionsValidator, IValidateOptions<RedisOptions> implementasyonuyla uygulama başlarken çalışır:

  • ConnectionString boşsa → OptionsValidationException fırlatır
  • Database negatifse → OptionsValidationException fırlatır

Hatalı yapılandırmayla production ortamına ulaşılmaz.


6. IRedisService

public interface IRedisService
{
    // Tekil operasyonlar
    Task SetAsync<T>(string key, T value, TimeSpan ttl, CancellationToken ct = default);
    Task<T?> GetAsync<T>(string key, CancellationToken ct = default);
    Task RemoveAsync(string key, CancellationToken ct = default);
    Task<bool> ExistsAsync(string key, CancellationToken ct = default);
    Task<bool> ExpireAsync(string key, TimeSpan ttl, CancellationToken ct = default);
    Task<long> IncrementAsync(string key, TimeSpan ttl, long delta = 1, CancellationToken ct = default);

    // Toplu operasyonlar
    Task SetManyAsync<T>(IEnumerable<KeyValuePair<string, T>> entries, TimeSpan ttl, CancellationToken ct = default);
    Task<IReadOnlyDictionary<string, T?>> GetManyAsync<T>(IEnumerable<string> keys, CancellationToken ct = default);
}

Metot Davranışları

Metot Key yoksa Key varsa
SetAsync Oluşturur Üzerine yazar
GetAsync null döner Deserialize eder
RemoveAsync Sessizce döner Siler
ExistsAsync false döner true döner
ExpireAsync false döner TTL günceller, true döner
IncrementAsync 0 + delta'dan başlar, TTL atar Artırır, TTL dokunulmaz

7. Key Prefix

KeyPrefix yapılandırıldığında tüm metodlara geçilen key'lere otomatik olarak ön ek eklenir:

{prefix}:{key}

Tüketen proje her key'e manuel prefix eklemek zorunda kalmaz.

// RedisOptions.KeyPrefix = "myapp"

await redis.SetAsync("user:123", dto, TimeSpan.FromHours(1));
// Redis'te: "myapp:user:123"

await redis.GetAsync<UserDto>("user:123");
// Redis'ten: "myapp:user:123" okunur

KeyPrefix boş bırakılırsa hiçbir dönüşüm yapılmaz, key olduğu gibi kullanılır.

Ortam Ayrımı

Farklı ortamların aynı Redis instance'ını güvenle paylaşması için:

// appsettings.Development.json
{ "Redis": { "KeyPrefix": "myapp-dev" } }

// appsettings.Production.json
{ "Redis": { "KeyPrefix": "myapp" } }

8. TTL Yönetimi

SetAsync ve IncrementAsync her çağrıda TimeSpan ttl parametresi zorunludur. Bu tasarım gereği bir kısıtlamadır; yanlışlıkla süresiz yazma ve Redis bellek sızıntısı riski önlenir.

// Her key için açık TTL verilmek zorunda
await redis.SetAsync("sms:905001234567", code, TimeSpan.FromMinutes(2));
await redis.SetAsync("session:abc123", session, TimeSpan.FromHours(1));
await redis.SetAsync("user:123", profile, TimeSpan.FromDays(7));

Tüketen Projede TTL Organizasyonu

Farklı TTL değerleri için enum + extension pattern önerilir:

public enum CacheTtl { SmsCode, Session, UserProfile, RateLimit }

public static class CacheTtlExtensions
{
    public static TimeSpan ToTimeSpan(this CacheTtl ttl) => ttl switch
    {
        CacheTtl.SmsCode     => TimeSpan.FromMinutes(2),
        CacheTtl.Session     => TimeSpan.FromHours(1),
        CacheTtl.UserProfile => TimeSpan.FromDays(7),
        CacheTtl.RateLimit   => TimeSpan.FromMinutes(1),
        _                    => TimeSpan.FromHours(1)
    };
}

// Kullanım
await redis.SetAsync("sms:905001234567", code, CacheTtl.SmsCode.ToTimeSpan());

9. IncrementAsync ve Fixed-Window Davranışı

Task<long> IncrementAsync(string key, TimeSpan ttl, long delta = 1, CancellationToken ct = default);

TTL yalnızca key ilk oluşturulduğunda atanır. Sonraki increment çağrılarında TTL sıfırlanmaz. Bu fixed-window davranışıdır ve rate limiting için doğru yaklaşımdır:

// Kullanıcı başına dakikada 10 istek — fixed-window rate limiting
public async Task<bool> IsAllowedAsync(string userId, CancellationToken ct)
{
    var key = $"rate:{userId}:{DateTime.UtcNow:yyyyMMddHHmm}";
    var count = await redis.IncrementAsync(key, TimeSpan.FromMinutes(1), ct: ct);
    return count <= 10;
}

Key içinde dakika bilgisi bulunur. Her dakika yeni bir key oluşur, 1 dakika sonra otomatik silinir.

Not: Süresiz sayaç gerekiyorsa (toplam kayıt sayısı gibi) IConnectionMultiplexer escape hatch kullanılmalıdır.


10. Toplu Operasyonlar

SetManyAsync

Arka planda Redis pipeline kullanır. Tüm SET komutları tek network round-trip'te gönderilir.

var entries = products.Select(p =>
    new KeyValuePair<string, ProductDto>($"product:{p.Id}", p));

await redis.SetManyAsync(entries, TimeSpan.FromMinutes(10), ct);

GetManyAsync

Arka planda Redis MGET kullanır. Tüm key'ler tek komutla okunur. Cache'te olmayan key'lerin değeri null gelir.

var keys = userIds.Select(id => $"user:{id}");
var cached = await redis.GetManyAsync<UserDto>(keys, ct);

// Hangileri cache'te yok?
var missingIds = userIds.Where(id => cached[$"user:{id}"] is null).ToList();

// Sadece eksikleri DB'den çek
var fromDb = await userRepository.GetByIdsAsync(missingIds, ct);

Performans Karşılaştırması

Yöntem 100 key için network Açıklama
Tekil GetAsync döngüsü 100 round-trip Her key ayrı komut
GetManyAsync 1 round-trip MGET tek komut
Tekil SetAsync döngüsü 100 round-trip Her key ayrı komut
SetManyAsync 1 round-trip Pipeline tek gidiş

11. Entegrasyon ve DI Kaydı

appsettings.json

{
  "Redis": {
    "ConnectionString": "localhost:6379",
    "KeyPrefix": "myapp",
    "Database": 0
  }
}

Ortama göre bağlantı string örnekleri:

// Yerel geliştirme
localhost:6379

// Şifreli
localhost:6379,password=secret

// SSL + üretim
redis.internal:6380,password=secret,ssl=true,abortConnect=false

Program.cs

// IConfiguration üzerinden (appsettings)
builder.Services.AddLedbimRedis(builder.Configuration);

// Programmatic (test veya özel senaryo)
builder.Services.AddLedbimRedis(options =>
{
    options.ConnectionString = "localhost:6379";
    options.KeyPrefix = "myapp";
});

DI Kayıtları

AddLedbimRedis(...) çağrısı şunları kaydeder:

Tip Lifecycle Açıklama
IConnectionMultiplexer Singleton StackExchange.Redis bağlantı havuzu
IRedisService Singleton Stateless, thread-safe implementasyon
IValidateOptions<RedisOptions> Singleton Fail-fast yapılandırma doğrulayıcı

12. Kullanım Örnekleri

Cache-Aside Pattern

public class UserService(IRedisService redis, IUserRepository userRepository)
{
    public async Task<UserDto?> GetAsync(int userId, CancellationToken ct)
    {
        var key = $"user:{userId}";

        var cached = await redis.GetAsync<UserDto>(key, ct);
        if (cached is not null) return cached;

        var user = await userRepository.GetByIdAsync(userId, ct);
        if (user is null) return null;

        await redis.SetAsync(key, user, TimeSpan.FromHours(1), ct);
        return user;
    }

    public async Task UpdateAsync(int userId, UpdateUserRequest request, CancellationToken ct)
    {
        await userRepository.UpdateAsync(userId, request, ct);
        await redis.RemoveAsync($"user:{userId}", ct); // invalidation
    }
}

SMS Doğrulama Kodu

public class SmsVerificationService(IRedisService redis)
{
    private static string Key(string phone) => $"sms:otp:{phone}";

    public async Task SendAsync(string phone, CancellationToken ct)
    {
        var code = Random.Shared.Next(100000, 999999).ToString();
        await redis.SetAsync(Key(phone), code, TimeSpan.FromMinutes(2), ct);
    }

    public async Task<bool> VerifyAsync(string phone, string inputCode, CancellationToken ct)
    {
        var stored = await redis.GetAsync<string>(Key(phone), ct);
        if (stored is null || stored != inputCode) return false;

        await redis.RemoveAsync(Key(phone), ct); // tek kullanım
        return true;
    }
}

Session Yönetimi

public class SessionService(IRedisService redis)
{
    private static string Key(string sessionId) => $"session:{sessionId}";

    public async Task CreateAsync(string sessionId, SessionData data, CancellationToken ct)
        => await redis.SetAsync(Key(sessionId), data, TimeSpan.FromHours(1), ct);

    public async Task<SessionData?> GetAsync(string sessionId, CancellationToken ct)
        => await redis.GetAsync<SessionData>(Key(sessionId), ct);

    public async Task ExtendAsync(string sessionId, CancellationToken ct)
        => await redis.ExpireAsync(Key(sessionId), TimeSpan.FromHours(1), ct);

    public async Task DeleteAsync(string sessionId, CancellationToken ct)
        => await redis.RemoveAsync(Key(sessionId), ct);
}

Token Kara Liste

public class TokenBlacklistService(IRedisService redis)
{
    public async Task RevokeAsync(string token, TimeSpan remaining, CancellationToken ct)
        => await redis.SetAsync($"revoked:{token}", true, remaining, ct);

    public async Task<bool> IsRevokedAsync(string token, CancellationToken ct)
        => await redis.ExistsAsync($"revoked:{token}", ct);
}

Rate Limiting

public class RateLimiter(IRedisService redis)
{
    public async Task<bool> IsAllowedAsync(string userId, int limit, CancellationToken ct)
    {
        var key = $"rate:{userId}:{DateTime.UtcNow:yyyyMMddHHmm}";
        var count = await redis.IncrementAsync(key, TimeSpan.FromMinutes(1), ct: ct);
        return count <= limit;
    }
}

13. Mimari Notlar

Neden IDistributedCache değil?

.NET'in standart IDistributedCache interface'i yalnızca Get/Set/Remove destekler ve byte[] döner. ExistsAsync, ExpireAsync, IncrementAsync gibi Redis'e özgü operasyonlar için yetersizdir. Ledbim.Redis, Redis'in gerçek yeteneklerini tipleştirilmiş bir API ile sunar.

Neden zorunlu TTL?

Her SetAsync çağrısı TTL gerektirir. Bu sınırlama, geliştiriciyi her key'in ömrünü düşünmeye zorlar ve Redis'te birikecek stale datayı önler. "Süresiz" yazmak gereken nadir durumlarda IConnectionMultiplexer escape hatch kullanılır.

ConnectionMultiplexer Lifecycle

StackExchange.Redis, ConnectionMultiplexer'ın uygulama boyunca tek instance olarak yaşamasını önerir. Bu nesne dahili bağlantı havuzunu yönetir. AddLedbimRedis(...) bu nesneyi singleton olarak kaydeder. Her request'te yeni bağlantı açılmaz.

Serializasyon

System.Text.Json camelCase policy ile kullanılır. JsonSerializerOptions static readonly olarak tek kez oluşturulur; her operasyonda yeni instance üretilmez. Newtonsoft.Json bağımlılığı yoktur.


14. Dikkat Edilmesi Gerekenler

# Kural Açıklama
1 TTL zorunlu SetAsync ve IncrementAsync'te TTL parametresi her zaman girilmelidir
2 Key boş olamaz Boş key geçilirse ArgumentException fırlatılır
3 GetAsync null döner Key yoksa exception fırlatmaz, null döner — null kontrolü zorunlu
4 IncrementAsync fixed-window TTL yalnızca ilk oluşturmada atanır; sonraki artışlarda sıfırlanmaz
5 RemoveAsync idempotent Key yoksa sessizce döner, hata fırlatmaz
6 ConnectionString zorunlu Boş bırakılırsa uygulama başlamaz — OptionsValidationException
7 Prefix tüm key'lere uygulanır GetManyAsync dönüş dictionary'sindeki key'ler prefix'siz orijinal key'lerdir
8 IConnectionMultiplexer DI'da Gelişmiş senaryo için inject edilebilir; yeni bağlantı açılmaz, aynı instance paylaşılır

15. Hızlı Başlangıç

1. NuGet:

dotnet add package Ledbim.Redis

2. appsettings.json:

{
  "Redis": {
    "ConnectionString": "localhost:6379",
    "KeyPrefix": "myapp"
  }
}

3. Program.cs:

builder.Services.AddLedbimRedis(builder.Configuration);

4. Kullanım:

public class ProductService(IRedisService redis)
{
    public async Task<ProductDto?> GetAsync(int id, CancellationToken ct)
    {
        var cached = await redis.GetAsync<ProductDto>($"product:{id}", ct);
        if (cached is not null) return cached;

        // DB'den yükle...
        await redis.SetAsync($"product:{id}", product, TimeSpan.FromMinutes(30), ct);
        return product;
    }
}
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 120 3/30/2026