OElite.Restme.Hosting 2.1.1

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

OElite.Restme.Hosting

NuGet Version Target Framework

ASP.NET Core integration extensions for OElite.Restme - provides dependency injection, IDistributedCache adapters, and middleware for seamless integration with Hosting/ASP.NET Core applications.

Purpose

This package decouples Hosting/ASP.NET Core-specific extensions from the core Restme packages, keeping the core libraries framework-agnostic while providing first-class Hositng/ASP.NET Core support.

Features

  • IDistributedCache adapter for OElite.Restme.Redis
  • IMemoryCache adapter for OElite.Restme memory provider
  • Memory distributed cache for in-memory IDistributedCache implementations
  • Dependency injection extensions for all Restme providers
  • Clean separation between core abstractions and framework integrations
  • Multi-framework support (net8.0, net9.0, net10.0)

Installation

dotnet add package OElite.Restme.Hosting

Usage

Redis Distributed Cache

Replace Microsoft.Extensions.Caching.StackExchangeRedis with OElite's Redis provider:

using OElite.Restme.Hosting.Redis;

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        // Option 1: Simple configuration
        builder.Services.AddRestmeRedisCache(
            connectionString: "localhost:6379",
            instanceName: "myapp:"
        );

        // Option 2: Configuration-based setup
        builder.Services.AddRestmeRedisCache(options =>
        {
            options.ConnectionString = builder.Configuration["oelite:data:redis:platform"];
            options.InstanceName = "myapp:";
        });

        var app = builder.Build();
        app.Run();
    }
}

Memory Cache

Replace Microsoft.Extensions.Caching.Memory with OElite's memory provider:

using OElite.Restme.Hosting.Memory;

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        // Option 1: IMemoryCache only
        builder.Services.AddRestmeMemoryCache("myapp:");

        // Option 2: Both IMemoryCache and IDistributedCache (in-memory)
        builder.Services.AddRestmeMemoryCacheWithDistributed("myapp:");

        // Option 3: Configuration-based setup
        builder.Services.AddRestmeMemoryCache(options =>
        {
            options.InstanceName = "myapp:";
        });

        var app = builder.Build();
        app.Run();
    }
}

Using IDistributedCache

Once registered, IDistributedCache is available for dependency injection:

public class MyService
{
    private readonly IDistributedCache _cache;

    public MyService(IDistributedCache cache)
    {
        _cache = cache;
    }

    public async Task<string?> GetCachedValueAsync(string key)
    {
        var bytes = await _cache.GetAsync(key);
        if (bytes == null) return null;

        return Encoding.UTF8.GetString(bytes);
    }

    public async Task SetCachedValueAsync(string key, string value, TimeSpan expiry)
    {
        var bytes = Encoding.UTF8.GetBytes(value);
        var options = new DistributedCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = expiry
        };

        await _cache.SetAsync(key, bytes, options);
    }
}

Using IMemoryCache

Once registered, IMemoryCache is available for dependency injection:

public class MyService
{
    private readonly IMemoryCache _cache;

    public MyService(IMemoryCache cache)
    {
        _cache = cache;
    }

    public string? GetCachedValue(string key)
    {
        if (_cache.TryGetValue(key, out var value))
        {
            return value?.ToString();
        }
        return null;
    }

    public void SetCachedValue(string key, string value, TimeSpan expiry)
    {
        var options = new MemoryCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = expiry
        };

        _cache.Set(key, value, options);
    }
}

Using ICacheProvider (OElite Native)

You can also use the OElite-native ICacheProvider interface for more control:

public class MyService
{
    private readonly ICacheProvider _cache;

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

    public async Task<MyObject?> GetCachedObjectAsync(string key)
    {
        // Automatic JSON deserialization
        return await _cache.GetAsync<MyObject>(key);
    }

    public async Task SetCachedObjectAsync(string key, MyObject obj, TimeSpan expiry)
    {
        // Automatic JSON serialization
        await _cache.SetAsync(key, obj, expiry);
    }
}

Configuration Structure

OElite Standard Configuration

