### Install RedisKit via NuGet Source: https://github.com/ersintarhan/rediskit/blob/master/articles/getting-started.md Installs the RedisKit package using the .NET CLI. This is the first step to include RedisKit in your project. ```bash dotnet add package RedisKit ``` -------------------------------- ### Pub/Sub Service Source: https://github.com/ersintarhan/rediskit/blob/master/articles/getting-started.md Shows how to use the `IRedisPubSubService` for publishing and subscribing to messages. Includes examples for sending notifications to a channel and setting up a subscriber to listen for incoming messages. ```csharp using RedisKit.Interfaces; public class NotificationService { private readonly IRedisPubSubService _pubSub; public NotificationService(IRedisPubSubService pubSub) { _pubSub = pubSub; } // Publisher public async Task SendNotificationAsync(string channel, Notification notification) { await _pubSub.PublishAsync(channel, notification); } // Subscriber public async Task StartListeningAsync() { await _pubSub.SubscribeAsync("notifications", async (channel, notification) => { Console.WriteLine($"Received: {notification.Message}"); await ProcessNotification(notification); }); } } ``` -------------------------------- ### Rediskit API Reference Source: https://github.com/ersintarhan/rediskit/blob/master/articles/getting-started.md Provides detailed API documentation for the Rediskit library, including class methods, parameters, and usage. ```APIDOC RedisKit: __init__(host: str, port: int, db: int = 0, password: Optional[str] = None) Initializes the Redis client. Parameters: host: Redis server hostname or IP address. port: Redis server port. db: Redis database number (defaults to 0). password: Redis password if authentication is required. get(key: str) -> Optional[str] Retrieves the value associated with a given key. Parameters: key: The key to retrieve. Returns: The value as a string, or None if the key does not exist. set(key: str, value: str, ex: Optional[int] = None, px: Optional[int] = None, nx: bool = False, xx: bool = False) -> bool Sets the string value of a key. Parameters: key: The key to set. value: The value to set. ex: Set the specified expire time, in seconds. px: Set the specified expire time, in milliseconds. nx: Only set the key if it does not already exist. xx: Only set the key if it already exists. Returns: True if the key was set, False otherwise. hgetall(key: str) -> Dict[str, str] Returns all fields and values of the hash stored at key. Parameters: key: The hash key. Returns: A dictionary of field-value pairs. publish(channel: str, message: str) -> int Posts a message to the given channel. Parameters: channel: The channel to publish to. message: The message to send. Returns: The number of clients that received the message. ``` -------------------------------- ### Cache Service with ValueTask Source: https://github.com/ersintarhan/rediskit/blob/master/articles/getting-started.md Implements a cache service using `IRedisCacheService` with `ValueTask` for performance-optimized hot paths. It includes methods for getting data from cache, fetching from an API if not cached, and checking for data existence. ```csharp using RedisKit.Interfaces; public class WeatherService { private readonly IRedisCacheService _cache; public WeatherService(IRedisCacheService cache) { _cache = cache; } // Using ValueTask for hot path optimization public async ValueTask GetWeatherAsync(string city) { var key = $"weather:{city}"; // Try to get from cache - ValueTask reduces allocations var cached = await _cache.GetAsync(key); if (cached != null) return cached; // Fetch from API var weather = await FetchWeatherFromApi(city); // Store in cache for 5 minutes - ValueTask for performance await _cache.SetAsync(key, weather, TimeSpan.FromMinutes(5)); return weather; } // Check if data exists without fetching public async ValueTask HasWeatherDataAsync(string city) { return await _cache.ExistsAsync($"weather:{city}"); } } ``` -------------------------------- ### High-Performance Batch Operations Source: https://github.com/ersintarhan/rediskit/blob/master/articles/getting-started.md Demonstrates using `IRedisCacheService.ExecuteBatchAsync` for efficient batch operations. This allows multiple Redis commands to be executed in a single round-trip, improving performance. Examples include fetching multiple data points and updating multiple values. ```csharp using RedisKit.Interfaces; public class DashboardService { private readonly IRedisCacheService _cache; public DashboardService(IRedisCacheService cache) { _cache = cache; } // ExecuteBatchAsync - Multiple operations in single round-trip public async Task GetDashboardDataAsync(string userId) { var result = await _cache.ExecuteBatchAsync(batch => { batch.GetAsync($"profile:{userId}"); batch.GetAsync>($"activities:{userId}"); batch.GetAsync($"stats:{userId}"); batch.ExistsAsync($"premium:{userId}"); batch.GetAsync($"notifications:count:{userId}"); }); return new DashboardData { Profile = result.GetResult(0), RecentActivities = result.GetResult>(1) ?? new(), Statistics = result.GetResult(2), IsPremiumUser = result.GetResult(3), NotificationCount = result.GetResult(4) ?? 0 }; } // Batch update multiple values public async Task UpdateUserDataAsync(string userId, UserUpdate update) { await _cache.ExecuteBatchAsync(batch => { batch.SetAsync($"profile:{userId}", update.Profile, TimeSpan.FromHours(1)); batch.SetAsync($"stats:{userId}", update.Stats, TimeSpan.FromHours(1)); batch.DeleteAsync($"cache:old:{userId}"); batch.ExpireAsync($"session:{userId}", TimeSpan.FromMinutes(30)); }); } } ``` -------------------------------- ### Redis Functions Usage (Redis 7.x) Source: https://github.com/ersintarhan/rediskit/blob/master/articles/getting-started.md Demonstrates how to use Redis Functions for server-side scripting. Includes creating a function library, loading it, and calling functions. ```csharp using RedisKit.Builders; using RedisKit.Interfaces; // Get the Redis Functions service var functionService = services.GetRequiredService(); // Check if Redis 7.x is supported if (await functionService.IsSupportedAsync()) { // Create a function library var library = new FunctionLibraryBuilder() .WithName("myapp") .WithDescription("My application functions") .AddFunction("get_user_score", @" function(keys, args) local user_id = args[1] local score = redis.call('GET', 'user:' .. user_id .. ':score') return score or 0 end ") .AddReadOnlyFunction("count_users", @" function(keys, args) return redis.call('DBSIZE') end ") .Build(); // Load the library await functionService.LoadAsync(library); // Call functions var score = await functionService.CallAsync("get_user_score", args: new[] { "123" }); var userCount = await functionService.CallReadOnlyAsync("count_users"); } ``` -------------------------------- ### Redis Connection Configuration Options Source: https://github.com/ersintarhan/rediskit/blob/master/articles/getting-started.md Configures the connection settings for RedisKit, including connection strings, authentication, timeouts, retry policies, and serialization options. ```csharp builder.Services.AddRedisKit(options => { // Connection settings options.ConnectionString = "localhost:6379,localhost:6380"; options.Password = "your-password"; options.DefaultDatabase = 0; // Timeouts options.ConnectTimeout = 5000; options.SyncTimeout = 5000; options.AsyncTimeout = 5000; // Retry configuration options.ConnectRetry = 3; options.ReconnectRetryPolicy = ReconnectRetryPolicy.ExponentialBackoff; // Serialization options.SerializerType = SerializerType.SystemTextJson; // or SerializerType.MessagePack for better performance }); ``` -------------------------------- ### Redis Stream Service Implementation Source: https://github.com/ersintarhan/rediskit/blob/master/articles/getting-started.md Demonstrates how to use the IRedisStreamService for publishing and consuming messages from Redis streams. Includes setting up a consumer group and handling incoming messages. ```csharp using RedisKit.Interfaces; public class EventProcessor { private readonly IRedisStreamService _streams; public EventProcessor(IRedisStreamService streams) { _streams = streams; } // Producer public async Task PublishEventAsync(UserEvent userEvent) { return await _streams.AddAsync("events:stream", userEvent); } // Consumer public async Task StartConsumerAsync() { await _streams.CreateConsumerGroupAsync("events:stream", "processors"); await _streams.ConsumeAsync( streamKey: "events:stream", groupName: "processors", consumerName: "worker-1", handler: async (message, streamEntry) => { Console.WriteLine($"Processing event: {message.EventType}"); await ProcessEvent(message); }); } } ``` -------------------------------- ### Sharded Pub/Sub Usage (Redis 7.0+) Source: https://github.com/ersintarhan/rediskit/blob/master/articles/getting-started.md Illustrates how to use Sharded Pub/Sub for distributing messages across Redis cluster shards. Covers subscribing, publishing, and unsubscribing. ```csharp using RedisKit.Interfaces; // Get the Sharded Pub/Sub service var shardedPubSub = services.GetRequiredService(); // Check if Sharded Pub/Sub is supported (Redis 7.0+) if (await shardedPubSub.IsSupportedAsync()) { // Subscribe to a sharded channel var subscription = await shardedPubSub.SubscribeAsync( "notifications:user:123", async (message, ct) => { Console.WriteLine($"Received on shard {message.ShardId}: {message.Data.Text}"); await ProcessNotification(message.Data); }); // Publish to sharded channel var subscribers = await shardedPubSub.PublishAsync( "notifications:user:123", new NotificationMessage { Text = "Hello from shard!" }); // Unsubscribe when done await shardedPubSub.UnsubscribeAsync(subscription); } // Note: Sharded Pub/Sub does NOT support pattern subscriptions // This will throw NotSupportedException: // await shardedPubSub.SubscribePatternAsync("pattern:*", handler); ``` -------------------------------- ### Configure RedisKit Services Source: https://github.com/ersintarhan/rediskit/blob/master/articles/getting-started.md Demonstrates how to add RedisKit services to the .NET service collection. It shows both default and custom configurations, including connection string, database selection, timeouts, and serializer type. ```csharp using RedisKit.Extensions; var builder = WebApplication.CreateBuilder(args); // Add RedisKit with default configuration builder.Services.AddRedisKit("localhost:6379"); // Or with custom configuration builder.Services.AddRedisKit(options => { options.ConnectionString = "localhost:6379"; options.DefaultDatabase = 0; options.ConnectTimeout = 5000; options.SyncTimeout = 5000; options.AsyncTimeout = 5000; options.SerializerType = SerializerType.SystemTextJson; }); var app = builder.Build(); ``` -------------------------------- ### Redis Health Monitoring Configuration Source: https://github.com/ersintarhan/rediskit/blob/master/articles/getting-started.md Configures health monitoring for the Redis connection, including check intervals and thresholds for marking the connection as unhealthy. ```csharp builder.Services.AddRedisKit(options => { options.HealthMonitoring = new HealthMonitoringSettings { Enabled = true, HealthCheckInterval = TimeSpan.FromSeconds(30), UnhealthyThreshold = 3 }; }); ``` -------------------------------- ### Redis Circuit Breaker Configuration Source: https://github.com/ersintarhan/rediskit/blob/master/articles/getting-started.md Enables and configures the circuit breaker pattern for Redis operations to prevent cascading failures. ```csharp builder.Services.AddRedisKit(options => { options.CircuitBreaker = new CircuitBreakerSettings { Enabled = true, FailureThreshold = 5, SamplingDuration = TimeSpan.FromSeconds(60), MinimumThroughput = 10, DurationOfBreak = TimeSpan.FromSeconds(30) }; }); ``` -------------------------------- ### Install RedisKit Package Source: https://github.com/ersintarhan/rediskit/blob/master/index.md Installs the RedisKit NuGet package using the .NET CLI. ```bash dotnet add package RedisKit ``` -------------------------------- ### Manage Redis Function Libraries Source: https://github.com/ersintarhan/rediskit/blob/master/articles/redis-functions.md Provides examples for managing loaded Redis Function libraries, including listing all libraries (with and without code), deleting a specific library, and flushing all libraries. Use `FlushAsync` with caution. ```csharp // List all loaded libraries var libraries = await functionService.ListAsync(); foreach (var lib in libraries) { Console.WriteLine($"Library: {lib.Name}"); Console.WriteLine($"Engine: {lib.Engine}"); Console.WriteLine($"Functions: {lib.Functions.Count}"); foreach (var func in lib.Functions) { Console.WriteLine($" - {func.Name} (Read-only: {func.IsReadOnly})"); } } // List with code included var librariesWithCode = await functionService.ListAsync(withCode: true); // Delete a library await functionService.DeleteAsync("myapp"); // Flush all libraries (use with caution!) await functionService.FlushAsync(FlushMode.Sync); ``` -------------------------------- ### Basic RedisKit Setup Source: https://github.com/ersintarhan/rediskit/blob/master/api/index.md Demonstrates how to add RedisKit services to the .NET Dependency Injection container and configure connection options and serializer type. ```csharp using RedisKit.Extensions; // Add RedisKit to DI container services.AddRedisKit(options => { options.ConnectionString = "localhost:6379"; options.SerializerType = SerializerType.MessagePack; }); ``` -------------------------------- ### Connection Management: Good Example Source: https://github.com/ersintarhan/rediskit/blob/master/_site/README.html Illustrates the recommended approach of using dependency injection for a pooled Redis connection, ensuring efficient reuse and reducing overhead. ```csharp public class GoodExample { private readonly IRedisCacheService _cache; // Injected, pooled connection public async Task SetValueAsync() { await _cache.SetAsync("key", "value"); } } ``` -------------------------------- ### Migration from Regular to Sharded Redis Pub/Sub Source: https://github.com/ersintarhan/rediskit/blob/master/articles/sharded-pubsub.md Provides a C# code example for migrating from regular Redis Pub/Sub to sharded Pub/Sub. It includes a fallback mechanism to regular Pub/Sub if sharded Pub/Sub is not supported or if pattern subscriptions are used. The example shows how to handle both publishing and subscribing with conditional logic. ```csharp // Before: Regular pub/sub public class OldMessaging { private readonly IRedisPubSubService _pubSub; public async Task PublishAsync(string channel, Message msg) { await _pubSub.PublishAsync(channel, msg); } public async Task SubscribeAsync(string pattern) { // Pattern subscription await _pubSub.SubscribePatternAsync( pattern, HandleMessage); } } // After: Sharded pub/sub with fallbackpublic class NewMessaging { private readonly IRedisShardedPubSub _shardedPubSub; private readonly IRedisPubSubService _regularPubSub; public async Task PublishAsync(string channel, Message msg) { // Use sharded for better performance if (await _shardedPubSub.IsSupportedAsync()) { await _shardedPubSub.PublishAsync(channel, msg); } else { // Fallback to regular await _regularPubSub.PublishAsync(channel, msg); } } public async Task SubscribeAsync(string channelOrPattern) { if (channelOrPattern.Contains("*") || channelOrPattern.Contains("?")) { // Pattern: must use regular await _regularPubSub.SubscribePatternAsync( channelOrPattern, HandleMessage); } else if (await _shardedPubSub.IsSupportedAsync()) { // Specific channel: use sharded await _shardedPubSub.SubscribeAsync( channelOrPattern, async (msg, ct) => await HandleMessage(msg.Data, ct)); } else { // Fallback to regular await _regularPubSub.SubscribeAsync( channelOrPattern, HandleMessage); } } } ``` -------------------------------- ### First Redis Cache Example (C#) Source: https://github.com/ersintarhan/rediskit/blob/master/_site/README.html A basic example of using RedisKit to store and retrieve a string value. It covers setting up Redis services, storing a greeting with a Time-To-Live (TTL), and retrieving it. ```csharp using RedisKit.Extensions; using RedisKit.Interfaces; // 1. Setup - Add to your Program.cs var builder = WebApplication.CreateBuilder(args); builder.Services.AddRedisServices(options => { options.ConnectionString = "localhost:6379"; }); var app = builder.Build(); // 2. Simple String Cache app.MapPost("/hello/{name}", async (string name, IRedisCacheService cache) => { // Store a simple string await cache.SetAsync($"greeting:{name}", $"Hello, {name}!", TimeSpan.FromMinutes(5)); return $"Greeting saved for {name}"; }); app.MapGet("/hello/{name}", async (string name, IRedisCacheService cache) => { // Retrieve the string var greeting = await cache.GetAsync($"greeting:{name}"); return greeting ?? "No greeting found"; }); app.Run(); ``` -------------------------------- ### Install RedisKit via NuGet Source: https://github.com/ersintarhan/rediskit/blob/master/README.md Installs the RedisKit package into your .NET project using the NuGet package manager. ```bash dotnet add package RedisKit ``` -------------------------------- ### Batch Operations Example Source: https://github.com/ersintarhan/rediskit/blob/master/articles/performance-tuning.md Compares inefficient individual operations with efficient batch operations using RedisKit. The example shows how to use `CreateBatch` and `Execute` for performing multiple cache operations in a single call. ```csharp public class BatchOperations { private readonly IRedisCacheService _cache; public async Task BatchSetAsync(Dictionary products) { // Bad: Individual operations foreach (var kvp in products) { await _cache.SetAsync(kvp.Key, kvp.Value); } // Good: Batch operation var batch = _cache.CreateBatch(); var tasks = products.Select(kvp => batch.SetAsync(kvp.Key, kvp.Value)).ToArray(); batch.Execute(); await Task.WhenAll(tasks); } } ``` -------------------------------- ### Redis Cache - Hello World Example Source: https://github.com/ersintarhan/rediskit/blob/master/README.md Illustrates how to use RedisKit for basic caching operations. It shows how to store a greeting message with a time-to-live and retrieve it later. ```csharp using RedisKit.Extensions; using RedisKit.Interfaces; // 1. Setup - Add to your Program.cs var builder = WebApplication.CreateBuilder(args); builder.Services.AddRedisServices(options => { options.ConnectionString = "localhost:6379"; }); var app = builder.Build(); // 2. Simple String Cache app.MapPost("/hello/{name}", async (string name, IRedisCacheService cache) => { // Store a simple string await cache.SetAsync($"greeting:{name}", $"Hello, {name}!", TimeSpan.FromMinutes(5)); return $"Greeting saved for {name}"; }); app.MapGet("/hello/{name}", async (string name, IRedisCacheService cache) => { // Retrieve the string var greeting = await cache.GetAsync($"greeting:{name}"); return greeting ?? "No greeting found"; }); app.Run(); ``` -------------------------------- ### Install RedisKit Package Source: https://github.com/ersintarhan/rediskit/blob/master/_site/index.html Command to add the RedisKit NuGet package to a .NET project. ```bash dotnet add package RedisKit ``` -------------------------------- ### Minimal Redis Setup (C#) Source: https://github.com/ersintarhan/rediskit/blob/master/_site/README.html Demonstrates the minimal configuration required to add Redis services to a .NET application using dependency injection. It shows how to set the connection string and then use the IRedisCacheService in an endpoint. ```csharp using RedisKit.Extensions; var builder = WebApplication.CreateBuilder(args); // Add Redis services with minimal configuration builder.Services.AddRedisServices(options => { options.ConnectionString = "localhost:6379"; }); var app = builder.Build(); // Use in your controllers or services app.MapGet("/cache/{key}", async (string key, IRedisCacheService cache) => { var value = await cache.GetAsync(key); return value ?? "Not found"; }); app.Run(); ``` -------------------------------- ### Install RedisKit via NuGet (C#) Source: https://github.com/ersintarhan/rediskit/blob/master/_site/README.html Command to add the RedisKit package to your .NET project using the NuGet package manager. ```bash dotnet add package RedisKit ``` -------------------------------- ### Library Versioning and Loading Source: https://github.com/ersintarhan/rediskit/blob/master/articles/redis-functions.md Demonstrates how to build a Redis Function library with version information using `FunctionLibraryBuilder` in C# and load it atomically, replacing any existing version. ```csharp var library = new FunctionLibraryBuilder() .WithName("myapp_v2") .WithDescription("My application functions v2.0.0") // ... functions .Build(); // Replace old version atomically await functionService.LoadAsync(library, replace: true); ``` -------------------------------- ### Migration from EVAL to Redis Functions Source: https://github.com/ersintarhan/rediskit/blob/master/articles/redis-functions.md Illustrates the transition from using `EVAL` with a script string to loading a Redis Function library. The new approach is more efficient for repeated calls. ```csharp // One-time setup var library = new FunctionLibraryBuilder() .WithName("myapp") .AddFunction("get_number", @" function(keys, args) local value = redis.call('GET', keys[1]) return tonumber(value) or 0 end ") .Build(); await functionService.LoadAsync(library); // Usage (much more efficient) var result = await functionService.CallAsync("get_number", keys: new[] { key }); ``` -------------------------------- ### Connection Management: Bad Example Source: https://github.com/ersintarhan/rediskit/blob/master/_site/README.html Demonstrates an anti-pattern of creating and disposing of Redis connections for each operation, leading to performance degradation due to connection overhead. ```csharp public async Task BadExample() { var connection = await ConnectionMultiplexer.ConnectAsync("localhost"); var db = connection.GetDatabase(); await db.StringSetAsync("key", "value"); connection.Dispose(); // Connection closed! } ``` -------------------------------- ### Getting Sharded Pub/Sub Statistics Source: https://github.com/ersintarhan/rediskit/blob/master/articles/sharded-pubsub.md Retrieves statistics for Sharded Pub/Sub, including the total number of channels, total subscribers, and the collection timestamp. It also shows how to get the subscriber count for a specific channel. ```csharp // Get sharded pub/sub statistics var stats = await shardedPubSub.GetStatsAsync(); Console.WriteLine($"Total Channels: {stats.TotalChannels}"); Console.WriteLine($"Total Subscribers: {stats.TotalSubscribers}"); Console.WriteLine($"Collected At: {stats.CollectedAt}"); // Get subscriber count for a specific channel var count = await shardedPubSub.GetSubscriberCountAsync("orders:new"); Console.WriteLine($"Subscribers for 'orders:new': {count}"); ``` -------------------------------- ### Pub/Sub Performance Benchmark Example Source: https://github.com/ersintarhan/rediskit/blob/master/articles/sharded-pubsub.md Provides a C# benchmark example comparing the latency of regular Redis Pub/Sub (cluster broadcast) versus sharded Redis Pub/Sub (single shard targeting). Sharded Pub/Sub demonstrates significantly lower average latency. ```csharp // Benchmark results (example) public class PubSubBenchmark { // Regular: ~2.5ms average (cluster broadcast) // Sharded: ~0.8ms average (single shard) [Benchmark] public async Task RegularPublish() { await regularPubSub.PublishAsync("test", message); } [Benchmark] public async Task ShardedPublish() { await shardedPubSub.PublishAsync("test", message); } } ``` -------------------------------- ### Troubleshooting: Function Not Found Source: https://github.com/ersintarhan/rediskit/blob/master/articles/redis-functions.md Provides a C# code example demonstrating how to catch and handle the `InvalidOperationException` when a Redis Function is called but not found, suggesting to load the library first. ```csharp try { await functionService.CallAsync("my_function"); } catch (InvalidOperationException ex) when (ex.Message.Contains("ERR Function not found")) { // Function doesn't exist - load the library first } ``` -------------------------------- ### Building RedisKit Project Source: https://github.com/ersintarhan/rediskit/blob/master/agents.md Command to build the RedisKit project. This compiles the source code into executable files and libraries. ```bash dotnet build ``` -------------------------------- ### Marking Functions as Read-Only Source: https://github.com/ersintarhan/rediskit/blob/master/articles/redis-functions.md Shows how to define a read-only function in C# for Redis. This function retrieves data without modifying it, using `redis.call('GET', keys[1])`. ```csharp .AddReadOnlyFunction("get_stats", @" function(keys, args) -- Only reading data, no writes return redis.call('GET', keys[1]) end ") ``` -------------------------------- ### Get Redis Function Statistics Source: https://github.com/ersintarhan/rediskit/blob/master/articles/redis-functions.md Retrieves statistics about the loaded Redis Functions, including the number of libraries, functions, memory usage, and currently running functions. Requires an instance of `IRedisFunction`. ```csharp var stats = await functionService.GetStatsAsync(); Console.WriteLine($"Libraries: {stats.LibraryCount}"); Console.WriteLine($"Functions: {stats.FunctionCount}"); Console.WriteLine($"Memory Usage: {stats.MemoryUsage} bytes"); Console.WriteLine($"Running Functions: {stats.RunningFunctions}"); ``` -------------------------------- ### Minimal RedisKit Setup Source: https://github.com/ersintarhan/rediskit/blob/master/README.md Demonstrates the minimal configuration required to set up Redis services in a .NET 9 application using dependency injection. It connects to a Redis instance running on localhost. ```csharp using RedisKit.Extensions; var builder = WebApplication.CreateBuilder(args); // Add Redis services with minimal configuration builder.Services.AddRedisServices(options => { options.ConnectionString = "localhost:6379"; }); var app = builder.Build(); // Use in your controllers or services app.MapGet("/cache/{key}", async (string key, IRedisCacheService cache) => { var value = await cache.GetAsync(key); return value ?? "Not found"; }); app.Run(); ``` -------------------------------- ### Redis Connection Management: Bad vs. Good Example Source: https://github.com/ersintarhan/rediskit/blob/master/README.md Demonstrates the incorrect way of creating new Redis connections for each operation versus the recommended approach of using dependency injection and connection pooling for efficiency. ```csharp // ❌ DON'T: Create new connections for each operation public async Task BadExample() { var connection = await ConnectionMultiplexer.ConnectAsync("localhost"); var db = connection.GetDatabase(); await db.StringSetAsync("key", "value"); connection.Dispose(); // Connection closed! } // ✅ DO: Use dependency injection and connection pooling public class GoodExample { private readonly IRedisCacheService _cache; // Injected, pooled connection public async Task SetValueAsync() { await _cache.SetAsync("key", "value"); } } ``` -------------------------------- ### Initialize RedisKit Services Source: https://github.com/ersintarhan/rediskit/blob/master/_site/index.html Demonstrates how to add RedisKit services to a .NET application, configuring the connection string and serializer type. ```csharp using RedisKit.Extensions; var builder = WebApplication.CreateBuilder(args); builder.Services.AddRedisServices(options => { options.ConnectionString = "localhost:6379"; options.Serializer = SerializerType.MessagePack; }); ``` -------------------------------- ### Redis Dependency Injection Setup Source: https://github.com/ersintarhan/rediskit/blob/master/_site/README.html Demonstrates how to configure and use Rediskit services within a .NET application using dependency injection. It shows how to bind Redis options from configuration and inject Redis services into custom classes. ```csharp // In your Program.cs or Startup.cs: var builder = WebApplication.CreateBuilder(args); // Add Redis services with configuration from appsettings.json builder.Services.Configure( builder.Configuration.GetSection("Redis")); builder.Services.AddRedisServices(options => { builder.Configuration.GetSection("Redis").Bind(options); }); // In your services: public class UserService { private readonly IRedisCacheService _cache; private readonly IRedisPubSubService _pubSub; private readonly IRedisStreamService _stream; private readonly ILogger _logger; public UserService( IRedisCacheService cache, IRedisPubSubService pubSub, IRedisStreamService stream, ILogger logger) { _cache = cache; _pubSub = pubSub; _stream = stream; _logger = logger; } public async Task GetUserAsync(string userId) { // Try cache first var cached = await _cache.GetAsync($"user:{userId}"); if (cached != null) return cached; // Load from database var user = await LoadFromDatabaseAsync(userId); // Cache for future requests if (user != null) { await _cache.SetAsync($"user:{userId}", user, TimeSpan.FromHours(1)); // Publish update event await _pubSub.PublishAsync("user-updates", new UserLoadedEvent { UserId = userId }); } return user; } } ``` -------------------------------- ### RedisKit Services Overview (C#) Source: https://github.com/ersintarhan/rediskit/blob/master/_site/api/RedisKit.Services.html Provides an overview of the RedisKit services available in the RedisKit.Services namespace. Includes links to detailed class documentation. ```csharp Namespace RedisKit.Services Classes: [PubSubService](RedisKit.Services.PubSubService.html) - High-performance implementation of IRedisPubSubService with advanced features [RedisCacheService](RedisKit.Services.RedisCacheService.html) - Implementation of IRedisCacheService using StackExchange.Redis and configurable serialization [RedisStreamService](RedisKit.Services.RedisStreamService.html) - Implementation of IRedisStreamService using StackExchange.Redis and configurable serialization RedisKit - High-performance Redis toolkit for .NET ``` -------------------------------- ### Redis Key Expiration: Absolute Expiration Example Source: https://github.com/ersintarhan/rediskit/blob/master/README.md Shows how to implement absolute expiration for time-sensitive data. This example sets a key's expiration to a specific point in time, such as the beginning of the next day. ```csharp // ✅ Use absolute expiration for time-sensitive data public async Task SetDailyReportAsync(Report report) { var tomorrow = DateTime.UtcNow.Date.AddDays(1); var ttl = tomorrow - DateTime.UtcNow; await _cache.SetAsync($"report:{DateTime.UtcNow:yyyy-MM-dd}", report, ttl); } ``` -------------------------------- ### BenchmarkDotNet Configuration and Environment Source: https://github.com/ersintarhan/rediskit/blob/master/RedisKit.Benchmarks/BenchmarkDotNet.Artifacts/results/RedisLib.Benchmarks.SerializerBenchmarks-report-github.md Details the BenchmarkDotNet version, host environment, .NET SDK version, and the specific .NET runtime and JIT compiler used for the benchmarks. This information is crucial for reproducibility and understanding the context of the performance results. ```benchmark BenchmarkDotNet v0.14.0, macOS Sequoia 15.5 (24F74) [Darwin 24.5.0] Apple M1 Max, 1 CPU, 10 logical and 10 physical cores .NET SDK 9.0.200 [Host] : .NET 9.0.2 (9.0.225.6610), Arm64 RyuJIT AdvSIMD DefaultJob : .NET 9.0.2 (9.0.225.6610), Arm64 RyuJIT AdvSIMD ``` -------------------------------- ### Running Tests with RedisKit Source: https://github.com/ersintarhan/rediskit/blob/master/agents.md Commands to execute tests for the RedisKit project. Includes options for running only unit tests or all tests, with a note on Redis dependency for integration tests. ```bash # Unit tests only (no Redis required) dotnet test --filter "Category!=Integration" # All tests (requires Redis) dotnet test ``` -------------------------------- ### Theme Setting Example Source: https://github.com/ersintarhan/rediskit/blob/master/_site/api/RedisKit.Models.HealthMonitoringSettings.html Sets the theme for the document based on local storage or system preferences. ```javascript const theme = localStorage.getItem('theme') || 'auto' document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme) ``` -------------------------------- ### Cache Hit Rate Monitoring Source: https://github.com/ersintarhan/rediskit/blob/master/_site/README.html Shows an example of a cache service that tracks cache hit and miss rates using a metrics service. ```csharp public class MetricsCacheService { private readonly IRedisCacheService _cache; private readonly IMetrics _metrics; public async Task GetWithMetricsAsync(string key) where T : class { var value = await _cache.GetAsync(key); if (value != null) _metrics.Increment("cache.hits"); else _metrics.Increment("cache.misses"); return value; } } ``` -------------------------------- ### Implement Custom Redis Serialization Source: https://github.com/ersintarhan/rediskit/blob/master/articles/performance-tuning.md Provides an example of a custom Redis serializer that optimizes specific types and falls back to MessagePack. ```csharp public class OptimizedSerializer : IRedisSerializer { public string Name => "Optimized"; public byte[] Serialize(T obj) { if (obj is MySpecialType special) { // Custom optimized serialization return SerializeSpecial(special); } // Fall back to MessagePack return MessagePackSerializer.Serialize(obj); } } ``` -------------------------------- ### Using IRedisStreamService Source: https://github.com/ersintarhan/rediskit/blob/master/api/index.md Provides examples of adding messages to and consuming messages from Redis streams using the IRedisStreamService, including consumer group management. ```csharp // Add to stream var messageId = await _streams.AddAsync("mystream", new MyEvent()); // Consume from stream await _streams.ConsumeAsync("mystream", "group", "consumer", async (msg, entry) => { await ProcessEvent(msg); }); ``` -------------------------------- ### Efficient Pub/Sub Pattern Subscription Source: https://github.com/ersintarhan/rediskit/blob/master/_site/README.html Demonstrates efficient Pub/Sub by using pattern subscriptions to listen to multiple channels with a single subscription, improving performance. ```csharp public class EfficientPubSub { private readonly IRedisPubSubService _pubSub; public async Task SubscribeEfficiently() { // Instead of subscribing to many individual channels // Use pattern subscription await _pubSub.SubscribePatternAsync( "events:*", // Single pattern subscription async (evt, ct) => await ProcessEventAsync(evt, ct) ); } } ``` -------------------------------- ### Memory Optimization: Compressing Large Objects Source: https://github.com/ersintarhan/rediskit/blob/master/_site/README.html Provides an example of a custom cache service that compresses large string values before storing them in Redis to save memory. ```csharp public class CompressedCacheService { private readonly IRedisCacheService _cache; public async Task SetCompressedAsync(string key, T value) where T : class { if (value is string str && str.Length > 1000) { // Compress strings larger than 1KB var compressed = Compress(str); await _cache.SetAsync($"{key}:compressed", compressed); } else { await _cache.SetAsync(key, value); } } } ``` -------------------------------- ### Create Redis Function Library Source: https://github.com/ersintarhan/rediskit/blob/master/articles/redis-functions.md Demonstrates how to build a Redis Function library using `FunctionLibraryBuilder`. This includes setting the library name, engine (LUA), description, and adding functions with their Lua code. ```csharp using RedisKit.Builders; var library = new FunctionLibraryBuilder() .WithName("myapp") .WithEngine("LUA") // Currently only LUA is supported .WithDescription("My application functions") .AddFunction("increment_score", @" function(keys, args) local key = keys[1] local increment = tonumber(args[1]) or 1 return redis.call('INCRBY', key, increment) end ") .AddFunction("get_user_data", @" function(keys, args) local user_id = args[1] local data = {} data.score = redis.call('GET', 'user:' .. user_id .. ':score') data.level = redis.call('GET', 'user:' .. user_id .. ':level') data.name = redis.call('GET', 'user:' .. user_id .. ':name') return cjson.encode(data) end ") .AddReadOnlyFunction("count_active_users", @" function(keys, args) local pattern = 'user:*:active' local cursor = '0' local count = 0 repeat local result = redis.call('SCAN', cursor, 'MATCH', pattern) cursor = result[1] count = count + #result[2] until cursor == '0' return count end ") .Build(); ``` -------------------------------- ### Absolute Expiration Example Source: https://github.com/ersintarhan/rediskit/blob/master/_site/README.html Shows how to set absolute expiration for time-sensitive data, ensuring a cache item expires at a specific time, like the beginning of the next day. ```csharp public async Task SetDailyReportAsync(Report report) { var tomorrow = DateTime.UtcNow.Date.AddDays(1); var ttl = tomorrow - DateTime.UtcNow; await _cache.SetAsync($"report:{DateTime.UtcNow:yyyy-MM-dd}", report, ttl); } ```