BlitzCache 2.1.1
dotnet add package BlitzCache --version 2.1.1
NuGet\Install-Package BlitzCache -Version 2.1.1
<PackageReference Include="BlitzCache" Version="2.1.1" />
<PackageVersion Include="BlitzCache" Version="2.1.1" />
<PackageReference Include="BlitzCache" />
paket add BlitzCache --version 2.1.1
#r "nuget: BlitzCache, 2.1.1"
#:package BlitzCache@2.1.1
#addin nuget:?package=BlitzCache&version=2.1.1
#tool nuget:?package=BlitzCache&version=2.1.1
โก BlitzCache
๐ Enterprise-grade caching that's ridiculously simple to use
One line of code prevents duplicate execution of expensive operations. BlitzCache is production-ready, ultra-fast (0.0001ms operations), and completely thread-safe. No configuration required.
โจ Why BlitzCache?
The Problem: Multiple concurrent calls = Multiple expensive operations
// Without BlitzCache: Expensive operations run multiple times
Task.Run(() => ExpensiveApiCall()); // Executes
Task.Run(() => ExpensiveApiCall()); // Executes again! ๐ธ
Task.Run(() => ExpensiveApiCall()); // And again! ๐ธ๐ธ
The Solution: One line of code changes everything
// With BlitzCache: One execution, all callers get the result
Task.Run(() => cache.BlitzGet("api-call", ExpensiveApiCall)); // Executes once
Task.Run(() => cache.BlitzGet("api-call", ExpensiveApiCall)); // Waits for result โณ
Task.Run(() => cache.BlitzGet("api-call", ExpensiveApiCall)); // Waits for result โณ
// All concurrent calls receive the SAME result when the first one completes!
๐ก๏ธ The Thundering Herd Protection
// Scenario: 100 users hit your API at the exact same moment
for (int i = 0; i < 100; i++)
{
Task.Run(async () => {
// Without BlitzCache: 100 SQL queries hit your database simultaneously ๐ฅ
// With BlitzCache: Only 1 SQL query executes, 99 others wait and get the result โก
var userData = await cache.BlitzGet($"user_{userId}",
() => database.GetSlowUserData(userId),
300000);
});
}
๐ Automatic Statistics
[12:51:32 INF] ***[Customers-Microservice] BlitzCache Statistics***
Hits: 22
Misses: 24
Hit Ratio: 47.83 %
Entries: 2
Evictions: 20
Active Semaphores: 0
Total Operations: 46
Approx. Memory: 120.75 KB
Top Heaviest:
users_cache - ~96 KB
products_cache - ~20 KB
Top Slowest Queries:
LoadBlitzSafe_UsageFromView_819735987 - Worse: 18266ms | Best: 93ms | Avg: 2014 | Occurrences: 10
LoadBlitzSafe_MarketingView_819735987 - Worse: 8608ms | Best: 198ms | Avg: 4403 | Occurrences: 2
LoadBlitzSafe_BillingView_-2041290683 - Worse: 655ms | Best: 107ms | Avg: 228 | Occurrences: 7
CalculateAllDatesFromMarketing - Worse: 408ms | Best: 34ms | Avg: 201 | Occurrences: 3
Perfect for protecting:
- ๐๏ธ SQL Server - Prevents slow query pile-ups that can crash databases
- ๐ External APIs - Avoids rate limiting and reduces costs
- ๐ File System - Prevents I/O bottlenecks from concurrent reads
- ๐งฎ Heavy Calculations - CPU-intensive operations run once, benefit everyone
๐ Enterprise Features, Simple API
โ
Zero duplicate execution - Guaranteed single execution per cache period
โ
Ultra-fast performance - 0.0001ms per operation with intelligent memory management
โ
Thread-safe by design - Handles any concurrency scenario automatically
โ
Memory leak prevention - Advanced cleanup prevents memory bloat
โ
Production tested - Comprehensive testing ensure reliability
โ
Works with everything - Sync, async, any data type, any .NET app
โ
Automatic logging - Built-in statistics monitoring with one line setup (v2.0.1+)
โ
Global statistics - As of v2.0.2, Statistics available and BlitzCacheLoggingService to log them automatically
โ
Top Slowest Queries - As of v2.0.2, BlitzCache tracks and exposes the top slowest queries, making it easy to identify performance bottlenecks in your application
โ
Approximate Memory Usage - As of v2.1.0, statistics include approximate memory usage for better monitoring
โ
Top Heaviest Entries - As of v2.1.0, easily identify the largest cached items with the top heaviest entries feature
โ
Capacity-Based Size Limit (Optional) - As of v2.1.0, set maxCacheSizeBytes to enable automatic eviction when the cache exceeds a size budget
โ
Zero-Overhead When Disabled - Set MaxTopSlowest or MaxTopHeaviest to 0 (or pass maxTopSlowest: 0, maxTopHeaviest: 0 to constructors) to completely skip tracking logic for those features. If both are disabled and no MaxCacheSizeBytes is configured, BlitzCache now skips all per-entry sizing for maximum throughput.
๐ Table of Contents
- Why BlitzCache?
- Key Features
- Performance Benefits
- Installation
- Quick Start
- Learning BlitzCache - Examples & Tutorials
- Real-World Examples
- Advanced Usage
- API Reference
- Comparison
- Contributing
- Migration Guide
๐ Real Impact
| Scenario | Without BlitzCache | With BlitzCache | Impact |
|---|---|---|---|
| 1000 concurrent API calls | 1000 executions | 1 execution | 99.9% faster |
| Database query bursts | Multiple DB hits | Single DB hit | Massive savings |
| SQL server under load | Server crashes ๐ฅ | Server protected ๐ก๏ธ | System stability |
| Operation speed | Varies | 0.0001ms | Lightning fast |
Detailed benchmarks and analysis โ
๐ฆ Get Started in 30 Seconds
dotnet add package BlitzCache
๐ Requirements: Your project needs .NET Core 3.1+ or .NET 5-8+. No special SDK required for usage.
๐ฅ For Contributors: Development requires .NET 8.0 SDK (see CONTRIBUTING.md)
Basic Usage
var cache = new BlitzCache(maxCacheSizeBytes: 200_000_000); // optional size limit
// Any expensive operation becomes cached instantly
var data = await cache.BlitzGet("key", ExpensiveOperation, timeoutMs);
ASP.NET Core Integration
// Setup (one line in Program.cs)
services.AddBlitzCache(maxCacheSizeBytes: 200_000_000);
// Optional: Add automatic logging of cache statistics (v2.0.2+)
services.AddBlitzCacheLogging(); // Logs cache performance hourly
// Usage anywhere
public WeatherService(IBlitzCache cache) => this.cache = cache;
public Task<Weather> GetWeather(string city) => cache.BlitzGet($"weather_{city}", () => CallWeatherApi(city));
Compatibility: .NET Standard 2.1+ | .NET Core 3.1+ | .NET 5-8+
๐ง Advanced Usage
Capacity-Based Size Limit
BlitzCache can enforce an overall cache size budget using .NET MemoryCacheโs SizeLimit. Enable it by providing maxCacheSizeBytes:
// Instance-based
var cache = new BlitzCacheInstance(maxCacheSizeBytes: 100 * 1024 * 1024); // 100 MB
// Global
var global = new BlitzCache(maxCacheSizeBytes: 100 * 1024 * 1024);
// DI
services.AddBlitzCache(maxCacheSizeBytes: 100 * 1024 * 1024);
How it works:
- Each entry is assigned an approximate size using an internal lightweight sizing strategy (selectable via
SizeComputationMode). - MemoryCache evicts entries (LRU-like with priority) when inserting would exceed SizeLimit.
- Enforced regardless of whether statistics are enabled.
Notes:
- Sizing is best-effort and optimized for common types (string, byte[], primitive arrays). Other types use a conservative default.
- You can still use expiration times; capacity-based eviction works in addition to them.
- If you do NOT set
maxCacheSizeBytesand also disableMaxTopHeaviest(set to 0), BlitzCache skips object sizing entirely for faster performance.
Automatic Cache Key Generation
BlitzCache can automatically generate cache keys based on the calling method and file:
// Cache key will be: "GetUserData" + "UserService.cs"
public async Task<UserData> GetUserData()
{
return await _cache.BlitzGet(async () => await FetchUserDataAsync());
}
Dynamic Cache Duration Based on Results
public async Task<ApiResponse> CallExternalApiAsync(string endpoint)
{
return await _cache.BlitzGet($"api_{endpoint}", async (nuances) => {
try
{
var result = await httpClient.GetAsync(endpoint);
if (result.IsSuccessStatusCode)
{
nuances.CacheRetention = 300000; // Success: cache for 5 minutes
return await result.Content.ReadFromJsonAsync<ApiResponse>();
}
else
{
nuances.CacheRetention = 30000; // Error: cache for 30 seconds
return new ApiResponse { Error = "API call failed" };
}
}
catch (Exception)
{
nuances.CacheRetention = 5000; // Exception: cache for 5 seconds
return new ApiResponse { Error = "Network error" };
}
});
}
Manual Cache Management
// Update cache manually
cache.BlitzUpdate("user_123", () => GetFreshUserData(), 120000);
// Remove from cache
cache.Remove("user_123");
// Async update
await cache.BlitzUpdate("weather_data", async () => await GetWeatherAsync(), 300000);
Cache Statistics and Monitoring
BlitzCache provides built-in performance statistics to help you monitor cache effectiveness and optimize your application.
As of v2.1.0+, statistics include approximate memory usage and top heaviest entries when enabled (defaults on):
var stats = cache.Statistics;
Console.WriteLine($"Approx Memory: {FormatBytes(stats.ApproximateMemoryBytes)}");
foreach (var heavy in stats.TopHeaviestEntries)
Console.WriteLine($" {heavy}"); // HeavyEntry prints with human-friendly units
static string FormatBytes(long bytes)
{
if (bytes < 1024) return $"{bytes} bytes";
var kb = bytes / 1024.0;
if (kb < 1024) return $"{kb:0.##} KB";
var mb = kb / 1024.0;
return $"{mb:0.##} MB";
}
Notes:
- Memory accounting is best-effort and uses a lightweight sizer for common types (strings, byte[] and primitive arrays). Custom sizing can be added in future versions.
- Heaviest list size is configurable via AddBlitzCache(..., maxTopHeaviest: 5).
- Set
MaxTopHeaviest = 0to disable tracking and memory sizing overhead (unless a capacity limit is configured). - Set
MaxTopSlowest = 0to disable slow query timing aggregation. - When both are disabled AND no capacity limit is set, BlitzCache avoids computing object sizes for minimal overhead.
Available Statistics:
HitCount: Total cache hits since instance creationMissCount: Total cache misses since instance creationHitRatio: Hit percentage (0.0 to 1.0)TotalOperations: Sum of hits and missesCurrentEntryCount: Current number of cached entriesEvictionCount: Number of manual removals and expirationsActiveSemaphoreCount: Current concurrency control structuresTopSlowestQueries: List of the slowest cache operations (v2.0.2+)TopHeaviestEntries: List of the heaviest cache entries (v2.1.0+)ApproximateMemoryBytes: Approximate memory usage in bytes (v2.1.0+)Reset(): Method to reset all counters to zero
Practical guidance:
- Use BlitzGet/BlitzUpdate APIs; they set AbsoluteExpiration and wire eviction callbacks for you.
- For manual removals via Remove, statistics are updated through the eviction callback automaticallyโno extra work needed.
- In tests, very small delays are used to allow callbacks to run; in production these callbacks execute automatically on the thread pool.
๐ Configuration via appsettings.json
From v2.1.x you can configure BlitzCache using the standard .NET Options pattern. This allows central configuration, environment overrides, and future expansion without API changes.
- Add a BlitzCache section to your appsettings.json:
{
"BlitzCache": {
"DefaultMilliseconds": 10000,
"MaxTopSlowest": 10,
"MaxTopHeaviest": 5,
"MaxCacheSizeBytes": 104857600,
"EvictionStrategy": "SmallestFirst",
"SizeComputationMode": "Balanced" // Fast | Balanced | Accurate | Adaptive
}
}
- Wire it up in Program.cs / Startup.cs:
builder.Services.Configure<BlitzCacheOptions>(builder.Configuration.GetSection("BlitzCache"));
builder.Services.AddBlitzCache(); // registers using configured options
builder.Services.AddBlitzCacheLogging(o => // optional logging via options delegate
{
o.LogInterval = TimeSpan.FromMinutes(30);
o.GlobalCacheIdentifier = "OrdersService-API";
});
- Inject and use:
public class OrdersService
{
private readonly IBlitzCache _cache;
public OrdersService(IBlitzCache cache) => _cache = cache;
public Task<Order> GetOrder(int id) => _cache.BlitzGet($"order_{id}", () => LoadOrder(id));
}
Override per environment (e.g. appsettings.Production.json) without code changes.
Optional: configure inline instead of JSON:
services.AddBlitzCache(o =>
{
o.DefaultMilliseconds = 5000;
o.MaxCacheSizeBytes = 50 * 1024 * 1024;
o.MaxTopSlowest = 8;
o.SizeComputationMode = SizeComputationMode.Fast;
});
Notes:
- If both Configure<BlitzCacheOptions> and AddBlitzCache(Action<BlitzCacheOptions>) are used, the configurations are additive; later settings overwrite earlier ones.
- Dynamic reload (IOptionsMonitor) is supported at the configuration layer, but the current global cache instance does not hotโswap its internal sizing/eviction strategy. For runtime reconfiguration you would introduce a proxy cache in a future version.
- All newly added option fields will automatically flow without changing registration code.
- Performance tip: set
MaxTopSlowest = 0orMaxTopHeaviest = 0to completely skip their tracking logic. If both are0andMaxCacheSizeBytesis null, BlitzCache skips all size computation for the leanest possible operation.
๐ API Reference
Core Methods
BlitzGet<T>(string cacheKey, Func<T> function, long? milliseconds = null)
Executes function and caches result for synchronous operations.
BlitzGet<T>(string cacheKey, Func<Task<T>> function, long? milliseconds = null)
Executes async function and caches result for asynchronous operations.
BlitzGet<T>(Func<T> function, long? milliseconds = null)
Auto-generates cache key based on caller method and file path.
BlitzGet<T>(string cacheKey, Func<Nuances, T> function, long? milliseconds = null)
Allows dynamic cache duration configuration via the Nuances parameter.
Management Methods
BlitzUpdate<T>(string cacheKey, Func<T> function, long milliseconds)
Manually updates cache entry with new value.
Remove(string cacheKey)
Removes specific entry from cache.
Dispose()
Cleans up resources (implements IDisposable).
Parameters
cacheKey: Unique identifier for the cached valuefunction: The function to execute and cachemilliseconds: Cache duration in milliseconds (optional, uses default if not specified)nuances: Object for dynamic cache configuration
๐ Comparison with Alternatives
| Feature | BlitzCache | MemoryCache | Redis | Custom Solutions |
|---|---|---|---|---|
| Zero Duplicate Execution | โ | โ | โ | โ ๏ธ Complex |
| Thread Safety | โ | โ | โ | โ ๏ธ Manual |
| Granular Locking | โ | โ | โ | โ ๏ธ Manual |
| Async Support | โ | โ | โ | โ ๏ธ Manual |
| Simple API | โ | โ | โ | โ ๏ธ Varies |
| No External Dependencies | โ | โ | โ | โ |
| Performance Overhead | Very Low | Low | Medium | Varies |
| Setup Complexity | None | Low | High | High |
Why Choose BlitzCache?
- Prevents Thundering Herd: Unlike basic caches, BlitzCache prevents multiple concurrent executions
- Zero Configuration: Works out of the box with sensible defaults
- Performance Focused: Designed specifically for high-concurrency scenarios
- Developer Friendly: Simple, intuitive API that "just works"
- ๏ฟฝ Enterprise Grade: Advanced memory leak prevention with comprehensive testing
- โก Ultra-Fast: 0.0001ms per operation with optimal memory management
- ๐ก๏ธ Robust Architecture: Advanced usage-based cleanup system
- ๐ง Production Ready: Intelligent smart lock management
๐ ๏ธ Troubleshooting
Common Issues
Q: Cache doesn't seem to work / function executes multiple times
- Ensure you're using the same cache key for identical operations
- Check that cache duration is appropriate for your use case
- Verify you're not creating multiple BlitzCache instances unnecessarily
Q: Memory usage growing over time
- BlitzCache automatically expires entries based on your specified durations
- Consider shorter cache durations for frequently changing data
- Use
Remove()method for manual cleanup when needed
Q: Async methods hanging or deadlocking
- Ensure you're using
awaitproperly with async BlitzGet methods - Avoid mixing sync and async patterns
- Check for circular dependencies in your cached functions
Q: Performance not as expected
- Verify your expensive operations are actually expensive enough to benefit from caching
- Check cache hit ratios - very short cache durations may not provide benefits
- Consider whether granular locking is needed for your use case
Getting Help
- ๐ Detailed Blog Post
- ๐ Report Issues
- ๐ฌ Discussions
- ๐ Performance Details & Test Results
๐ฏ Production-Ready Caching Solution
BlitzCache delivers enterprise-grade performance and reliability:
- โ Zero memory leaks - Advanced usage-based cleanup
- โ 0.0001ms per operation - Ultra-high performance
- โ Every feature is tested - Comprehensive reliability
- โ Advanced architecture - Intelligent memory management
- โ Thread-safe - Concurrent operation guarantees
Perfect for demanding production workloads! ๐
๐ ๏ธ Migration Guide: 1.x โ 2.x
If you are upgrading from BlitzCache 1.x to 2.x, please note the following breaking changes:
- Async BlitzUpdate Signature: The
BlitzUpdate<T>method for async operations now returns aTaskinstead ofvoid. Update your code toawaitthese calls:- Before (v1.x):
void BlitzUpdate<T>(string cacheKey, Func<Task<T>> function, long milliseconds); - After (v2.x):
Task BlitzUpdate<T>(string cacheKey, Func<Task<T>> function, long milliseconds);
- Before (v1.x):
- API Cleanup: Obsolete and redundant APIs have been removed. Review the new interface for available methods.
- Unified Concurrency Control: All concurrency is now managed with SemaphoreSlim. Remove any code referencing SmartLockDictionary or SmartLock classes.
- Instance-Based Caching: BlitzCache is now instance-based instead of static. Update your code to create and manage BlitzCache instances as needed.
Migration Steps:
- Update your NuGet reference to BlitzCache 2.x.
- Refactor all async
BlitzUpdateusages to return and await aTask. - Update all projects using BlitzCache to be compatible with the new interface.
- Review and update any code referencing removed or changed APIs.
- Run your test suite to ensure all caching and concurrency scenarios work as expected.
For full details, see the Changelog.
๐ค Contributing
We welcome contributions! Here's how you can help:
Ways to Contribute
- ๐ Report bugs or issues
- ๐ก Suggest new features or improvements
- ๐ Improve documentation
- ๐ง Submit pull requests
- โญ Star the repository
- ๐ข Share with other developers
Development Setup
git clone https://github.com/chanido/blitzcache.git
cd blitzcache
dotnet restore
dotnet build
dotnet test
Pull Request Guidelines
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Write tests for your changes
- Ensure all tests pass
- Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Code of Conduct
Please be respectful and constructive in all interactions. We're here to build something great together! ๐
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
- Built with โค๏ธ by Chan
- Thanks to all contributors
- Inspired by the need for simple, high-performance caching solutions
โญ If BlitzCache helped you, please consider giving it a star! โญ
Made with โก by the BlitzCache team
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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 was computed. 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 was computed. 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. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Microsoft.Extensions.Caching.Memory (>= 8.0.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Hosting.Abstractions (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
BlitzCache v2.1.1 - Zero-Overhead Conditional Features
NEW IN v2.1.1:
โข Conditional statistics: When maxTopSlowest or maxTopHeaviest < 1 the related tracking is fully disabled (no allocations / updates).
โข Automatic skip of per-entry size calculation & capacity enforcement when no maxCacheSizeBytes configured.
โข Deterministic capacity enforcement using simulated remaining bytes to avoid transient over-eviction.
โข Logger now omits disabled Top sections entirely for cleaner output.
โข Additional tests covering disabled tracking & eviction precision.
Notes:
โข Performance-focused release with no breaking changes.
โข Disabling features now truly removes their runtime cost.