### Full Hybrid Cache Setup Example Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisHybridCacheClient.md Demonstrates how to initialize and use the RedisHybridCacheClient. This includes setting up the Redis connection, configuring the hybrid cache with specific options for both Redis and local caches, performing cache operations like SetAsync and GetAsync, and invalidating cache entries. ```csharp // Initialize Redis connection var options = ConfigurationOptions.Parse("localhost:6379"); var muxer = await ConnectionMultiplexer.ConnectAsync(options); // Create hybrid cache var hybrid = new RedisHybridCacheClient( o => o .ConnectionMultiplexer(muxer) .UseDatabase(0) .RedisChannelName("myapp-cache-messages") .ReadMode(CommandFlags.PreferReplica), local => local .MaxItems(5000) .LoggerFactory(loggerFactory)); // Use like normal cache var user = new { Name = "Alice", Id = 123 }; await hybrid.SetAsync("user:123", user, TimeSpan.FromHours(1)); // Fast local read on second access var cached = await hybrid.GetAsync("user:123"); // Invalidate across all instances await hybrid.RemoveAsync("user:123"); // Cleanup hybrid.Dispose(); ``` -------------------------------- ### File Storage Example Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/types.md Example demonstrating how to retrieve file information using the storage API. ```csharp var fileInfo = await storage.GetFileInfoAsync("docs/readme.txt"); Console.WriteLine($"{fileInfo.Path}: {fileInfo.Size} bytes, modified {fileInfo.Modified}"); ``` -------------------------------- ### Full RedisFile Storage Usage Example Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisFileStorage.md Demonstrates the complete lifecycle of file operations using RedisFileStorage, including setup, saving, checking existence, metadata retrieval, copying, reading, listing, and deleting files. Ensure a Redis connection is established and the container name is configured. ```csharp // Setup var muxer = await ConnectionMultiplexer.ConnectAsync("localhost"); var storage = new RedisFileStorage(o => o .ConnectionMultiplexer(muxer) .ContainerName("myapp-files")); // Save file using (var stream = new MemoryStream()) { using (var writer = new StreamWriter(stream)) { await writer.WriteAsync("Hello, Redis File Storage!"); await writer.FlushAsync(); } stream.Position = 0; bool saved = await storage.SaveFileAsync("greeting.txt", stream); } // Check existence if (await storage.ExistsAsync("greeting.txt")) { // Get metadata var info = await storage.GetFileInfoAsync("greeting.txt"); Console.WriteLine($"File size: {info?.Size} bytes"); // Copy file await storage.CopyFileAsync("greeting.txt", "greeting-backup.txt"); // Read file var stream = await storage.GetFileStreamAsync("greeting.txt", StreamMode.Read); if (stream != null) { using (var reader = new StreamReader(stream)) { string content = await reader.ReadToEndAsync(); Console.WriteLine(content); } } // List files var files = await storage.GetFileListAsync("greeting*"); foreach (var file in files) Console.WriteLine($"- {file.Path}"); // Delete files await storage.DeleteFileAsync("greeting-backup.txt"); } storage.Dispose(); ``` -------------------------------- ### Full RedisMessageBus Usage Example Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisMessageBus.md Demonstrates the complete lifecycle of using RedisMessageBus, including setup, publishing domain events (OrderPlaced), and subscribing to handle events and publish related events (OrderShipped). ```csharp // Domain event public class OrderPlaced { public int OrderId { get; set; } public decimal Total { get; set; } } public class OrderShipped { public int OrderId { get; set; } public string TrackingNumber { get; set; } } // Setup var muxer = await ConnectionMultiplexer.ConnectAsync("localhost"); var messageBus = new RedisMessageBus(o => o .Subscriber(muxer.GetSubscriber()) .Topic("orders")); // Producer: Publish order event async Task PublishOrderAsync(int orderId) { var order = new OrderPlaced { OrderId = orderId, Total = 99.99m }; await messageBus.PublishAsync(order, new MessageOptions { UniqueId = $"order-{orderId}", CorrelationId = Guid.NewGuid().ToString() }); } // Consumer: Listen for order placements async Task SubscribeToOrdersAsync() { // Handle order placements await messageBus.SubscribeAsync(async (message, ct) => { var order = message.GetBody(); Console.WriteLine($"Order placed: {order.OrderId} for ${order.Total}"); // Simulate processing await Task.Delay(1000, ct); // Publish related event await messageBus.PublishAsync(new OrderShipped { OrderId = order.OrderId, TrackingNumber = "TRACK123" }); }); // Handle order shipments await messageBus.SubscribeAsync(async (message, ct) => { var shipment = message.GetBody(); Console.WriteLine($"Order shipped: {shipment.OrderId} - {shipment.TrackingNumber}"); }); } // Run var cts = new CancellationTokenSource(); _ = Task.Run(() => SubscribeToOrdersAsync()); await PublishOrderAsync(1001); await PublishOrderAsync(1002); await Task.Delay(5000); cts.Cancel(); await messageBus.CloseAsync(); ``` -------------------------------- ### Quick Start: Redis File Storage Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/README.md Demonstrates basic file upload, download, and deletion using RedisFileStorage. ```csharp var storage = new RedisFileStorage(o => o .ConnectionMultiplexer(muxer) .ContainerName("app-storage")); using (var stream = File.OpenRead("local.txt")) await storage.SaveFileAsync("remote/file.txt", stream); var fileStream = await storage.GetFileStreamAsync("remote/file.txt", StreamMode.Read); var fileInfo = await storage.GetFileInfoAsync("remote/file.txt"); await storage.DeleteFileAsync("remote/file.txt"); ``` -------------------------------- ### Path Normalization Example Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisFileStorage.md Demonstrates how RedisFileStorage normalizes paths by converting backslashes to forward slashes, ensuring cross-platform compatibility. Both examples achieve the same result. ```csharp // These are equivalent: await storage.SaveFileAsync("folder\file.txt", stream); // Windows-style await storage.SaveFileAsync("folder/file.txt", stream); // Unix-style ``` -------------------------------- ### Quick Start: Redis Distributed Cache Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/README.md Demonstrates how to set and get data from a distributed Redis cache using RedisCacheClient. Requires a Redis connection. ```csharp var muxer = await ConnectionMultiplexer.ConnectAsync("localhost"); var cache = new RedisCacheClient(o => o.ConnectionMultiplexer(muxer)); await cache.SetAsync("user:123", userData, TimeSpan.FromHours(1)); var cached = await cache.GetAsync("user:123"); ``` -------------------------------- ### Add Foundatio.Redis Package Source: https://github.com/foundatiofx/foundatio.redis/blob/main/README.md Install the Foundatio.Redis NuGet package to your project to begin using its features. ```bash dotnet add package Foundatio.Redis ``` -------------------------------- ### Full Queue Processing Example Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisQueue.md Demonstrates setting up, producing, and consuming messages with RedisQueue. Includes retry and timeout configurations. Ensure Redis is running and accessible. ```csharp public class EmailJob { public string To { get; set; } public string Subject { get; set; } public string Body { get; set; } } // Setup var muxer = await ConnectionMultiplexer.ConnectAsync("localhost"); var queue = new RedisQueue(o => o .ConnectionMultiplexer(muxer) .Name("email-queue") .Retries(3) .RetryDelay(TimeSpan.FromSeconds(30)) .WorkItemTimeout(TimeSpan.FromMinutes(5))); // Producer async Task ProduceAsync() { for (int i = 0; i < 10; i++) { await queue.EnqueueAsync(new EmailJob { To = $"user{i}@example.com", Subject = "Hello", Body = "Test message" }); } } // Consumer async Task ConsumeAsync(CancellationToken ct) { await queue.StartWorkingAsync(async entry => { var job = entry.Value; try { // Simulate long operation await Task.Delay(2000, ct); // Renew lock if still working if (!ct.IsCancellationRequested) await queue.RenewLockAsync(entry); Console.WriteLine($"Sent email to {job.To}"); // Auto-completed if handler doesn't throw } catch (Exception ex) { Console.WriteLine($"Failed: {ex.Message}"); throw; // Will be abandoned and retried } }, autoComplete: true, cancellationToken: ct); } var cts = new CancellationTokenSource(); _ = Task.Run(() => ProduceAsync()); _ = Task.Run(() => ConsumeAsync(cts.Token)); await Task.Delay(30000); cts.Cancel(); await queue.DeleteQueueAsync(); ``` -------------------------------- ### Redis File Storage Implementation Source: https://github.com/foundatiofx/foundatio.redis/blob/main/README.md Demonstrates using Redis for file storage. This example requires a Redis connection and the Foundatio.Redis package. ```csharp // File Storage IFileStorage storage = new RedisFileStorage(o => o.ConnectionMultiplexer(muxer)); await storage.SaveFileAsync("docs/readme.txt", "Hello World"); ``` -------------------------------- ### Add Foundatio CI Feed and Install Pre-release Package Source: https://github.com/foundatiofx/foundatio.redis/blob/main/README.md Use these commands to add the Feedz CI source and install the latest pre-release version of Foundatio.Redis. ```bash dotnet nuget add source https://f.feedz.io/foundatio/foundatio/nuget -n foundatio-feedz dotnet add package Foundatio.Redis --prerelease ``` -------------------------------- ### Complete Multi-Service Setup with Dependency Injection Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/configuration.md Demonstrates how to configure multiple Foundatio.Redis services, including IConnectionMultiplexer, ICacheClient, RedisHybridCacheClient, IMessageBus, RedisQueue, and IFileStorage, using IServiceCollection in a .NET application. ```csharp public class Startup { public void ConfigureServices(IServiceCollection services) { // Shared Redis connection services.AddSingleton(sp => ConnectionMultiplexer.Connect( ConfigurationOptions.Parse( Configuration.GetConnectionString("Redis")))); // Cache services.AddSingleton(sp => new RedisCacheClient(o => o .ConnectionMultiplexer(sp.GetRequiredService()) .UseDatabase(0) .ReadMode(CommandFlags.PreferReplica))); // Hybrid Cache services.AddSingleton(sp => new RedisHybridCacheClient( o => o .ConnectionMultiplexer(sp.GetRequiredService()) .UseDatabase(1), local => local.MaxItems(10000))); // Message Bus services.AddSingleton(sp => { var muxer = sp.GetRequiredService(); return new RedisMessageBus(o => o .Subscriber(muxer.GetSubscriber()) .Topic("domain-events")); }); // Queues services.AddSingleton>(sp => new RedisQueue(o => o .ConnectionMultiplexer(sp.GetRequiredService()) .Name("email-queue") .Retries(3) .RetryDelay(TimeSpan.FromSeconds(30)))); services.AddSingleton>(sp => new RedisQueue(o => o .ConnectionMultiplexer(sp.GetRequiredService()) .Name("processing-queue") .Retries(5) .WorkItemTimeout(TimeSpan.FromMinutes(15)))); // File Storage services.AddSingleton(sp => new RedisFileStorage(o => o .ConnectionMultiplexer(sp.GetRequiredService()) .ContainerName("app-storage"))); } } ``` -------------------------------- ### Redis Queuing Implementation Source: https://github.com/foundatiofx/foundatio.redis/blob/main/README.md Shows how to use Redis as a message queue for background work items. Ensure Foundatio.Redis is installed and Redis is accessible. ```csharp // Queuing IQueue queue = new RedisQueue(o => o.ConnectionMultiplexer(muxer)); await queue.EnqueueAsync(new WorkItem { Data = "Hello" }); var entry = await queue.DequeueAsync(); ``` -------------------------------- ### GetQueueStatsAsync Example Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/types.md Demonstrates how to retrieve queue statistics using GetQueueStatsAsync. Use this to check the current state of a queue. ```csharp var stats = await queue.GetQueueStatsAsync(); Console.WriteLine($"Queued: {stats.Queued}, Working: {stats.Working}, Completed: {stats.Completed}"); ``` -------------------------------- ### Message Bus Subscribe Example Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/types.md Shows how to subscribe to a message bus and deserialize the message body. Use this in message handler implementations. ```csharp await messageBus.SubscribeAsync(async (message, ct) => { var user = message.GetBody(); Console.WriteLine($"User: {user.Email}"); }); ``` -------------------------------- ### Quick Start: Redis Message Bus (Pub/Sub) Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/README.md Demonstrates publishing and subscribing to messages using RedisMessageBus. This enables distributed pub/sub messaging with type-based subscriptions. ```csharp var messageBus = new RedisMessageBus(o => o .Subscriber(muxer.GetSubscriber()) .Topic("domain-events")); await messageBus.PublishAsync(new UserCreated { UserId = 123 }); await messageBus.SubscribeAsync(async (message, ct) => { var user = message.GetBody(); Console.WriteLine($"User created: {user.UserId}"); }); ``` -------------------------------- ### Cache GetAsync Example Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/types.md Demonstrates checking for a cached value, handling cases where the key is not found or the value is explicitly null. Use this after retrieving data from the cache. ```csharp var result = await cache.GetAsync("key"); if (result.HasValue) { if (result.Value == null) Console.WriteLine("Key exists but value is null"); else Console.WriteLine($"Value: {result.Value}"); } else { Console.WriteLine("Key not found"); } ``` -------------------------------- ### Quick Start: Redis Hybrid Cache Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/README.md Shows how to use RedisHybridCacheClient for a two-tier cache combining local in-memory and distributed Redis caches. Automatic invalidation is handled via pub/sub. ```csharp var hybrid = new RedisHybridCacheClient( o => o.ConnectionMultiplexer(muxer), local => local.MaxItems(5000)); await hybrid.SetAsync("key", value); // Set in both tiers await hybrid.RemoveAsync("key"); // Invalidate locally and across instances ``` -------------------------------- ### Quick Start: Redis Queue with Retry and Dead-Letter Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/README.md Illustrates setting up and using a RedisQueue for reliable message processing with retry and dead-letter capabilities. The queue is configured with retry counts and delays. ```csharp var queue = new RedisQueue(o => o .ConnectionMultiplexer(muxer) .Name("work-queue") .Retries(3) .RetryDelay(TimeSpan.FromMinutes(1))); await queue.EnqueueAsync(new WorkItem { Data = "task" }); await queue.StartWorkingAsync(async entry => { await ProcessAsync(entry.Value); // Auto-completed if handler doesn't throw }, autoComplete: true); ``` -------------------------------- ### Handling Redis Connection and Timeout Errors Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/errors.md Provides an example of catching RedisConnectionException and TimeoutException during a cache operation, suggesting fallback or retry strategies. ```csharp try { await cache.SetAsync("key", "value"); } catch (RedisConnectionException ex) { Console.WriteLine($"Redis connection failed: {ex.Message}"); // Implement circuit breaker or fallback } catch (TimeoutException ex) { Console.WriteLine($"Operation timed out: {ex.Message}"); // Retry with backoff or use fallback } ``` -------------------------------- ### RedisMessageBus Disposal Example Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisMessageBus.md Demonstrates the usage of RedisMessageBus within a using statement to ensure proper disposal. Subscriptions are automatically closed upon disposal. ```csharp using (var messageBus = new RedisMessageBus(options)) { await messageBus.PublishAsync(new MyEvent()); } // Subscriptions automatically closed ``` -------------------------------- ### Starting a Worker to Process Queue Entries Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisQueue.md Use StartWorkingAsync to initiate a worker that processes messages using a provided handler. Configure autoComplete to automatically complete entries or handle completion manually. ```csharp public async Task StartWorkingAsync( Func, CancellationToken, Task> handler, bool autoComplete = true, CancellationToken cancellationToken = default) ``` ```csharp // Single worker with auto-complete await queue.StartWorkingAsync(async entry => { Console.WriteLine($"Processing: {entry.Value.Data}"); await Task.Delay(100); }, autoComplete: true, cancellationToken: cts.Token); // Multiple workers without auto-complete for (int i = 0; i < 5; i++) { await queue.StartWorkingAsync(async entry => { try { await ProcessAsync(entry.Value); await entry.CompleteAsync(); } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); await entry.AbandonAsync(); } }, autoComplete: false, cancellationToken: cts.Token); } ``` -------------------------------- ### StartWorkingAsync Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisQueue.md Starts a worker thread that continuously dequeues and processes messages from the queue. It can be configured to automatically complete entries or require manual completion. ```APIDOC ## StartWorkingAsync ### Description Starts a worker thread that continuously dequeues and processes messages. ### Method Signature ```csharp public async Task StartWorkingAsync( Func, CancellationToken, Task> handler, bool autoComplete = true, CancellationToken cancellationToken = default) ``` ### Parameters #### Path Parameters - **handler** (Func, CancellationToken, Task>) - Required - Async function to process each entry - **autoComplete** (bool) - Optional - Automatically complete entries that handler doesn't throw for. Defaults to true. - **cancellationToken** (CancellationToken) - Optional - Cancellation token for worker. Defaults to CancellationToken.None. ### Throws - `ArgumentNullException` if handler is null ### Example ```csharp // Single worker with auto-complete await queue.StartWorkingAsync(async entry => { Console.WriteLine($"Processing: {entry.Value.Data}"); await Task.Delay(100); }, autoComplete: true, cancellationToken: cts.Token); // Multiple workers without auto-complete for (int i = 0; i < 5; i++) { await queue.StartWorkingAsync(async entry => { try { await ProcessAsync(entry.Value); await entry.CompleteAsync(); } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); await entry.AbandonAsync(); } }, autoComplete: false, cancellationToken: cts.Token); } ``` ``` -------------------------------- ### Connect to Redis Sentinel Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/configuration.md Connects to a Redis Sentinel setup, specifying multiple Sentinel instances and a service name. This allows for high availability and automatic failover. ```csharp // Redis Sentinel var options = ConfigurationOptions.Parse("sentinel1:26379,sentinel2:26379,sentinel3:26379"); options.ServiceName = "mymaster"; // Sentinel service name var muxer = await ConnectionMultiplexer.ConnectAsync(options); ``` -------------------------------- ### RedisCacheClient Methods Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisCacheClient.md Provides methods for interacting with the Redis cache, including getting single or multiple items, paginating lists, and setting values. ```APIDOC ## GetAsync(string key) ### Description Gets a single value from cache by key. ### Method GET (conceptual, as this is an SDK method) ### Endpoint N/A (SDK Method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Method Signature ```csharp public async Task> GetAsync(string key) ``` ### Parameters - **key** (string) - Required - Cache key (cannot be empty) ### Returns `Task>` - Cache value wrapper containing the deserialized value or indicating no value ### Throws - `ArgumentException` if key is null or empty ### Example ```csharp var cached = await cache.GetAsync("user:123"); if (cached.HasValue) { Console.WriteLine(cached.Value.Name); } ``` ## GetAllAsync(IEnumerable keys) ### Description Gets multiple values from cache in a single operation (MGET in cluster-aware batches). ### Method GET (conceptual, as this is an SDK method) ### Endpoint N/A (SDK Method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Method Signature ```csharp public async Task>> GetAllAsync(IEnumerable keys) ``` ### Parameters - **keys** (IEnumerable) - Required - Collection of cache keys ### Returns `Task>>` - Read-only dictionary mapping keys to cache values ### Throws - `ArgumentNullException` if keys is null - `ArgumentException` if any key is null or empty ### Example ```csharp var results = await cache.GetAllAsync(new[] { "count:1", "count:2" }); foreach (var kvp in results) { if (kvp.Value.HasValue) Console.WriteLine($"{kvp.Key}: {kvp.Value.Value}"); } ``` ## GetListAsync(string key, int? page = null, int pageSize = 100) ### Description Gets a paginated list of items stored under a key as a sorted set (with expiration scores). ### Method GET (conceptual, as this is an SDK method) ### Endpoint N/A (SDK Method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Method Signature ```csharp public async Task>> GetListAsync(string key, int? page = null, int pageSize = 100) where T : notnull ``` ### Parameters - **key** (string) - Required - Cache key storing the list - **page** (int?) - Optional - Default: null - Page number (1-based); null returns all non-expired items - **pageSize** (int) - Optional - Default: 100 - Items per page ### Returns `Task>>` - Collection of non-expired items ### Throws - `ArgumentException` if key is null or empty - `ArgumentOutOfRangeException` if page is less than 1 ### Example ```csharp // Get all non-expired items var all = await cache.GetListAsync("tags"); // Get page 2 with custom page size var page2 = await cache.GetListAsync("tags", page: 2, pageSize: 50); ``` ## SetAsync(string key, T value, TimeSpan? expiresIn = null) ### Description Sets a cache value, overwriting any existing value. ### Method POST (conceptual, as this is an SDK method) ### Endpoint N/A (SDK Method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Method Signature ```csharp public async Task SetAsync(string key, T value, TimeSpan? expiresIn = null) ``` ### Parameters - **key** (string) - Required - Cache key (cannot be empty) - **value** (T) - Required - Value to cache - **expiresIn** (TimeSpan?) - Optional - Default: null - Expiration duration; null means no expiration ### Returns `Task` - True if set succeeded ### Throws - `ArgumentException` if key is null or empty ### Example ```csharp var user = new { Name = "Alice", Id = 123 }; await cache.SetAsync("user:123", user, TimeSpan.FromHours(1)); ``` ``` -------------------------------- ### Implement Circuit Breaker Pattern for Fallback Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/errors.md This example demonstrates using a circuit breaker to prevent repeated calls to a failing Redis cache. If the circuit is open, it fails fast; otherwise, it records successes or failures to manage the circuit state. ```csharp var circuitBreaker = new CircuitBreakerPolicy(); async Task> GetWithFallback(string key) { try { if (circuitBreaker.IsOpen) return CacheValue.NoValue; // Fail fast var result = await cache.GetAsync(key); circuitBreaker.RecordSuccess(); return result; } catch (Exception ex) { circuitBreaker.RecordFailure(ex); return CacheValue.NoValue; // Return empty instead of throwing } } ``` -------------------------------- ### Get Paged File List Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisFileStorage.md Retrieves a paginated list of files from storage. Use when dealing with a large number of files to manage memory and improve performance. Supports filtering by a wildcard search pattern. ```csharp public async Task GetPagedFileListAsync(int pageSize = 100, string? searchPattern = null, CancellationToken cancellationToken = default) ``` ```csharp var paged = await storage.GetPagedFileListAsync(pageSize: 50, searchPattern: "documents/*"); // Get first page if (paged.HasMore) { foreach (var file in paged.Files) Console.WriteLine(file.Path); // Navigate to next page await paged.NextPageAsync(); } ``` -------------------------------- ### Build Foundatio.Redis Project Source: https://github.com/foundatiofx/foundatio.redis/blob/main/README.md Build the Foundatio.Redis solution using the dotnet CLI. ```bash dotnet build ``` -------------------------------- ### Redis Caching Implementation Source: https://github.com/foundatiofx/foundatio.redis/blob/main/README.md Demonstrates how to set up and use Redis for caching. Requires a running Redis instance and the Foundatio.Redis package. ```csharp // Caching var muxer = await ConnectionMultiplexer.ConnectAsync("localhost"); ICacheClient cache = new RedisCacheClient(o => o.ConnectionMultiplexer(muxer)); await cache.SetAsync("user:123", user, TimeSpan.FromMinutes(5)); var cached = await cache.GetAsync("user:123"); ``` -------------------------------- ### GetFileInfoAsync Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisFileStorage.md Gets file metadata including path, size, and creation/modification timestamps. ```APIDOC ## GetFileInfoAsync ### Description Gets file metadata including path, size, and creation/modification timestamps. ### Method `public async Task GetFileInfoAsync(string path)` ### Parameters #### Path Parameters - **path** (string) - Required - File path ### Returns `Task` - FileSpec object with metadata; null if file not found ### Throws - `ArgumentNullException` if path is null ### Example ```csharp var fileInfo = await storage.GetFileInfoAsync("docs/readme.txt"); if (fileInfo != null) { Console.WriteLine($"Size: {fileInfo.Size} bytes"); Console.WriteLine($"Created: {fileInfo.Created}"); Console.WriteLine($"Modified: {fileInfo.Modified}"); } ``` ``` -------------------------------- ### GetFileStreamAsync Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisFileStorage.md Gets a file as a stream. Supports read-only mode; write mode is not supported. ```APIDOC ## GetFileStreamAsync ### Description Gets a file as a stream. Supports read-only mode; write mode is not supported. ### Method `public async Task GetFileStreamAsync(string path, StreamMode streamMode, CancellationToken cancellationToken = default)` ### Parameters #### Path Parameters - **path** (string) - Required - File path - **streamMode** (StreamMode) - Required - StreamMode.Read (write mode not supported) - **cancellationToken** (CancellationToken) - Optional - Cancellation token ### Returns `Task` - MemoryStream containing file content; null if file not found ### Throws - `ArgumentNullException` if path is null - `NotSupportedException` if streamMode is Write ### Example ```csharp var stream = await storage.GetFileStreamAsync("docs/readme.txt", StreamMode.Read); if (stream != null) { using (var reader = new StreamReader(stream)) { string content = await reader.ReadToEndAsync(); Console.WriteLine(content); } } ``` ``` -------------------------------- ### Build, Test, and Format Foundatio.Redis Project Source: https://github.com/foundatiofx/foundatio.redis/blob/main/AGENTS.md Commands to build, test, and format the Foundatio.Redis solution using the .NET CLI. Use Foundatio.All.slnx when building within a workspace. ```bash # Build dotnet build Foundatio.Redis.slnx # Test dotnet test Foundatio.Redis.slnx # Format code dotnet format Foundatio.Redis.slnx ``` -------------------------------- ### Get File Stream from Redis Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisFileStorage.md Retrieves a file from Redis storage as a readable stream. Write mode is not supported. ```csharp var stream = await storage.GetFileStreamAsync("docs/readme.txt", StreamMode.Read); if (stream != null) { using (var reader = new StreamReader(stream)) { string content = await reader.ReadToEndAsync(); Console.WriteLine(content); } } ``` -------------------------------- ### Redis Messaging Implementation Source: https://github.com/foundatiofx/foundatio.redis/blob/main/README.md Illustrates setting up Redis for publish/subscribe messaging. This requires a Redis connection and the Foundatio.Redis package. ```csharp // Messaging IMessageBus messageBus = new RedisMessageBus(o => o.Subscriber(muxer.GetSubscriber())); await messageBus.PublishAsync(new MyMessage { Data = "Hello" }); ``` -------------------------------- ### GetFileListAsync Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisFileStorage.md Gets file metadata for all files matching a search pattern, with optional pagination. Returns a collection of FileSpec objects. ```APIDOC ## GetFileListAsync ### Description Gets file metadata for all files matching a search pattern, with optional pagination. Returns a collection of FileSpec objects. ### Method Not applicable (SDK method) ### Endpoint Not applicable (SDK method) ### Parameters #### Path Parameters - **searchPattern** (string?) - No - null - Wildcard pattern (e.g., "docs/*.md"); null returns all - **limit** (int?) - No - null - Maximum number of results; null = unlimited - **skip** (int?) - No - null - Number of results to skip (for pagination) #### Query Parameters - **cancellationToken** (CancellationToken) - No - default - Cancellation token ### Request Example ```csharp // List all files var allFiles = await storage.GetFileListAsync(); foreach (var file in allFiles) Console.WriteLine($"{file.Path} ({file.Size} bytes)"); // List with pagination var first10 = await storage.GetFileListAsync(limit: 10, skip: 0); var next10 = await storage.GetFileListAsync(limit: 10, skip: 10); // List matching pattern var markdownFiles = await storage.GetFileListAsync("docs/*.md"); var logFiles = await storage.GetFileListAsync("logs/*.log", limit: 100); ``` ### Response #### Success Response - **IEnumerable** - Collection of FileSpec objects #### Response Example ```json [ { "Path": "file1.txt", "Size": 1024, "LastModified": "2023-10-27T10:00:00Z" } ] ``` ``` -------------------------------- ### Load Configuration from appsettings.json and Environment Variables Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/configuration.md Shows how to load Redis connection strings from standard .NET configuration sources like appsettings.json and environment variables. This allows for flexible configuration management. ```csharp // From appsettings.json var configuration = new ConfigurationBuilder() .AddJsonFile("appsettings.json") .AddEnvironmentVariables() .Build(); var redisConnection = configuration.GetConnectionString("Redis"); // "DefaultEndpoints=redis.example.com:6379;ssl=true" var options = ConfigurationOptions.Parse(redisConnection); var muxer = await ConnectionMultiplexer.ConnectAsync(options); ``` -------------------------------- ### Instantiate RedisQueue with Options Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisQueue.md Creates a new Redis queue instance using explicit configuration options. Ensure a ConnectionMultiplexer is provided. ```csharp public class WorkItem { public string Data { get; set; } } var muxer = await ConnectionMultiplexer.ConnectAsync("localhost"); var queue = new RedisQueue(o => o .ConnectionMultiplexer(muxer) .Name("work-queue") .Retries(3) .RetryDelay(TimeSpan.FromMinutes(1)) .UseDatabase(0)); await queue.EnqueueAsync(new WorkItem { Data = "Hello" }); ``` -------------------------------- ### Get File Metadata from Redis Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisFileStorage.md Retrieves metadata for a file stored in Redis, including its size and timestamps. Returns null if the file is not found. ```csharp var fileInfo = await storage.GetFileInfoAsync("docs/readme.txt"); if (fileInfo != null) { Console.WriteLine($"Size: {fileInfo.Size} bytes"); Console.WriteLine($"Created: {fileInfo.Created}"); Console.WriteLine($"Modified: {fileInfo.Modified}"); } ``` -------------------------------- ### RedisHybridCacheClient Constructors Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisHybridCacheClient.md Provides details on how to instantiate the RedisHybridCacheClient, either directly with options or using a builder pattern. ```APIDOC ## RedisHybridCacheClient(RedisHybridCacheClientOptions, InMemoryCacheClientOptions?) ### Description Creates a new hybrid cache with Redis distributed cache and optional local in-memory cache. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Constructor Signature ```csharp public RedisHybridCacheClient(RedisHybridCacheClientOptions options, InMemoryCacheClientOptions? localOptions = null) ``` ### Parameters - **options** (RedisHybridCacheClientOptions) - Required - Configuration for distributed Redis cache - **localOptions** (InMemoryCacheClientOptions?) - Optional - Configuration for local in-memory cache; if null, uses default in-memory options ### Throws - `ArgumentNullException` if options or ConnectionMultiplexer is null ### Example ```csharp var muxer = await ConnectionMultiplexer.ConnectAsync("localhost"); var hybrid = new RedisHybridCacheClient(o => o .ConnectionMultiplexer(muxer) .UseDatabase(0) .ReadMode(CommandFlags.PreferReplica), localOptions: null); // Use default in-memory config await hybrid.SetAsync("key", "value", TimeSpan.FromMinutes(5)); var cached = await hybrid.GetAsync("key"); ``` ## RedisHybridCacheClient(Builder, Builder?) ### Description Creates a new hybrid cache using builder pattern for both distributed and local cache configuration. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Constructor Signature ```csharp public RedisHybridCacheClient(Builder config, Builder? localConfig = null) ``` ### Parameters - **config** (Builder) - Required - Builder function for Redis cache options - **localConfig** (Builder?) - Optional - Builder function for in-memory cache options ### Example ```csharp var hybrid = new RedisHybridCacheClient( config: o => o .ConnectionMultiplexer(muxer) .UseDatabase(1), localConfig: local => local .MaxItems(1000)); ``` ``` -------------------------------- ### Get Expiration Time for a Key Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisCacheClient.md Retrieves the remaining time-to-live (TTL) for a specific cache key. Returns null if the key has no expiration set or does not exist. ```csharp public async Task GetExpirationAsync(string key) ``` ```csharp var ttl = await cache.GetExpirationAsync("session:abc"); if (ttl.HasValue) Console.WriteLine($"Expires in {ttl.Value.TotalSeconds} seconds"); ``` -------------------------------- ### Create RedisFileStorage with Options Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisFileStorage.md Creates a new Redis file storage instance using explicit options. Ensure you have a ConnectionMultiplexer configured. ```csharp var muxer = await ConnectionMultiplexer.ConnectAsync("localhost"); var storage = new RedisFileStorage(o => o .ConnectionMultiplexer(muxer) .ContainerName("app-storage") .ReadMode(CommandFlags.PreferReplica)); await storage.SaveFileAsync("docs/readme.txt", "Hello World"); ``` -------------------------------- ### Dependency Injection Configuration Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/README.md Configures Redis clients and queues using dependency injection with Foundatio.Redis. ```csharp services.AddSingleton(sp => ConnectionMultiplexer.Connect(Configuration.GetConnectionString("Redis"))); services.AddSingleton(sp => new RedisCacheClient(o => o .ConnectionMultiplexer(sp.GetRequiredService()) .UseDatabase(0))); services.AddSingleton>(sp => new RedisQueue(o => o .ConnectionMultiplexer(sp.GetRequiredService()) .Name("email-queue") .Retries(3))); ``` -------------------------------- ### Run Tests for Foundatio.Redis Project Source: https://github.com/foundatiofx/foundatio.redis/blob/main/README.md Execute all tests for the Foundatio.Redis project using the dotnet CLI. ```bash dotnet test ``` -------------------------------- ### Get Single Value from Cache Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisCacheClient.md Retrieves a single cached value by its key. The returned CacheValue wrapper indicates if a value was found and contains the deserialized object. ```csharp var cached = await cache.GetAsync("user:123"); if (cached.HasValue) { Console.WriteLine(cached.Value.Name); } ``` -------------------------------- ### Get Expirations for Multiple Keys Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisCacheClient.md Efficiently retrieves expiration times for multiple keys in a single Redis operation using a Lua script. Returns a dictionary mapping keys to their TTLs. ```csharp public async Task> GetAllExpirationAsync(IEnumerable keys) ``` ```csharp var expirations = await cache.GetAllExpirationAsync(new[] { "key1", "key2" }); foreach (var kvp in expirations) Console.WriteLine($"{kvp.Key}: {kvp.Value?.TotalSeconds ?? 0} seconds"); ``` -------------------------------- ### Connect to Redis with Options Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/configuration.md Connects to Redis with custom configuration options, including service name, SSL, and password. This is useful for more secure or specific Redis deployments. ```csharp // With options var options = ConfigurationOptions.Parse("localhost:6379"); options.ServiceName = "myservice"; options.Ssl = true; options.Password = "secret"; var muxer = await ConnectionMultiplexer.ConnectAsync(options); ``` -------------------------------- ### Get Multiple Values from Cache Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisCacheClient.md Fetches multiple cached values efficiently using a single Redis operation (MGET). Returns a dictionary mapping keys to their respective CacheValue objects. ```csharp var results = await cache.GetAllAsync(new[] { "count:1", "count:2" }); foreach (var kvp in results) { if (kvp.Value.HasValue) Console.WriteLine($"{kvp.Key}: {kvp.Value.Value}"); } ``` -------------------------------- ### Create RedisMessageBus with Options Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisMessageBus.md Instantiate RedisMessageBus with explicit configuration options, including the Redis subscriber, topic, and serializer. ```csharp var muxer = await ConnectionMultiplexer.ConnectAsync("localhost"); var messageBus = new RedisMessageBus(o => o .Subscriber(muxer.GetSubscriber()) .Topic("events") .Serializer(new JsonSerializer())); await messageBus.PublishAsync(new MyEvent { Data = "Hello" }); ``` -------------------------------- ### Create RedisCacheClient with ConnectionMultiplexer Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisCacheClient.md Instantiates a RedisCacheClient using a pre-configured ConnectionMultiplexer and specifies database and read mode. Use this when you have an existing ConnectionMultiplexer instance. ```csharp var muxer = await ConnectionMultiplexer.ConnectAsync("localhost"); var cache = new RedisCacheClient(o => o .ConnectionMultiplexer(muxer) .UseDatabase(0) .ReadMode(CommandFlags.PreferReplica)); await cache.SetAsync("key", "value", TimeSpan.FromMinutes(5)); var result = await cache.GetAsync("key"); ``` -------------------------------- ### Get Paginated List from Cache Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisCacheClient.md Retrieves a paginated collection of items stored as a sorted set under a specific key. Supports fetching all non-expired items or specific pages with a custom page size. ```csharp // Get all non-expired items var all = await cache.GetListAsync("tags"); // Get page 2 with custom page size var page2 = await cache.GetListAsync("tags", page: 2, pageSize: 50); ``` -------------------------------- ### Configure RedisFileStorageOptions Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/configuration.md Configure RedisFileStorageOptions using the builder to set the connection multiplexer, container name, read mode, and other storage-specific options. ```csharp var storage = new RedisFileStorage(o => o .ConnectionMultiplexer(muxer) .ContainerName("myapp-files") .ReadMode(CommandFlags.PreferReplica) .LoggerFactory(loggerFactory)); ``` -------------------------------- ### RedisFileStorage Constructors Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisFileStorage.md Provides documentation for the constructors of the RedisFileStorage class. ```APIDOC ## RedisFileStorage(RedisFileStorageOptions) ### Description Creates a new Redis file storage with the specified configuration. ### Parameters #### Path Parameters - **options** (RedisFileStorageOptions) - Required - Configuration including ConnectionMultiplexer (required), ContainerName, ReadMode ### Throws - `ArgumentNullException` if options or ConnectionMultiplexer is null ### Example ```csharp var muxer = await ConnectionMultiplexer.ConnectAsync("localhost"); var storage = new RedisFileStorage(o => o .ConnectionMultiplexer(muxer) .ContainerName("app-storage") .ReadMode(CommandFlags.PreferReplica)); await storage.SaveFileAsync("docs/readme.txt", "Hello World"); ``` ## RedisFileStorage(Builder) ### Description Creates a new Redis file storage using builder pattern. ### Parameters #### Path Parameters - **config** (Builder) - Required - Builder function configuring storage options ``` -------------------------------- ### RedisHybridCacheClient Constructor with Options Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisHybridCacheClient.md Creates a new hybrid cache instance using Redis as the distributed backend and an optional local in-memory cache. Requires Redis connection options and optionally allows configuration for the local cache. ```csharp var muxer = await ConnectionMultiplexer.ConnectAsync("localhost"); var hybrid = new RedisHybridCacheClient(o => o .ConnectionMultiplexer(muxer) .UseDatabase(0) .ReadMode(CommandFlags.PreferReplica), localOptions: null); // Use default in-memory config await hybrid.SetAsync("key", "value", TimeSpan.FromMinutes(5)); var cached = await hybrid.GetAsync("key"); ``` -------------------------------- ### Running All Tests in Foundatio.Redis Source: https://github.com/foundatiofx/foundatio.redis/blob/main/AGENTS.md Command to execute all tests within the Foundatio.Redis solution. ```bash dotnet test Foundatio.Redis.slnx ``` -------------------------------- ### RedisQueue Constructors Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisQueue.md Provides details on how to instantiate a RedisQueue, either directly with options or using a builder pattern. ```APIDOC ## RedisQueue(RedisQueueOptions) ### Description Creates a new Redis queue with the specified configuration. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **options** (RedisQueueOptions) - Required - Configuration including ConnectionMultiplexer (required), Name, Retries, RetryDelay, WorkItemTimeout. ### Throws: - `ArgumentNullException` if options or ConnectionMultiplexer is null ### Example: ```csharp public class WorkItem { public string Data { get; set; } } var muxer = await ConnectionMultiplexer.ConnectAsync("localhost"); var queue = new RedisQueue(o => o .ConnectionMultiplexer(muxer) .Name("work-queue") .Retries(3) .RetryDelay(TimeSpan.FromMinutes(1)) .UseDatabase(0)); await queue.EnqueueAsync(new WorkItem { Data = "Hello" }); ``` ``` ```APIDOC ## RedisQueue(Builder, RedisQueueOptions>) ### Description Creates a new Redis queue using builder pattern. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **config** (Builder, RedisQueueOptions>) - Required - Builder function configuring queue options. ### Example: None provided in source. ``` -------------------------------- ### Connect to Standalone Redis Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/configuration.md Establishes a connection to a single Redis instance. Ensure Redis is running on localhost:6379. ```csharp // Standalone Redis var muxer = await ConnectionMultiplexer.ConnectAsync("localhost:6379"); ``` -------------------------------- ### Configure RedisCacheClientOptions Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/configuration.md Use the builder to configure RedisCacheClientOptions, specifying connection multiplexer, database, read mode, serialization, and logging. ```csharp var cache = new RedisCacheClient(o => o .ConnectionMultiplexer(muxer) .UseDatabase(1) .ReadMode(CommandFlags.PreferReplica) .ShouldThrowOnSerializationError(false) .Serializer(new JsonSerializer()) .LoggerFactory(loggerFactory)); ``` -------------------------------- ### List Files in Redis with Pagination Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisFileStorage.md Use GetFileListAsync to retrieve file metadata. Supports wildcard search patterns and optional pagination (limit and skip). ```csharp // List all files var allFiles = await storage.GetFileListAsync(); foreach (var file in allFiles) Console.WriteLine($"{file.Path} ({file.Size} bytes)"); // List with pagination var first10 = await storage.GetFileListAsync(limit: 10, skip: 0); var next10 = await storage.GetFileListAsync(limit: 10, skip: 10); // List matching pattern var markdownFiles = await storage.GetFileListAsync("docs/*.md"); var logFiles = await storage.GetFileListAsync("logs/*.log", limit: 100); ``` -------------------------------- ### RedisHybridCacheClient Disposal Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/api-reference/RedisHybridCacheClient.md Demonstrates how to properly dispose of the RedisHybridCacheClient to release resources. This can be done using a 'using' statement for automatic disposal or by calling the Dispose() method manually. ```csharp using (var hybrid = new RedisHybridCacheClient(options)) { await hybrid.SetAsync("key", "value"); // Resources automatically cleaned up } // Or manually: hybrid.Dispose(); ``` -------------------------------- ### Running Tests with Detailed Logging Source: https://github.com/foundatiofx/foundatio.redis/blob/main/AGENTS.md Command to execute tests and enable detailed console logging, which can be helpful for debugging test failures. ```bash dotnet test --logger "console;verbosity=detailed" ``` -------------------------------- ### Share IConnectionMultiplexer via Dependency Injection Source: https://github.com/foundatiofx/foundatio.redis/blob/main/_autodocs/configuration.md Demonstrates how to register IConnectionMultiplexer as a singleton in a dependency injection container. This ensures a single, thread-safe instance is shared across the application, which is crucial for performance and resource management. ```csharp // Dependency injection setup services.AddSingleton(sp => { var options = ConfigurationOptions.Parse( Configuration.GetConnectionString("Redis"))); return ConnectionMultiplexer.Connect(options); }); // Usage in multiple components services.AddSingleton(sp => new RedisCacheClient(o => o .ConnectionMultiplexer(sp.GetRequiredService())))); services.AddSingleton>(sp => new RedisQueue(o => o .ConnectionMultiplexer(sp.GetRequiredService()) .Name("work-queue"))); ```