AsyncCache 3.0.3

dotnet add package AsyncCache --version 3.0.3
NuGet\Install-Package AsyncCache -Version 3.0.3
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="AsyncCache" Version="3.0.3" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add AsyncCache --version 3.0.3
#r "nuget: AsyncCache, 3.0.3"
#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.
// Install AsyncCache as a Cake Addin
#addin nuget:?package=AsyncCache&version=3.0.3

// Install AsyncCache as a Cake Tool
#tool nuget:?package=AsyncCache&version=3.0.3

AsyncCache

NuGet version Build Build

Async cache uses an "async lock" (a semaphore) to prevent competing/simultaneous calls to the data source.

Usage

AsyncCache is not a singleton. If you want your cached key/values to be scoped as a singleton (also just generally speaking), I recommend using a dependency injector to instantiate AsyncCache.

The reason the cached key/values are scoped to the instance of AsyncCache is this way you can control both the TimeSpan and the scope of your key/values.

Usage Example Note: Don't use .Result from a task. Async functions should be called by async functions. This is just an example app to illustrate usage of AsyncCache. This example app is synchronous..so maybe a bad example but it should still illistrate the usage.

using Cache;
using System;
using System.Threading.Tasks;
        
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var random = new Random();
            var cache = new AsyncCache();
        
            Console.WriteLine("Not Cached:");
            for (var i = 0; i < 5; i++)
                Console.WriteLine(random.Next(0, 5));
        
            Console.WriteLine("\nCached:");
            for (var i = 0; i < 5; i++)
                Console.WriteLine(cache.Get(
                    key: "random integer",
                    dataSource: () => Task.FromResult(random.Next(0, 5))).Result);
        
            Console.ReadKey();
        }
    }
}

Example App Output:

    Not Cached:
    4
    2
    2
    4
    0
    
    Cached:
    2
    2
    2
    2
    2

Here is example usage from unit tests (below). Did I mention how simple it is?

[TestInitialize]
public void Setup()
{
    _cache = new AsyncCache();
}

[TestMethod]
public async Task ShouldReturnResultFromDataSourceTask()
{
    //Arrange
    //Act
    int result = await _cache.Get("some key", () => Task.FromResult(2));

    //Assert
    result.Should().Be(2);
}
        
[TestMethod]
public async Task ShouldLockToPreventRaceCondition()
{
    var tcs1 = new TaskCompletionSource<int>();
    var tcs2 = new TaskCompletionSource<int>();

    int? result1 = null;
    int? result2 = null;
    var get1 = _cache.Get(key: "key1", dataSource: () => tcs1.Task).ContinueWith(t => result1 = t.Result);
    var get2 = _cache.Get(key: "key1", dataSource: () => tcs2.Task).ContinueWith(t => result2 = t.Result);

    tcs1.SetResult(1);
    tcs2.SetResult(2);

    await Task.WhenAll(get1, get2);

    result1.Should().Be(1, "because this is the initial value inserted into the cache.");
    result2.Should().Be(1, "because the previous/parallel request should've already inserted 1");
}
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • No dependencies.

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
3.0.3 923 1/31/2024
3.0.2 454 11/28/2023
2.0.1 1,568 9/30/2021
1.0.67 384 9/30/2021
1.0.66 326 9/30/2021
1.0.65 470 9/25/2021
1.0.64 361 9/24/2021
1.0.39 5,677 7/1/2018
1.0.38 1,051 3/14/2018
1.0.37 1,287 10/11/2017
1.0.34 1,061 3/16/2017
1.0.33 1,378 11/16/2016
1.0.32 1,259 11/16/2016
1.0.31 1,206 11/16/2016
1.0.30 1,642 6/16/2016
1.0.28 1,175 3/19/2016
1.0.27 1,253 3/5/2016
1.0.26 1,269 3/5/2016
1.0.25 1,264 2/20/2016
1.0.24 1,313 2/20/2016
1.0.23 1,288 2/20/2016
1.0.22 1,286 2/20/2016
1.0.21 1,251 2/16/2016
1.0.20 1,295 2/16/2016
1.0.19 1,298 2/16/2016
1.0.18 1,288 2/14/2016
1.0.1 1,298 2/14/2016
1.0.0 9,918 2/13/2016