A powerful, modular .NET library that provides a unified interface for HTTP requests, caching, message queuing, and cloud storage operations. Built with modern .NET and designed for simplicity, performance, and flexibility.
- Unified API: Single
Restclass for all operations - Modular Architecture: Load only the backends you need
- Multiple Backend Support: Redis, RabbitMQ, Azure Blob Storage, S3-compatible providers
- Cache Providers: Redis, Azure Blob Storage, S3 (perfect for CDN scenarios)
- S3-Compatible: Support for Backblaze B2, MinIO, DigitalOcean Spaces, and more
- Async/Await: Full async support throughout
- Dynamic Loading: Providers loaded automatically when packages are referenced
- Type Safety: Strong typing with generic methods
- JSON Serialization: Built-in JSON handling with custom serialization support
- Stream Support: Direct stream handling for file operations
- Expiry Support: TTL for cache operations
- CDN Ready: Proper cache headers for CDN integration
Install-Package OElite.Restme# Redis for caching and queuing
Install-Package OElite.Restme.Redis
# RabbitMQ for message queuing
Install-Package OElite.Restme.RabbitMQ
# Azure Blob Storage for storage and caching
Install-Package OElite.Restme.Azure
# S3-compatible storage (AWS S3, Backblaze B2, MinIO, etc.)
Install-Package OElite.Restme.S3OElite.Restme uses a modular architecture where the core library provides abstractions and backend-specific implementations are loaded dynamically:
OElite.Restme (Core)
βββ Abstractions (ICacheProvider, IStorageProvider, etc.)
βββ Default Providers (Fallback implementations)
βββ Service Locator (Dynamic provider loading)
Backend Packages:
βββ OElite.Restme.Redis (Redis cache provider)
βββ OElite.Restme.RabbitMQ (RabbitMQ queue provider)
βββ OElite.Restme.Azure (Azure Blob Storage provider)
βββ OElite.Restme.S3 (S3-compatible storage provider)
using OElite;
// Initialize HTTP client
var rest = new Rest("https://api.example.com", new RestConfig { OperationMode = RestMode.Http });
// GET request
var user = await rest.GetAsync<User>("/users/123");
// POST request with data
var newUser = await rest.PostAsync<User>("/users", userData);
// PUT request
var updatedUser = await rest.PutAsync<User>("/users/123", updatedData);
// DELETE request
await rest.DeleteAsync("/users/123");// Add OElite.Restme.Redis package
var rest = new Rest("localhost:6379", RestMode.RedisCacheClient);
// Cache data with expiry
await rest.CachemeAsync("user:123", userData, 60); // 60 minutes
// Retrieve cached data
var cachedUser = await rest.FindmeAsync<User>("user:123");
// Remove from cache
await rest.RemovemeAsync("user:123");// Add OElite.Restme.Azure package
var connectionString = "DefaultEndpointsProtocol=https;AccountName=...;RootPath=my-app/uploads";
var rest = new Rest(connectionString, RestMode.AzureStorageClient);
// Store data (rootPath is automatically prefixed)
await rest.StoremAsync("documents/report.pdf", fileData); // Stored as "my-app/uploads/documents/report.pdf"
// Retrieve data
var fileData = await rest.RetrievemeAsync<byte[]>("documents/report.pdf");
// Use as cache (CDN-ready)
await rest.CachemeAsync("cache:key", data, TimeSpan.FromHours(1));// Add OElite.Restme.S3 package
// Amazon S3
var rest = new Rest("AccessKeyId=...;SecretAccessKey=...;Region=us-west-2", RestMode.S3Client);
// Backblaze B2 with root path
var rest = new Rest("AccessKeyId=...;SecretAccessKey=...;ServiceUrl=https://s3.us-west-004.backblazeb2.com;ForcePathStyle=true;RootPath=my-app/uploads", RestMode.S3Client);
// MinIO (local development) with root path
var rest = new Rest("AccessKeyId=minioadmin;SecretAccessKey=minioadmin;ServiceUrl=http://localhost:9000;ForcePathStyle=true;UseHttp=true;RootPath=dev/cache", RestMode.S3Client);
// Store and cache operations (rootPath is automatically prefixed)
await rest.StoremAsync("files/document.pdf", fileData); // Stored as "my-app/uploads/files/document.pdf"
await rest.CachemeAsync("cache:key", data, TimeSpan.FromHours(2)); // Cached as "dev/cache/cache:key"// Add OElite.Restme.RabbitMQ package
var rest = new Rest("amqp://localhost", RestMode.RabbitMq);
// Publish message
await rest.QueuemeAsync("user.created", userData);
// Consume messages
await rest.DomeAsync<User>("user.created", async (user) => {
// Process user
return true; // Continue processing
});Use built-in base providers for simple scenarios without external infrastructure.
using OElite;
// Memory cache
var restMemoryCache = new Rest(
configuration: new RestConfig { OperationMode = RestMode.MemoryAsCache }
);
await restMemoryCache.CachemeAsync("user:123", userData, TimeSpan.FromMinutes(30));
var cached = await restMemoryCache.FindmeAsync<User>("user:123");
// Local file system storage (uses default AppContext.BaseDirectory/restme_storage)
var restLocalFs = new Rest(
endPointOrConnectionString: "/var/data/myapp", // optional base directory; omit to use default
configuration: new RestConfig { OperationMode = RestMode.LocalFileSystemAsStorage }
);
await restLocalFs.StoremAsync("docs/report.pdf", fileBytes);
var file = await restLocalFs.RetrievemeAsync<byte[]>("docs/report.pdf");
// In-memory queue (single-process)
var restInMemoryQueue = new Rest(
configuration: new RestConfig { OperationMode = RestMode.InMemoryQueue }
);
await restInMemoryQueue.QueuemeAsync("events.user.created", newUser);
await restInMemoryQueue.DomeAsync<User>("events.user.created", async user => {
// handle user
return true;
});RestMode.Http- HTTP REST clientRestMode.RedisCacheClient- Redis cachingRestMode.AzureStorageClient- Azure Blob StorageRestMode.S3Client- S3-compatible storageRestMode.RabbitMq- RabbitMQ message queuingRestMode.MemoryAsCache- In-memory cache (base provider)RestMode.LocalFileSystemAsStorage- Local filesystem storage (base provider)RestMode.InMemoryQueue- In-process queue (base provider)
localhost:6379
redis://localhost:6379
redis://user:password@localhost:6379
DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=mykey;EndpointSuffix=core.windows.net;RootPath=my-app/uploads
AccessKeyId=your_key;SecretAccessKey=your_secret;ServiceUrl=https://your-endpoint.com;BucketName=your-bucket;ForcePathStyle=true;RootPath=my-app/uploads
amqp://localhost
amqp://user:password@localhost:5672
The Rest class provides generic operations that work across all backends:
var rest = new Rest(connectionString, RestMode.S3Client);
// GET - retrieves from cache or storage
var data = await rest.GetAsync<MyData>("key");
// POST - stores in both cache and storage
var result = await rest.PostAsync<MyData>("key", data, TimeSpan.FromHours(1));
// PUT - updates cache and storage
var updated = await rest.PutAsync<MyData>("key", updatedData, TimeSpan.FromHours(2));
// DELETE - removes from cache and storage
await rest.DeleteAsync<MyData>("key");Direct stream handling for file operations:
// Store stream directly
using var fileStream = File.OpenRead("document.pdf");
await rest.StoremAsync("documents/report.pdf", fileStream);
// Retrieve as stream
var stream = await rest.RetrievemeAsync<Stream>("documents/report.pdf");Advanced caching with expiry and CDN support:
// Cache with custom expiry
await rest.CachemeAsync("user:123", userData, TimeSpan.FromMinutes(30));
// Check if cached
var exists = await rest.ExistsmeAsync("user:123");
// Set expiry
await rest.ExpiremeAsync("user:123", TimeSpan.FromHours(1));
// Find with callback
var user = await rest.FindmeAsync<User>("user:123", async (u) => {
// Process user data
return true;
});Advanced message queuing patterns:
// Publish to specific exchange
await rest.QueuemeAsync("user.created", userData, "user-events", "user.created");
// Consume with completion condition
await rest.DomeAsync<User>("user.created",
messageHandler: async (user) => {
// Process user
return true;
},
completionCondition: async () => {
// Stop when no more messages
return false;
},
exchangeName: "user-events",
queueName: "user-processing"
);OElite.Restme.S3 supports numerous S3-compatible providers with advanced path management:
The RootPath parameter allows you to organize your storage with logical path prefixes. When specified, all operations will automatically prefix the provided path to your object keys.
Benefits:
- Environment Separation: Use different root paths for dev/staging/production
- Application Isolation: Separate different applications in the same bucket
- Logical Organization: Group related files under common prefixes
- Easy Migration: Change root paths without code changes
Example:
// Connection string with rootPath
var rest = new Rest("AccessKeyId=...;SecretAccessKey=...;RootPath=my-app/uploads", RestMode.S3Client);
// Operations automatically use the root path
await rest.StoremAsync("documents/file.pdf", data); // Stored as "my-app/uploads/documents/file.pdf"
await rest.CachemeAsync("user:123", userData); // Cached as "my-app/uploads/user:123"
// Root path is applied to all operations (GET, PUT, DELETE, EXISTS)
var file = await rest.RetrievemeAsync<byte[]>("documents/file.pdf"); // Retrieves from "my-app/uploads/documents/file.pdf"Connection String Parameters:
AccessKeyId- S3 access key IDSecretAccessKey- S3 secret access keyServiceUrl- S3 endpoint URL (for non-AWS providers)BucketName- S3 bucket nameRegion- AWS region (for AWS S3)ForcePathStyle- Use path-style URLs (required for most non-AWS providers)UseHttp- Use HTTP instead of HTTPS (for local development)RootPath- Logical prefix for all operations
Examples:
# AWS S3
AccessKeyId=AKIAIOSFODNN7EXAMPLE;SecretAccessKey=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY;Region=us-west-2
# Backblaze B2
AccessKeyId=your_key_id;SecretAccessKey=your_secret;ServiceUrl=https://s3.us-west-004.backblazeb2.com;ForcePathStyle=true;RootPath=myapp/data
# MinIO (Local)
AccessKeyId=minioadmin;SecretAccessKey=minioadmin;ServiceUrl=http://localhost:9000;ForcePathStyle=true;UseHttp=true;RootPath=dev/cache
| Package | Description | Latest Version |
|---|---|---|
| OElite.Restme | Core abstractions and HTTP client | |
| OElite.Restme.Utils | Utility extensions and helpers |
Advanced MongoDB library with comprehensive query capabilities, high-performance updates, aggregation pipelines, and denormalization system.
Key Features:
- High-Performance UpdateBuilder: 2-3x faster updates with fluent API and BSON optimization
- Enhanced LINQ Extensions: Complete LINQ support with advanced aggregation operations
- Type-safe MongoDB operations with full IntelliSense support
- Advanced aggregation pipelines for complex queries with expression-to-pipeline conversion
- Automatic denormalization for efficient data relationships
- Enhanced LINQ expression support with nested documents and extension methods
- Performance-optimized aggregation methods using MongoDB's native capabilities
- MongoDB class mapping with conflict resolution
- β MongoDB-Free Application Layer: Complete abstraction eliminates MongoDB dependencies from application code
- Zero Vendor Lock-in: Application developers work with pure .NET types and collections
- Clean Architecture: Perfect separation between business logic and database implementation
- π MongoDbDocument API: Replace BsonDocument with pure .NET Dictionary-based operations
- π IMongoDbCollection Interface: MongoDB-free collection operations with Dictionary and lambda support
- π Seamless Type Conversion: Internal MongoDB type conversion while exposing clean .NET APIs
Quick Example:
// Entity with denormalized fields
[DbCollection("products", DbNamingConvention.SnakeCase)]
public class Product : BaseEntity
{
[DbId] public DbObjectId Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
public DbObjectId CategoryId { get; set; }
[DenormalizedField("categories", "name", "@CategoryId")]
public string CategoryName { get; set; } = string.Empty;
}
// Repository with enhanced LINQ support and high-performance updates
public class ProductRepository : DataRepository
{
public MongoQuery<Product> ProductStock => new(_adapter.GetCollection<Product>());
// Enhanced LINQ queries with extension method support
public async Task<List<Product>> GetExpensiveProductsAsync(decimal minPrice)
{
return await ProductStock
.Where(p => p.Price > minPrice)
.Where(p => p.Name.IsNotNullOrEmpty()) // Extension method support
.OrderByDescending(p => p.Price)
.Take(10)
.ToListAsync();
}
// High-performance updates with fluent API
public async Task UpdateProductAsync(DbObjectId productId, string newName, decimal newPrice)
{
await ProductStock
.Where(p => p.Id == productId)
.UpdateAsync(u => u
.Set(p => p.Name, newName)
.Set(p => p.Price, newPrice)
.Inc(p => p.ViewCount, 1)
.CurrentDate(p => p.UpdatedAt));
}
// Advanced aggregation operations
public async Task<List<ProductSummary>> GetProductSummariesAsync()
{
return await ProductStock
.Where(p => p.Status == EntityStatus.Active)
.SelectAsync(p => new ProductSummary
{
Name = p.Name,
Price = p.Price,
CategoryName = p.Category.Name // Nested property support
});
}
// Performance-optimized collection fetching
public async Task<ProductCollection> GetActiveProductsAsync(int pageIndex, int pageSize)
{
return await ProductStock
.Where(p => p.Status == EntityStatus.Active)
.OrderBy(p => p.Name)
.FetchAsync<Product, ProductCollection>(pageIndex, pageSize, returnTotalCount: false);
}
// β MongoDB-Free Aggregation: Zero MongoDB dependencies in application code
public async Task<List<(string Query, int Count)>> GetPopularSearchTermsAsync(DbObjectId merchantId)
{
// Complex aggregation pipeline using pure Dictionary<string, object>
var pipeline = new Dictionary<string, object>[]
{
new Dictionary<string, object> {
["$match"] = new Dictionary<string, object> {
["ownerMerchantId"] = merchantId.ToString(),
["searchedOnUtc"] = new Dictionary<string, object> { ["$gte"] = DateTime.UtcNow.AddDays(-7) }
}
},
new Dictionary<string, object> {
["$group"] = new Dictionary<string, object> {
["_id"] = "$normalizedQuery",
["count"] = new Dictionary<string, object> { ["$sum"] = 1 }
}
},
new Dictionary<string, object> {
["$sort"] = new Dictionary<string, object> { ["count"] = -1 }
},
new Dictionary<string, object> {
["$limit"] = 10
}
};
// Returns List<Dictionary<string, object>> - no MongoDB types exposed
var results = await DbCentre.SearchHistory.AggregateAsync<Dictionary<string, object>>(pipeline);
// Application code uses standard .NET types
return results.Select(doc => (
Query: (string)doc["_id"],
Count: (int)doc["count"]
)).ToList();
}
// π MongoDB-Free Collection Operations: New API for zero-dependency database operations
public async Task<List<Product>> GetProductsWithMongoDbFreeAPI(string categoryName)
{
// Get MongoDB-free collection interface - no MongoDB types exposed
var productsCollection = DbCentre.GetMongoDbCollection<Product>();
// Use strongly-typed operations with lambda expressions
var activeProducts = await productsCollection.FindAsync(p => p.Status == EntityStatus.Active);
// Or use Dictionary-based filters for dynamic queries
var categoryFilter = new Dictionary<string, object>
{
["categoryName"] = categoryName,
["status"] = (int)EntityStatus.Active
};
var categoryProducts = await productsCollection.FindAsync(categoryFilter);
return categoryProducts;
}
// π MongoDbDocument API: Direct document operations without MongoDB dependencies
public async Task<List<MongoDbDocument>> GetProductDocuments(string searchTerm)
{
// Get raw MongoDB-free collection for document operations
var collection = DbCentre.GetMongoDbCollection("products");
// Create filter using MongoDbDocument (replaces BsonDocument)
var filter = new MongoDbDocument
{
["name"] = new MongoDbDocument { ["$regex"] = searchTerm, ["$options"] = "i" },
["status"] = 1
};
// Returns List<MongoDbDocument> - pure .NET types, no MongoDB dependencies
var results = await collection.FindAsync(filter);
return results;
}
}OElite.Restme.MongoDb provides complete abstraction from MongoDB specifics, ensuring your application code remains vendor-neutral and testable.
Before (Traditional MongoDB.Driver usage):
using MongoDB.Driver; // β Direct MongoDB dependency
using MongoDB.Bson; // β Exposes internal types
public async Task<List<BsonDocument>> GetReports() // β MongoDB types in return signature
{
var collection = _database.GetCollection<BsonDocument>("reports");
var pipeline = new BsonDocument[] // β MongoDB-specific pipeline format
{
new BsonDocument("$match", new BsonDocument("status", "active")),
new BsonDocument("$group", new BsonDocument
{
{ "_id", "$category" },
{ "count", new BsonDocument("$sum", 1) }
})
};
var cursor = await collection.AggregateAsync(pipeline);
return await cursor.ToListAsync(); // β Returns MongoDB-specific types
}After (OElite.Restme.MongoDb with MongoDB-Free API):
// β
Zero MongoDB dependencies - clean application code
public async Task<List<(string Category, int Count)>> GetReports() // β
Pure .NET return types
{
// Get MongoDB-free collection interface
var reportsCollection = DbCentre.GetMongoDbCollection("reports");
var pipeline = new Dictionary<string, object>[] // β
Standard .NET collections
{
new Dictionary<string, object> {
["$match"] = new Dictionary<string, object> { ["status"] = "active" }
},
new Dictionary<string, object> {
["$group"] = new Dictionary<string, object> {
["_id"] = "$category",
["count"] = new Dictionary<string, object> { ["$sum"] = 1 }
}
}
};
// β
Returns List<Dictionary<string, object>> - no MongoDB types
var results = await reportsCollection.AggregateAsync(pipeline);
// β
Application code works with standard .NET types
return results.Select(doc => (
Category: (string)doc["_id"],
Count: (int)doc["count"]
)).ToList();
}
// π NEW: MongoDbDocument API (replaces BsonDocument)
public async Task<List<MongoDbDocument>> GetActiveReportsAsync()
{
var reportsCollection = DbCentre.GetMongoDbCollection("reports");
// Create filter using MongoDbDocument instead of BsonDocument
var filter = new MongoDbDocument
{
["status"] = "active",
["createdAt"] = new MongoDbDocument { ["$gte"] = DateTime.UtcNow.AddDays(-30) }
};
// β
Returns List<MongoDbDocument> - pure .NET types
return await reportsCollection.FindAsync(filter);
}
// π NEW: Strongly-typed MongoDB-free operations
public async Task<List<Report>> GetReportsWithTypedAPI()
{
var reportsCollection = DbCentre.GetMongoDbCollection<Report>();
// Lambda expressions - no MongoDB types needed
var reports = await reportsCollection.FindAsync(r => r.Status == "active");
// Dictionary filters for dynamic queries
var dynamicFilter = new Dictionary<string, object>
{
["status"] = "active",
["priority"] = new Dictionary<string, object> { ["$in"] = new[] { "high", "urgent" } }
};
var priorityReports = await reportsCollection.FindAsync(dynamicFilter);
return reports;
}Architecture Benefits:
- π― Zero Vendor Lock-in: Switch databases without changing application logic
- π§ͺ Enhanced Testability: Mock with standard .NET interfaces and collections
- π Clean Domain Models: Business logic free from infrastructure concerns
- π Future-Proof: Database implementation changes don't affect application code
- π₯ Developer Experience: Team members don't need MongoDB expertise for application development
ASP.NET Core integration extensions providing dependency injection, cache adapters, and middleware.
Key Features:
- IDistributedCache and IMemoryCache adapters
- Dependency injection extensions for all providers
- Clean separation between core and framework integrations
- Multi-framework support (.NET 8+)
- Redis and Memory cache implementations
Quick Example:
// Replace Microsoft.Extensions.Caching.StackExchangeRedis
builder.Services.AddRestmeRedisCache(options =>
{
options.ConnectionString = "localhost:6379";
options.InstanceName = "myapp:";
});
// Or use memory cache with both IMemoryCache and IDistributedCache
builder.Services.AddRestmeMemoryCacheWithDistributed("myapp:");
// Use in controllers exactly like Microsoft's caching
public class ProductController : ControllerBase
{
private readonly IDistributedCache _cache;
public ProductController(IDistributedCache cache) => _cache = cache;
public async Task<Product> GetAsync(int id)
{
var cached = await _cache.GetStringAsync($"product:{id}");
if (cached != null) return JsonSerializer.Deserialize<Product>(cached);
// Fetch and cache...
}
}Enterprise-grade rate limiting middleware with advanced DDoS protection and adaptive limiting.
Key Features:
- Multiple algorithms: Fixed Window, Token Bucket, Sliding Window, Leaky Bucket
- DDoS protection with progressive blocking
- Emergency mode for severe attacks
- Adaptive limiting based on server load
- Distributed Redis storage for multi-instance deployments
- RFC 6585 compliant with proper HTTP headers
Quick Example:
builder.Services.AddRateLimiting(options =>
{
options.Limit = 1000;
options.WindowInSeconds = 60;
options.EnableDDoSProtection = true;
options.DDoSThreshold = 5000;
options.EmergencyMode.Enabled = true;
options.Algorithm = RateLimitAlgorithm.TokenBucket;
options.StorageType = RateLimitStorageType.Redis;
});
app.UseRateLimiting();Utility extensions and helper methods for common operations.
Key Features:
- String extension methods (
IsNotNullOrEmpty(), etc.) - Collection helpers and LINQ extensions
- Validation utilities
- Data transformation helpers
Google Cloud Platform integrations and utilities.
Key Features:
- Google Cloud Storage integration
- Google Authentication helpers
- Firebase utilities
- Google API client extensions
The Hosting package provides powerful cache extensions that work with both IDistributedCache and IMemoryCache:
// Enhanced cache methods with Rest-style API
public static class CacheExtensions
{
// Find cached data with advanced features
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;
// Cache data 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;
// Expire cached data with grace period options
public static async Task<bool> ExpiremeAsync(this IDistributedCache cache,
string key,
bool invalidateGracePeriod = true,
CancellationToken cancellationToken = default);
// Query object-based caching 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;
}Usage Example:
public class ProductService
{
private readonly IDistributedCache _cache;
public ProductService(IDistributedCache cache) => _cache = cache;
public async Task<Product?> GetProductAsync(int productId)
{
// Try cache first with refresh callback
return await _cache.FindmeAsync<Product>(
key: $"product:{productId}",
refreshAction: async () => await FetchProductFromDatabase(productId)
);
}
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 InvalidateProductCacheAsync(int productId)
{
// Expire with grace period (allows stale data during refresh)
await _cache.ExpiremeAsync($"product:{productId}", invalidateGracePeriod: false);
}
}# Install packages
dotnet add package OElite.Restme.Hosting
dotnet add package OElite.Restme.Redis// Program.cs
builder.Services.AddRestmeRedisCache("localhost:6379", "myapi:");
// Controller
public class ProductController : ControllerBase
{
private readonly IDistributedCache _cache;
[HttpGet("{id}")]
public async Task<Product?> Get(int id)
{
return await _cache.FindmeAsync<Product>(
$"product:{id}",
refreshAction: () => _repository.GetByIdAsync(id)
);
}
}# Install packages
dotnet add package OElite.Restme.MongoDb
dotnet add package OElite.Restme.RateLimiting
dotnet add package OElite.Restme.Hosting// Program.cs
builder.Services.AddRateLimiting(options =>
{
options.Limit = 1000;
options.EnableDDoSProtection = true;
options.StorageType = RateLimitStorageType.Redis;
});
builder.Services.AddRestmeRedisCache("localhost:6379", "api:");
// Repository with enhanced MongoDB operations
public class ProductRepository : DataRepository
{
public MongoQuery<Product> Products => new(_adapter.GetCollection<Product>());
// High-performance LINQ queries with aggregation
public async Task<ProductCollection> GetPopularProductsAsync(int pageIndex, int pageSize)
{
return await Products
.Where(p => p.Status == EntityStatus.Active)
.Where(p => p.Rating > 4.0)
.OrderByDescending(p => p.SalesCount)
.FetchAsync<Product, ProductCollection>(pageIndex, pageSize, returnTotalCount: true);
}
// Advanced aggregation operations
public async Task<List<CategorySummary>> GetCategoryStatisticsAsync()
{
return await Products
.Where(p => p.Status == EntityStatus.Active)
.SelectAsync(p => new CategorySummary
{
CategoryId = p.CategoryId,
CategoryName = p.Category.Name,
TotalProducts = 1,
AveragePrice = p.Price
});
}
// High-performance batch updates
public async Task UpdateProductPricesAsync(decimal categoryId, decimal priceMultiplier)
{
await Products
.Where(p => p.CategoryId == categoryId)
.UpdateAsync(u => u
.Mul(p => p.Price, priceMultiplier)
.Inc(p => p.UpdateCount, 1)
.CurrentDate(p => p.UpdatedAt));
}
// Server-side mathematical operations
public async Task<decimal> GetCategoryTotalValueAsync(DbObjectId categoryId)
{
return await Products
.Where(p => p.CategoryId == categoryId)
.Where(p => p.Status == EntityStatus.Active)
.SumAsync(p => p.Price);
}
}# Install packages
dotnet add package OElite.Restme
dotnet add package OElite.Restme.S3
dotnet add package OElite.Restme.RabbitMQ
dotnet add package OElite.Restme.Redispublic class DocumentService
{
private readonly Rest _storage; // S3 for file storage
private readonly Rest _cache; // Redis for caching
private readonly Rest _queue; // RabbitMQ for events
public DocumentService()
{
_storage = new Rest("AccessKeyId=...;ServiceUrl=https://s3.amazonaws.com", RestMode.S3Client);
_cache = new Rest("localhost:6379", RestMode.RedisCacheClient);
_queue = new Rest("amqp://localhost", RestMode.RabbitMq);
}
public async Task<byte[]> GetDocumentAsync(string documentId)
{
// Try cache first
var cached = await _cache.FindmeAsync<byte[]>($"doc:{documentId}");
if (cached != null) return cached;
// Fetch from storage
var document = await _storage.RetrievemeAsync<byte[]>($"documents/{documentId}");
// Cache for future requests
await _cache.CachemeAsync($"doc:{documentId}", document, TimeSpan.FromHours(1));
return document;
}
public async Task SaveDocumentAsync(string documentId, byte[] data)
{
// Save to storage
await _storage.StoremAsync($"documents/{documentId}", data);
// Invalidate cache
await _cache.RemovemeAsync($"doc:{documentId}");
// Publish event
await _queue.QueuemeAsync("document.saved", new { DocumentId = documentId });
}
}- Core only: Use
OElite.Restmefor HTTP clients - ASP.NET Core: Add
OElite.Restme.Hostingfor DI integration - Caching: Use
OElite.Restme.Redisor memory providers - Database: Add
OElite.Restme.MongoDbfor MongoDB operations - Security: Include
OElite.Restme.RateLimitingfor protection
// Use configuration sections
builder.Services.Configure<RedisOptions>(
builder.Configuration.GetSection("Redis")
);
// Environment-based configuration
var redisConnection = builder.Configuration.GetConnectionString("Redis")
?? Environment.GetEnvironmentVariable("REDIS_CONNECTION");// Graceful degradation for cache failures
public async Task<Product?> GetProductAsync(int id)
{
try
{
return await _cache.FindmeAsync<Product>($"product:{id}");
}
catch (Exception ex)
{
_logger.LogError(ex, "Cache error for product {ProductId}", id);
return await _repository.GetByIdAsync(id); // Fallback to database
}
}// Use appropriate data structures
public async Task<ProductCollection> GetProductsByCategoryAsync(int categoryId)
{
return await Products
.Where(p => p.CategoryId == categoryId)
.Where(p => p.Status == EntityStatus.Active)
.OrderBy(p => p.Name)
.FetchAsync<Product, ProductCollection>(returnTotalCount: false); // Skip count for better performance
}- Documentation: OElite Platform Wiki
- Examples: GitHub Examples Repository
- API Reference: API Documentation
- Support: GitHub Issues
This project is licensed under the MIT License. See LICENSE file for details.
OElite.Restme - Unifying your data operations across HTTP, caching, storage, and messaging