OElite.Restme.Redis 2.1.1-develop.516

OElite.Restme.Redis

NuGet Version Target Framework

Redis integration package for the Restme framework, providing high-performance caching and distributed data storage capabilities with enterprise-grade features.

Overview

OElite.Restme.Redis provides a robust Redis integration for the OElite platform, offering high-performance caching, distributed storage, and session management. Built on StackExchange.Redis, it delivers enterprise-grade reliability with automatic failover, connection pooling, and advanced caching strategies.

Features

  • Generic Provider Factory: Auto-registered via ServiceLocator with capability detection
  • Provider Capability: ProviderCapabilities.Cache - Redis exclusively provides caching
  • High-Performance Caching: Lightning-fast Redis-based caching with connection multiplexing
  • Automatic Serialization: JSON serialization/deserialization with support for complex objects
  • Connection Management: Robust connection handling with automatic retry and failover
  • Type Safety: Strongly-typed cache operations with generic support
  • Expiration Management: Flexible TTL (Time-To-Live) support for cache entries
  • Error Handling: Comprehensive error handling with custom exceptions
  • Async/Await Support: Full asynchronous operations for optimal performance
  • Key Validation: Built-in key validation and sanitization

Installation

dotnet add package OElite.Restme.Redis

Quick Start

Provider Factory Auto-Registration

OElite.Restme.Redis automatically registers itself with the service locator when loaded:

// Automatic registration happens when assembly is loaded
// The RedisServiceFactory registers itself as "redis" provider

// Check provider capabilities
var factory = ServiceLocator.GetFactory("redis");
var capabilities = factory?.SupportedCapabilities;
// capabilities == ProviderCapabilities.Cache

// Check if cache provider can be created
bool canCreateCache = factory?.CanCreateProvider<ICacheProvider>() ?? false;
// canCreateCache == true

bool canCreateStorage = factory?.CanCreateProvider<IStorageProvider>() ?? false;
// canCreateStorage == false (Redis only supports caching)

Basic Configuration

using OElite;
using OElite.Abstractions;

// Option 1: Using Rest with generic provider pattern (recommended)
var rest = new Rest("redis://localhost:6379",
    configuration: new RestConfig
    {
        OperationMode = RestMode.Redis,
        AuthSecret = "your-password" // Optional
    });

// Get cache provider using generic factory pattern
var cacheProvider = rest.GetProvider<ICacheProvider>();

// NEW: Named providers for multiple cache instances
var primaryCache = rest.GetProvider<ICacheProvider>("primary");
var sessionCache = rest.GetProvider<ICacheProvider>("sessions");
var tempCache = rest.GetProvider<ICacheProvider>("temporary");

// Option 2: Direct provider instantiation (still supported)
var config = new RestConfig { AuthSecret = "your-redis-password" };
var directProvider = new RedisCacheProvider("localhost:6379", config);

Basic Cache Operations

// Store data in cache
await cacheProvider.SetAsync("user:123", userData, TimeSpan.FromHours(1));

// Retrieve data from cache
var user = await cacheProvider.GetAsync<User>("user:123");

// Check if key exists
bool exists = await cacheProvider.ExistsAsync("user:123");

// Remove from cache
await cacheProvider.RemoveAsync("user:123");

Core Features

Type-Safe Caching

Store and retrieve strongly-typed objects:

// Store complex objects
public class Product
{
    public string Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public DateTime CreatedAt { get; set; }
}

var product = new Product
{
    Id = "prod-123",
    Name = "Sample Product",
    Price = 99.99m,
    CreatedAt = DateTime.UtcNow
};

// Cache with expiration
await cacheProvider.SetAsync($"product:{product.Id}", product, TimeSpan.FromMinutes(30));

// Retrieve typed object
var cachedProduct = await cacheProvider.GetAsync<Product>($"product:{product.Id}");

String Caching

Direct string storage for simple scenarios:

// Store strings directly
await cacheProvider.SetAsync("session:token", authToken, TimeSpan.FromHours(2));

// Retrieve strings
var token = await cacheProvider.GetAsync<string>("session:token");

Expiration Management

Multiple expiration strategies:

// Set with specific TTL
await cacheProvider.SetAsync("temp:data", tempData, TimeSpan.FromMinutes(5));

// Set without expiration (persistent until manually removed)
await cacheProvider.SetAsync("config:settings", settings);

// Set with absolute expiration
var absoluteExpiry = DateTime.UtcNow.AddDays(1);
await cacheProvider.SetAsync("daily:report", report, absoluteExpiry - DateTime.UtcNow);

Advanced Usage

Bulk Operations