{
  "oelite": {
    "data": {
      "redis": {
        "kortex": "redis.services.oelite.io:6379,db=0",
        "platform": "redis.services.oelite.io:6379,db=1",
        "obelisk": "redis.services.oelite.io:6379,db=2",
        "oesterling": "redis.services.oelite.io:6379,db=3"
      }
    }
  }
}

Reading Configuration

// Kortex server
var redisConnectionString = configuration.GetValue<string>("oelite:data:redis:kortex");

// Platform services
var redisConnectionString = configuration.GetValue<string>("oelite:data:redis:platform");

// Obelisk CRM
var redisConnectionString = configuration.GetValue<string>("oelite:data:redis:obelisk");

Benefits Over Microsoft Packages

Redis Cache

Feature Microsoft.Extensions.Caching.StackExchangeRedis OElite.Restme.Hosting
Abstraction Layer Direct StackExchange.Redis dependency OElite.Restme abstraction
Provider Swapping Requires code changes Config-based provider switching
JSON Serialization Manual Automatic with ICacheProvider
Framework Coupling Tightly coupled Decoupled (core packages are framework-agnostic)
OElite Ecosystem Not integrated First-class OElite integration

Memory Cache

Feature Microsoft.Extensions.Caching.Memory OElite.Restme.Hosting
Provider Interface IMemoryCache only Both IMemoryCache + ICacheProvider
JSON Serialization Manual object conversion Automatic with ICacheProvider
Distributed Option Separate registration required Single registration for both
Instance Isolation Global instance Instance-prefixed keys
OElite Ecosystem Not integrated First-class OElite integration

Architecture

┌─────────────────────────────────────────────────────────────┐
│  ASP.NET Core Application                                    │
│  - Uses IDistributedCache/IMemoryCache (framework abstractions) │
└─────────────┬───────────────────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────────────────┐
│  OElite.Restme.Hosting (This Package)                    │
│  - RedisDistributedCache (IDistributedCache adapter)        │
│  - RestmeMemoryCache (IMemoryCache adapter)                 │
│  - MemoryDistributedCache (in-memory IDistributedCache)     │
│  - ServiceCollectionExtensions (DI registration)            │
└─────────────┬───────────────────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────────────────┐
│  OElite.Restme.Redis / OElite.Restme (Memory)               │
│  - RedisCacheProvider (ICacheProvider implementation)       │
│  - MemoryCacheProvider (ICacheProvider implementation)      │
└─────────────┬───────────────────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────────────────┐
│  OElite.Restme (Core)                                        │
│  - ICacheProvider (abstraction)                              │
│  - RestConfig (configuration)                                │
└─────────────┬───────────────────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────────────────┐
│  StackExchange.Redis / In-Memory                             │
│  - Low-level Redis client / .NET Dictionary                  │
└─────────────────────────────────────────────────────────────┘

Migration from Microsoft.Extensions.Caching.StackExchangeRedis

Before (Microsoft):

services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = "localhost:6379";
    options.InstanceName = "myapp:";
});

After (OElite):

using OElite.Restme.Hosting.Redis;

services.AddRestmeRedisCache(options =>
{
    options.ConnectionString = "localhost:6379";
    options.InstanceName = "myapp:";
});

No other code changes required! IDistributedCache works exactly the same.

Migration from Microsoft.Extensions.Caching.Memory

Before (Microsoft):

services.AddMemoryCache();

After (OElite):

using OElite.Restme.Hosting.Memory;

// Option 1: IMemoryCache only
services.AddRestmeMemoryCache("myapp:");

// Option 2: Both IMemoryCache and IDistributedCache
services.AddRestmeMemoryCacheWithDistributed("myapp:");

No other code changes required! IMemoryCache works exactly the same.

🔧 Enhanced Cache Extension Methods

The package provides powerful extension methods that work with both IDistributedCache and IMemoryCache, offering Rest-style API with advanced features:

DistributedCacheExtensions

Enhanced methods for IDistributedCache with grace period support and query object caching:

FindmeAsync Methods
// Basic find with refresh action
public static async Task<T?> FindmeAsync<T>(this IDistributedCache cache,
    string key,
    bool returnExpired = false,
    bool returnInGrace = true,
    Func<T, Task<bool>>? additionalValidation = null,
    Func<Task<T>>? refreshAction = null,
    CancellationToken cancellationToken = default) where T : class;

