<ABP framework> cache and TTL framework Cache
Introduction
ABP provides a cache interface, which is used internally. Although the default Implementation of the interface is MemoryCache, you can use any other implementation of the cache provider. The Abp. RedisCache package uses Redis for caching (view the "Redis cache integration" below ").
ICacheManager
The main interface for caching is ICacheManager. We can inject it and use it to get a cache, such:
public class TestAppService : ApplicationService{ private readonly ICacheManager _cacheManager; public TestAppService(ICacheManager cacheManager) { _cacheManager = cacheManager; } public Item GetItem(int id) { //Try to get from cache return _cacheManager .GetCache("MyCache") .Get(id.ToString(), () => GetFromDatabase(id)) as Item; } public Item GetFromDatabase(int id) { //... retrieve item from database }}
In this example, ICacheManager is injected and a cache named MyCache is obtained.
Warning GetCache Method
If your class is not a Singleton, do not use GetCache in your constructor; otherwise, your cache may be destroyed.
ICache
The ICacheManager. GetCache method returns an ICache. A cache is a singleton (each cache name ). The first request is created and the same cache object is always returned. Therefore, we can share the same cache with the same name in different classes (clients.
In the sample code, we can see the simple use of the ICache. get method. It has two parameters:
Key: String, required, the key of a cache entry.
Factory: an action. It is called when the cache item of the specified key cannot be found. The Factory method should create and return the actual item. If the cache of the specified key already exists, it will not be called.
ICache interfaces include GetOrDefault, Set, Remove, and Clear methods. The async version is also available.
ITypedCache
The ICache interface uses a string as the key and the value is of the object type. ITypedCache encapsulates ICache and provides type security and generics. We can use the generic GetCache extension method to obtain an ITypedCache:
ITypedCache<int, Item> myCache = _cacheManager.GetCache<int, Item>("MyCache");
Similarly, we can use the AsTyped Extension Method to convert an existing ICache instance to ITypedCache.
Configuration
The default cache timeout value is 60 Minutes, which can be changed. If you do not use items in the cache for more than 60 minutes, the items are automatically removed from the cache. You can configure the specified cache or all the caches.
//Configuration for all cachesConfiguration.Caching.ConfigureAll(cache =>{ cache.DefaultSlidingExpireTime = TimeSpan.FromHours(2);});//Configuration for a specific cacheConfiguration.Caching.Configure("MyCache", cache =>{ cache.DefaultSlidingExpireTime = TimeSpan.FromHours(8);});
This code should be written in your module's PreInitialize method. With this code, MyCache will have eight hours of timeout, and other caches will have two hours.
Call your configuration behavior in the first creation cache (in the first request. The configuration is not limited to DefaultSlidingExpireTime. Because the cache object is an ICache, you can use its attributes and methods for free configuration and initialization.
Entity Cache
Although the ABP cache system is for common purposes, there is an EntityCache base class that can help you cache objects. If we obtain entities through their IDs, we can use this base class to cache them so that we no longer need to frequently query them from the database. Assume that we have a person entity as follows:
public class Person : Entity{ public string Name { get; set; } public int Age { get; set; }}
Let us assume that we already know the Id and frequently obtain the Name. First, we need to create a class to cache items:
[AutoMapFrom(typeof(Person))]public class PersonCacheItem{ public string Name { get; set; }}
We should not store objects directly in the cache. Because the cache may need to serialize the cached objects, entities may not be serialized (especially those with navigation attributes ). This is why we create a simple (such as DTO: Data Transmission object) class to store data. Added the AutoMapFrom feature, which can automatically convert a Person to a PersonCacheItem object. If AutoMapFrom is not used, we should manually convert/map the MapToCacheItem method of the EntityCache class to be overloaded.
Although not required, we may want to define an interface for our cache class:
public interface IPersonCache : IEntityCache<PersonCacheItem>{}
Finally, we can create cache classes for entities:
public class PersonCache : EntityCache<Person, PersonCacheItem>, IPersonCache, ITransientDependency{ public PersonCache(ICacheManager cacheManager, IRepository<Person> repository) : base(cacheManager, repository) { }}
This is all the code. Our Person cache is available. The cache class can be temporary (for example) or standalone. This does not mean that the cached data is temporary. It is always global and thread-safe in your application.
Now, if you need the Name of Person, we can get it from the cache using the person Id. The example of using the Person cache is as follows:
public class MyPersonService : ITransientDependency{ private readonly IPersonCache _personCache; public MyPersonService(IPersonCache personCache) { _personCache = personCache; } public string GetPersonNameById(int id) { return _personCache[id].Name; //alternative: _personCache.Get(id).Name; }}
We simply inject IPersonCache to get the cache items and the Name attribute.
How does EntityCache work?
- Obtain the object from the warehouse (from the database) in the first call, and then obtain the object from the cache in the next call.
- If an object is updated or deleted, it automatically invalidates the cache, so it will be retrieved from the database again in the next call.
- Use IObjectMapper to map to the cache items. The AutoMpper module implements IObjectMapper, so the AutoMapper module is required. You can reload the MapToCacheItem method to manually map objects to cache items.
- The full name of the cache class is used as the cache name. You can change it by passing a cache name to the base constructor.
- Is thread-safe.
If you need more complex caching technologies, you can expand EntityCache or create your own solutions.
Redis cache Integration
The default Cache Management uses the memory cache. Therefore, if you have multiple concurrent Web servers using the same application, it may become a problem. In this case, you need a distributed/centralized cache service, you can simply use Redis as your cache server.
First, you need to install the Nuget package of the ABC. RedisCache in your application (for example, you can install it in your Web project ). Add the DependsOn feature to the AbpRedisCacheModule and call the useRedis Extension Method in the pre-initialization method of your module. As follows:
//...other namespacesusing Abp.Runtime.Caching.Redis;namespace MyProject.AbpZeroTemplate.Web{ [DependsOn( //...other module dependencies typeof(AbpRedisCacheModule))] public class MyProjectWebModule : AbpModule { public override void PreInitialize() { //...other configurations Configuration.Caching.UseRedis(); } //...other code }}
The "localhost" is used as the default connection string in the Abp. RedisCache package. You can add a connection string in the configuration file to overwrite it. For example:
<add name="Abp.Redis.Cache" connectionString="localhost"/>
Similarly, you can add the Redis Database Id to the appSettings, for example:
<add key="Abp.Redis.Cache.DatabaseId" value="2"/>
Different database IDs help to create different key spaces (independent caches) on the same server ).
The UseRedis method also has an overload. You can use the given action to directly set the option value (in the configuration file ).
For more information about Redis and its configuration, see the Redis documentation.
Reminder: The apsaradb for Redis server should be installed and run in the ABP.