Home

Awesome

Build Status codecov NuGet version (FastCache.Core)

πŸ”₯Easily to use cacheπŸ”₯

🀟 Install

Choose caching provider that you need and install it via Nuget.

Install-Package FastCache.InMemory
Install-Package FastCache.Redis
Install-Package FastCache.MultiSource

πŸš€ Quick start

// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseServiceProviderFactory(new DynamicProxyServiceProviderFactory());
builder.Services.AddInMemoryCache(); // InMemory

// builder.Services.AddMultiBucketsInMemoryCache(); // Big cache
// builder.Services.AddRedisCache("server=localhost:6379;timeout=5000;MaxMessageSize=1024000;Expire=3600", canGetRedisClient: true) // "Expire=3600" is redis global timeout
// canGetRedisClient = true => get redisClient instance
// var redisClient = serviceProvider.GetService<ICacheClient>();

// UserService.cs
[Cacheable("user-single", "{id}", 60 * 30)] // Cache expires after two seconds
public virtual User Single(string id)
{
    return _dbContext.Set<User>().Single(x => x.Id == id);
}

**********************************
***** Method must be virtual *****
**********************************

πŸ“š Support Autofac

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(build =>
{
    build.RegisterDynamicProxy();
});

β˜€οΈ Use in Controller

// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseServiceProviderFactory(new DynamicProxyServiceProviderFactory());
builder.Services.AddInMemoryCache(); // InMemory

builder.Services.AddMvc().AddControllersAsServices(); // the key point

// UserController.cs
[ApiController]
[Route("/user")]
public class UserController : ControllerBase
{
    [Route("/"), HttpGet]
    [Cacheable("user-single", "{id}", 60 * 10)]
    public virtual User Get(string id)
    {
        return _userService.Single(id);
    }
}
**********************************
***** Method must be "virtual" *****
**********************************

⏱ About Cache expiration ( For InMemory )

πŸͺ£ About InMemory BigCache ( Multi Buckets )

πŸ“Œ Redis cluster

builder.Services.AddRedisCache("server=127.0.0.1:6000,127.0.0.1:7000,127.0.0.1:6379;db=3;timeout=7000")

This Redis component supports Redis Cluster, configure any node address, 
it will be able to automatically discover other addresses and slot distribution,
and use the correct node when performing read and write operations.

This Redis component does not directly support the Redis sentinel, but supports it in the form of active-standby failover.

Cache automatic eviction

// UserService.cs
public class UserService
{
    [Cacheable("user-single", "{id}", 2)] // Cache expires after two seconds
    public virtual User Single(string id)
    {
        return _dbContext.Set<User>().Single(x => x.Id == id);
    }
}

Active cache eviction

// UserService.cs
public class UserService
{
    [Cacheable("user-single", "{id}", 2)] // Cache expires after two seconds
    public virtual User Single(string id)
    {
        return _dbContext.Set<User>().Single(x => x.Id == id);
    }
    
    [Evictable(new[] { "user-single", "other cache name" }, "{id}")]
    // [Evictable(new[] { "user" }, "{id}*")] // when {id} is "123", it will match keys starting with user:123 and perform a fuzzy deletion.
    public virtual void Delete(string id)
    {
        // delete logic...
    }
}

πŸ‘» Match both uses

// UserService.cs
public class UserService
{
    [Cacheable("user-single", "{id}")] // cache never expires
    public virtual User Single(string id)
    {
        // Get User logic...
    }
    
    [Cacheable("user-single", "{user:id}")]
    [Evictable(new[] { "user-single", "other cache name" }, "{user:id}")] 
    public virtual User Update(User user)
    {
        // Update logic...
    }
}

**********************************************

The Update method will be executed first. 
After the method is successfully executed, the setup cache will be invalidated,
and finally the Cacheable operation will be executed.

STEP:
 1. When "user:id" = "123"
 2. Then Evict cache: "user-single:123"
 3. Then After updated will caching:  "user-single:123" -> { latest user data }


πŸš€ This means that the cache will always be kept up to date,
thus triggering queries to the database will be significantly reduced πŸš€ 

**********************************************

🍺 Multi Source ( Currently supports Redis and inMemory )

// Program.cs
builder.Services.AddMultiSourceCache(
    "server=localhost:6379;timeout=5000;MaxMessageSize=1024000;Expire=3600",  // redis connectionString
    true                                                                      // can get redis client
);


// UserController.cs
// Target.Redis Target.InMemory
[HttpGet]
[MultiSourceCacheable("MultiSource-single", "{id}", Target.Redis, 60)] // Target.Redis
public virtual async Task<User> Get1(string id)
{
    return await _userService.Single(id).Result;
}

[HttpGet]
[MultiSourceCacheable("MultiSource-single", "{id}", Target.InMemory, 60)] // Target.InMemory
public virtual async Task<User> Get2(string id)
{
    return await _userService.Single(id).Result;
}


**********************************************
According to business needs, flexibly store the cache in redis or memory
**********************************************

πŸŽƒ Parameter Description

// MemoryCache
public static void AddInMemoryCache(
    this IServiceCollection services, 
    int maxCapacity = 1000000,
    MaxMemoryPolicy maxMemoryPolicy = MaxMemoryPolicy.LRU, int cleanUpPercentage = 10
)
{  // ... }

// MulitBucketsMemoryCache
public static void AddMultiBucketsInMemoryCache(
    this IServiceCollection services,
    uint buckets = 5,
    uint maxCapacity = 500000,
    MaxMemoryPolicy maxMemoryPolicy = MaxMemoryPolicy.LRU,
    int cleanUpPercentage = 10)
{  //...  }
ParameterTypeDefaultRequireExplain
bucketsuint5falseThe number of containers to store the cache, up to 128
bucketMaxCapacityuint1000000false(MemoryCache) Initialize capacity <br/> <br/> (MulitBucketsMemroyCache) The capacity of each barrel, it is recommended that 500,000 ~ 1,000,000
maxMemoryPolicyMaxMemoryPolicyMaxMemoryPolicy.LRUfalseLRU = Least Recently Used , TTL = Time To Live, Or RANDOM
cleanUpPercentageint10falseAfter the capacity is removed, the percentage deleted

Variable explanation

// foo:bar:1 -> "item1"
{
   "foo": {
      "bar": [
         "item1",
         "qux"
     ]
   }
}

// foo:bar:0:url -> "test.weather.com"
{
   "foo": {
      "bar": [
         {
            "url": "test.weather.com",
            "key": "DEV1234567"
         }
     ]
   }
}