// Query object-based find with MD5 key generation
public static async Task<T?> FindmeAsync<T>(this IDistributedCache cache,
    object queryObject,
    bool returnExpired = false,
    bool returnInGrace = true,
    Func<T, Task<bool>>? additionalValidation = null,
    Func<Task<T>>? refreshAction = null,
    CancellationToken cancellationToken = default) where T : class;
CachemeAsync Methods
// Basic cache with expiry and grace period
public static async Task CachemeAsync<T>(this IDistributedCache cache,
    string key,
    T data,
    int expiryInSeconds = -1,
    int graceInSeconds = -1,
    CancellationToken cancellationToken = default) where T : class;

// Query object-based cache with MD5 key generation
public static async Task CachemeAsync<T>(this IDistributedCache cache,
    object queryObject,
    T data,
    int expiryInSeconds = -1,
    int graceInSeconds = -1,
    CancellationToken cancellationToken = default) where T : class;
ExpiremeAsync Methods
// Basic expiry with grace period options
public static async Task<bool> ExpiremeAsync(this IDistributedCache cache,
    string key,
    bool invalidateGracePeriod = true,
    CancellationToken cancellationToken = default);

// Query object-based expiry with MD5 key generation
public static async Task<bool> ExpiremeAsync<T>(this IDistributedCache cache,
    object queryObject,
    bool invalidateGracePeriod = true,
    CancellationToken cancellationToken = default);

MemoryCacheExtensions

Enhanced methods for IMemoryCache with similar functionality:

FindmeAsync Methods
// Basic find with refresh action
public static async Task<T?> FindmeAsync<T>(this IMemoryCache cache,
    string key,
    bool returnExpired = false,
    bool returnInGrace = true,
    Func<T, Task<bool>>? additionalValidation = null,
    Func<Task<T>>? refreshAction = null,
    CancellationToken cancellationToken = default) where T : class;

// Query object-based find with MD5 key generation
public static async Task<T?> FindmeAsync<T>(this IMemoryCache cache,
    object queryObject,
    bool returnExpired = false,
    bool returnInGrace = true,
    Func<T, Task<bool>>? additionalValidation = null,
    Func<Task<T>>? refreshAction = null,
    CancellationToken cancellationToken = default) where T : class;
CachemeAsync Methods
// Basic cache with expiry and grace period
public static void CachemeAsync<T>(this IMemoryCache cache,
    string key,
    T data,
    int expiryInSeconds = -1,
    int graceInSeconds = -1) where T : class;

// Query object-based cache with MD5 key generation
public static void CachemeAsync<T>(this IMemoryCache cache,
    object queryObject,
    T data,
    int expiryInSeconds = -1,
    int graceInSeconds = -1) where T : class;
ExpiremeAsync Methods
// Basic expiry with grace period options
public static bool ExpiremeAsync(this IMemoryCache cache,
    string key,
    bool invalidateGracePeriod = true);

// Query object-based expiry with MD5 key generation
public static bool ExpiremeAsync<T>(this IMemoryCache cache,
    object queryObject,
    bool invalidateGracePeriod = true);

🎯 Advanced Usage Examples

Basic Cache Operations
public class ProductService
{
    private readonly IDistributedCache _cache;

    public ProductService(IDistributedCache cache) => _cache = cache;

    public async Task<Product?> GetProductAsync(int productId)
    {
        // Try cache first with automatic refresh
        return await _cache.FindmeAsync<Product>(
            key: $"product:{productId}",
            refreshAction: async () => await FetchProductFromDatabase(productId)
        );
    }

    public async Task CacheProductAsync(Product product)
    {
        // Cache with 1 hour expiry and 30 minute grace period
        await _cache.CachemeAsync($"product:{product.Id}", product, 3600, 1800);
    }

    public async Task InvalidateProductAsync(int productId)
    {
        // Expire immediately
        await _cache.ExpiremeAsync($"product:{productId}", invalidateGracePeriod: true);
    }
}
Query Object Caching
public class ProductSearchService
{
    private readonly IDistributedCache _cache;