// Store multiple items efficiently
var tasks = new List<Task>();
foreach (var item in items)
{
    tasks.Add(cacheProvider.SetAsync($"bulk:{item.Id}", item, TimeSpan.FromHours(1)));
}
await Task.WhenAll(tasks);

// Retrieve multiple items
var retrieveTasks = ids.Select(id => cacheProvider.GetAsync<Item>($"bulk:{id}"));
var results = await Task.WhenAll(retrieveTasks);

Conditional Operations

// Only set if key doesn't exist
if (!await cacheProvider.ExistsAsync("unique:key"))
{
    await cacheProvider.SetAsync("unique:key", uniqueData);
}

// Cache-aside pattern
public async Task<User> GetUserAsync(string userId)
{
    var cacheKey = $"user:{userId}";

    // Try cache first
    var cachedUser = await cacheProvider.GetAsync<User>(cacheKey);
    if (cachedUser != null)
        return cachedUser;

    // Fallback to database
    var user = await _userRepository.GetByIdAsync(userId);
    if (user != null)
    {
        // Store in cache for future requests
        await cacheProvider.SetAsync(cacheKey, user, TimeSpan.FromMinutes(15));
    }

    return user;
}

Named Cache Providers

NEW in v2.1.0: Support for multiple cache provider instances using named providers:

// Create Rest instance
var rest = new Rest("redis://localhost:6379", new RestConfig { OperationMode = RestMode.Redis });

// Get named cache providers for different use cases
var userCache = rest.GetProvider<ICacheProvider>("users");
var sessionCache = rest.GetProvider<ICacheProvider>("sessions");
var apiCache = rest.GetProvider<ICacheProvider>("api-responses");
var tempCache = rest.GetProvider<ICacheProvider>("temporary");

// Use different cache providers for logical separation
await userCache.SetAsync("user:123", userData, TimeSpan.FromMinutes(30));
await sessionCache.SetAsync("session:abc123", sessionData, TimeSpan.FromHours(24));
await apiCache.SetAsync("api:external-service:users", apiResponse, TimeSpan.FromMinutes(10));
await tempCache.SetAsync("temp:processing:456", processingData, TimeSpan.FromMinutes(5));

// Default provider (backward compatible)
var defaultCache = rest.GetProvider<ICacheProvider>(); // Same as GetProvider<ICacheProvider>("default")

// Named providers enable organized caching strategies
public class UserService
{
    private readonly ICacheProvider _userProfileCache;
    private readonly ICacheProvider _userPermissionsCache;
    private readonly ICacheProvider _userPreferencesCache;

    public UserService(Rest rest)
    {
        _userProfileCache = rest.GetProvider<ICacheProvider>("user-profiles");
        _userPermissionsCache = rest.GetProvider<ICacheProvider>("user-permissions");
        _userPreferencesCache = rest.GetProvider<ICacheProvider>("user-preferences");
    }

    public async Task<UserProfile> GetUserProfileAsync(string userId)
    {
        var cacheKey = $"profile:{userId}";

        // Check cache first
        var cached = await _userProfileCache.GetAsync<UserProfile>(cacheKey);
        if (cached != null) return cached;

        // Fetch from database and cache
        var profile = await _userRepository.GetProfileAsync(userId);
        if (profile != null)
        {
            await _userProfileCache.SetAsync(cacheKey, profile, TimeSpan.FromMinutes(15));
        }

        return profile;
    }

    public async Task<List<Permission>> GetUserPermissionsAsync(string userId)
    {
        var cacheKey = $"permissions:{userId}";

        // Use dedicated permissions cache with longer TTL
        var cached = await _userPermissionsCache.GetAsync<List<Permission>>(cacheKey);
        if (cached != null) return cached;

        var permissions = await _permissionService.GetUserPermissionsAsync(userId);
        await _userPermissionsCache.SetAsync(cacheKey, permissions, TimeSpan.FromHours(1));

        return permissions;
    }
}

Error Handling

try
{
    var data = await cacheProvider.GetAsync<MyData>("my:key");
}
catch (OEliteException ex)
{
    // Handle cache-specific errors
    _logger.LogError(ex, "Cache operation failed");
    // Fallback to alternative data source
}
catch (Exception ex)
{
    // Handle general errors
    _logger.LogError(ex, "Unexpected error during cache operation");
}

Integration Patterns

Dependency Injection

// In Startup.cs or Program.cs
services.AddSingleton<ICacheProvider>(provider =>
{
    var connectionString = configuration.GetConnectionString("Redis");
    var config = new RestConfig();
    return new RedisCacheProvider(connectionString, config);
});

