Ledbim.Redis
1.0.0
dotnet add package Ledbim.Redis --version 1.0.0
NuGet\Install-Package Ledbim.Redis -Version 1.0.0
<PackageReference Include="Ledbim.Redis" Version="1.0.0" />
<PackageVersion Include="Ledbim.Redis" Version="1.0.0" />
<PackageReference Include="Ledbim.Redis" />
paket add Ledbim.Redis --version 1.0.0
#r "nuget: Ledbim.Redis, 1.0.0"
#:package Ledbim.Redis@1.0.0
#addin nuget:?package=Ledbim.Redis&version=1.0.0
#tool nuget:?package=Ledbim.Redis&version=1.0.0
Ledbim.Redis
Versiyon: 1.0.0 | Target: .NET 10 | Bağımlılık:
Ledbim.Corebağı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
- Paket Amacı
- Paket Kapsamı
- Bağımlılıklar
- Önemli Yapılar
- RedisOptions
- IRedisService
- Key Prefix
- TTL Yönetimi
- IncrementAsync ve Fixed-Window Davranışı
- Toplu Operasyonlar
- Entegrasyon ve DI Kaydı
- Kullanım Örnekleri
- Mimari Notlar
- Dikkat Edilmesi Gerekenler
- 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>veSetAsync<T>generic metodları JSON serializasyonu otomatik yönetir; tüketen projebyte[]veyaRedisValueile hiç muhatap olmaz. - Zorunlu TTL: Her
SetAsyncveIncrementAsyncç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.KeyPrefixile tüm key'lere otomatik ön ek eklenir. Farklı ortam veya uygulamalar aynı Redis instance'ını güvenle paylaşabilir. - Bağlantı yönetimi:
ConnectionMultiplexersingleton lifecycle'ıyla doğru şekilde oluşturulur ve DI'ya kaydedilir. - Fail-fast yapılandırma: Eksik veya hatalı
ConnectionStringile 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:
ConnectionStringboşsa →OptionsValidationExceptionfırlatırDatabasenegatifse →OptionsValidationExceptionfı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)
IConnectionMultiplexerescape 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 | Versions 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. |
-
net10.0
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Options (>= 10.0.0)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.0)
- StackExchange.Redis (>= 2.8.24)
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 |