    public ProductSearchService(IDistributedCache cache) => _cache = cache;

    public async Task<List<Product>> SearchProductsAsync(ProductSearchQuery query)
    {
        // Use query object for automatic MD5 key generation
        return await _cache.FindmeAsync<List<Product>>(
            queryObject: query,
            refreshAction: async () => await ExecuteProductSearch(query)
        );
    }

    public async Task CacheSearchResultsAsync(ProductSearchQuery query, List<Product> results)
    {
        // Cache search results using query object
        await _cache.CachemeAsync(query, results, expiryInSeconds: 1800); // 30 minutes
    }

    public async Task InvalidateSearchAsync<T>(ProductSearchQuery query)
    {
        // Invalidate specific search results
        await _cache.ExpiremeAsync<T>(query, invalidateGracePeriod: true);
    }
}
Grace Period and Validation
public class UserService
{
    private readonly IMemoryCache _cache;

    public UserService(IMemoryCache cache) => _cache = cache;

    public async Task<User?> GetUserAsync(int userId)
    {
        return await _cache.FindmeAsync<User>(
            key: $"user:{userId}",
            returnInGrace: true, // Allow stale data during refresh
            additionalValidation: async (user) =>
            {
                // Custom validation logic
                return user.IsActive && !user.IsDeleted;
            },
            refreshAction: async () => await FetchUserFromDatabase(userId)
        );
    }

    public async Task ExpireUserWithGraceAsync(int userId)
    {
        // Expire but allow grace period for smooth refresh
        _cache.ExpiremeAsync($"user:{userId}", invalidateGracePeriod: false);
    }
}

🔑 Key Features

1. Grace Period Support
  • Expiry vs Grace: Items can be expired but still served during grace period
  • Background Refresh: Automatic refresh triggers when items expire but are still in grace
  • Smooth UX: Users never experience cache misses during refresh
2. Query Object Caching
  • Automatic MD5 Keys: Complex query objects automatically generate consistent cache keys
  • Type Safety: Generic constraints ensure proper type handling
  • Serialization: JSON serialization of query objects for key generation
3. Validation and Refresh
  • Custom Validation: Optional validation functions for cached data
  • Automatic Refresh: Background refresh actions when cache misses or validation fails
  • Fallback Strategy: Graceful degradation when refresh actions fail
4. Rest-Style API Consistency
  • Familiar Methods: FindmeAsync, CachemeAsync, ExpiremeAsync match Rest patterns
  • Consistent Parameters: Same parameter patterns across all cache providers
  • Type Safety: Generic constraints ensure only Rest implementation types

🚀 Performance Benefits

  • Reduced Database Load: Grace period reduces database hits during refresh
  • Better User Experience: Stale data served instantly while fresh data loads in background
  • Efficient Key Management: MD5 hashing ensures consistent, collision-resistant keys
  • Memory Efficient: Proper expiry handling prevents memory leaks

🛡️ Error Handling

The extension methods include comprehensive error handling:

// Automatic fallback on cache failures
public async Task<Product?> GetProductSafelyAsync(int productId)
{
    try
    {
        return await _cache.FindmeAsync<Product>(
            $"product:{productId}",
            refreshAction: () => _repository.GetByIdAsync(productId)
        );
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Cache operation failed for product {ProductId}", productId);
        return await _repository.GetByIdAsync(productId); // Direct fallback
    }
}

Future Extensions

This package will be expanded to include:

  • Storage extensions: IFileStorage integration for S3/Azure providers
  • Queue extensions: Background job processing with RabbitMQ
  • Health checks: ASP.NET Core health check integrations
  • Middleware: Request caching, response compression, etc.
  • OElite.Restme - Core abstractions and interfaces
  • OElite.Restme.Redis - Redis cache provider
  • OElite.Restme.RabbitMQ - RabbitMQ queue provider
  • OElite.Restme.S3 - S3 storage provider

License

Copyright © Phanes Technology Ltd. All rights reserved.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.1.1 230 7/21/2026
2.0.9 335 11/11/2025