// In your service
public class ProductService
{
    private readonly ICacheProvider _cache;
    private readonly IProductRepository _repository;

    public ProductService(ICacheProvider cache, IProductRepository repository)
    {
        _cache = cache;
        _repository = repository;
    }

    public async Task<Product> GetProductAsync(string id)
    {
        var cacheKey = $"product:{id}";

        var cached = await _cache.GetAsync<Product>(cacheKey);
        if (cached != null) return cached;

        var product = await _repository.GetByIdAsync(id);
        if (product != null)
        {
            await _cache.SetAsync(cacheKey, product, TimeSpan.FromMinutes(10));
        }

        return product;
    }
}

Session Management

public class SessionManager
{
    private readonly ICacheProvider _cache;

    public SessionManager(ICacheProvider cache)
    {
        _cache = cache;
    }

    public async Task<UserSession> GetSessionAsync(string sessionId)
    {
        return await _cache.GetAsync<UserSession>($"session:{sessionId}");
    }

    public async Task SetSessionAsync(string sessionId, UserSession session)
    {
        await _cache.SetAsync($"session:{sessionId}", session, TimeSpan.FromHours(24));
    }

    public async Task InvalidateSessionAsync(string sessionId)
    {
        await _cache.RemoveAsync($"session:{sessionId}");
    }
}

Configuration

Authentication Configuration

var config = new RestConfig
{
    AuthSecret = "your-redis-password" // Redis password
};
var cacheProvider = new RedisCacheProvider("localhost:6379", config);

Legacy Connection String Options (Still Supported)

// Basic connection
"localhost:6379"

// With authentication
"localhost:6379,password=your-password"

// Multiple endpoints with failover
"server1:6379,server2:6379,server3:6379"

// With SSL
"your-redis-instance.com:6380,ssl=true,password=your-password"

// Azure Redis Cache
"your-cache.redis.cache.windows.net:6380,password=your-access-key,ssl=true"

RestConfig Configuration

var config = new RestConfig
{
    // Configure serialization, logging, and other options
    // Refer to OElite.Restme documentation for details
};

Performance Considerations

Connection Multiplexing

The Redis provider uses StackExchange.Redis connection multiplexing for optimal performance:

// Single connection is reused across all operations
var provider = new RedisCacheProvider(connectionString, config);

// All operations share the same connection pool
await provider.SetAsync("key1", data1);
await provider.SetAsync("key2", data2);
await provider.GetAsync<Data>("key1");

Serialization Performance

  • Strings: Direct storage without serialization overhead
  • Objects: JSON serialization using Newtonsoft.Json
  • Large Objects: Consider compression for objects > 1MB

Key Naming Strategies

Use consistent, hierarchical key naming:

// Good: Hierarchical and descriptive
"user:profile:123"
"product:details:456"
"session:auth:abc-def"

// Avoid: Generic or unclear
"data123"
"temp"
"cache_item"

Integration with OElite Platform

With OElite.Restme.Hosting

// Register with ASP.NET Core DI
services.AddOEliteRedisCache(configuration.GetConnectionString("Redis"));

// Use IDistributedCache interface
services.AddSingleton<IDistributedCache, RedisDistributedCache>();

With OElite.Common

// Leverage shared types and utilities
var cacheKey = CacheKeyBuilder.Build("user", userId);
await cacheProvider.SetAsync(cacheKey, user, CachePolicy.Standard);

Error Handling

Common exceptions and handling strategies:

try
{
    await cacheProvider.GetAsync<Data>("key");
}
catch (OEliteException ex) when (ex.Message.Contains("connection"))
{
    // Connection issues - implement fallback
    _logger.LogWarning("Redis connection failed, falling back to database");
}
catch (OEliteException ex) when (ex.Message.Contains("serialization"))
{
    // Serialization issues - data corruption or type mismatch
    _logger.LogError("Cache data serialization failed: {Error}", ex.Message);
    await cacheProvider.RemoveAsync("key"); // Remove corrupted data
}

Requirements

  • .NET 8.0, 9.0, or 10.0
  • StackExchange.Redis 2.9.17+
  • OElite.Restme (dependency for base abstractions)

Thread Safety

RedisCacheProvider is thread-safe and designed for concurrent operations:

  • Uses connection multiplexing for thread safety
  • All async operations are thread-safe
  • Can be used as a singleton in DI containers

License

Copyright © Phanes Technology Ltd. All rights reserved.

Showing the top 20 packages that depend on OElite.Restme.Redis.

Packages Downloads
OElite.Restme.Hosting
ASP.NET Core integration extensions for OElite.Restme - provides DI registration, IDistributedCache adapters, and middleware
2
OElite.Restme.AspNetCore
ASP.NET Core integration extensions for OElite.Restme - provides DI registration, IDistributedCache adapters, and middleware
1
OElite.Restme.RateLimiting
Production-grade rate limiting middleware for ASP.NET Core applications with support for distributed scenarios, memory and Redis storage, and flexible configuration.
1
OElite.Common.Hosting
Package Description
0

.NET 8.0

.NET 9.0

.NET 10.0

Version Downloads Last updated
2.1.1-develop.568 1 01/16/2026
2.1.1-develop.521 0 01/13/2026
2.1.1-develop.520 0 01/13/2026
2.1.1-develop.519 0 01/13/2026
2.1.1-develop.518 0 01/13/2026
2.1.1-develop.516 0 01/13/2026
2.1.1-develop.513 0 01/13/2026
2.1.1-develop.508 0 01/13/2026
2.1.0-develop.449 0 01/13/2026
2.1.0-develop.445 0 01/13/2026
2.0.9-develop.442 0 01/13/2026
2.0.9-develop.434 0 01/13/2026
2.0.9-develop.433 0 01/13/2026
2.0.9-develop.432 0 01/13/2026
2.0.9-develop.430 0 01/13/2026
2.0.9-develop.420 0 01/13/2026
2.0.9-develop.419 0 01/13/2026
2.0.9-develop.418 0 01/13/2026
2.0.9-develop.414 0 01/13/2026
2.0.9-develop.413 0 01/13/2026
2.0.9-develop.398 0 01/13/2026
2.0.9-develop.393 0 01/13/2026
2.0.9-develop.390 0 01/13/2026
2.0.9-develop.388 0 01/13/2026
2.0.9-develop.386 0 01/13/2026
2.0.9-develop.257 0 01/13/2026
2.0.9-develop.256 0 01/13/2026
2.0.9-develop.255 0 01/13/2026
2.0.9-develop.254 0 01/13/2026
2.0.9-develop.253 0 01/13/2026
2.0.9-develop.252 0 01/13/2026
2.0.9-develop.251 0 01/13/2026
2.0.9-develop.250 0 01/13/2026
2.0.9-develop.249 0 01/13/2026
2.0.9-develop.248 0 01/13/2026
2.0.9-develop.247 0 01/13/2026
2.0.9-develop.246 0 01/13/2026
2.0.9-develop.245 0 01/13/2026
2.0.9-develop.243 0 01/13/2026
2.0.9-develop.242 0 01/13/2026
2.0.9-develop.241 0 01/13/2026
2.0.9-develop.233 0 01/13/2026
2.0.9-develop.232 0 01/13/2026
2.0.9-develop.230 0 01/13/2026
2.0.9-develop.229 0 01/13/2026
2.0.9-develop.228 0 01/13/2026
2.0.9-develop.223 0 01/13/2026
2.0.9-develop.221 0 01/13/2026
2.0.9-develop.220 0 01/13/2026
2.0.9-develop.214 0 01/13/2026
2.0.9-develop.213 0 01/13/2026
2.0.9-develop.208 0 01/13/2026
2.0.9-develop.207 0 01/13/2026
2.0.9-develop.204 0 01/13/2026
2.0.9-develop.192 0 01/13/2026
2.0.9-develop.191 0 01/13/2026
2.0.9-develop.190 0 01/13/2026
2.0.9-develop.143 0 01/13/2026
2.0.9-develop.142 0 01/13/2026
2.0.9-develop.135 0 01/13/2026
2.0.9-develop.90 0 01/13/2026
2.0.9-develop.79 0 01/13/2026
2.0.9-develop.74 0 01/13/2026
2.0.9-develop.73 0 01/13/2026
2.0.9-develop.71 0 01/13/2026
2.0.9-develop.70 0 01/13/2026
2.0.9-develop.69 0 01/13/2026
2.0.9-develop.68 0 01/13/2026
2.0.9-develop.67 0 01/13/2026
2.0.9-develop.66 0 01/13/2026
2.0.9-develop.65 0 01/13/2026
2.0.9-develop.64 0 01/13/2026
2.0.9-develop.50 0 01/13/2026
2.0.9-develop.49 0 01/13/2026
2.0.9-develop.48 0 01/13/2026
2.0.8-develop.31 0 01/13/2026
2.0.7-develop.30 0 01/13/2026
2.0.6-develop.29 0 01/13/2026
2.0.6-develop.27 0 01/13/2026
2.0.5-develop.26 0 01/13/2026
2.0.5-develop.25 0 01/13/2026