Add Data to Cache
After successfully connecting to the cache and gaining a valid cache handle, you can add data to the cache. This data is usually frequently accessed by the application and not frequently modified. For example, you wish to add the products information of a store into the cache as it is frequently accessed for checking availability. This saves database trips as data can be accessed from the cache instead of accessing database for each request.
NCache provides the Add() method and its overloads to facilitate adding objects to cache for the first time.
Add Operation Behavior
Add is a one-time operation. The same key cannot be added again if it already exists in the cache. For that you need to Insert it into the cache, which overwrites the value for the existing key.
Add returns CacheItemVersion, a value which internally marks the version of the cache item being added. For each subsequent update of the same item, this version will be updated. This is used in data concurrency scenarios to internally keep track of the updated objects, and is discussed in detail in the chapter Optimistic Locking.
In advanced cases, if data source is configured, data will be added to cache as well as the data source during the Add operation. For more details, refer to the chapter Data Source Providers.
Pre-requisites For Adding Data
- Include the following namespace in your application:
Alachisoft.NCache.Web.Caching
. - The application must be connected to cache before performing the operation.
- Cache must be running.
- Make sure that the data being added is serializable.
- To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
Single Item
You can add a single object to the cache using various overloads of the Add() method.
Warning
If the key already exists, an "OperationFailedException" will be thrown.
The following example adds an object of Product class and its associated key into the cache. This returns CacheItemVersion. If the key already exists, a "Specified key already exists" exception is thrown. The code sample then checks whether the key has been successfully added to cache or not.
Tip
One quick way to verify whether item has been added is to use either properties of the Cache class:
Recommendation: To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
try
{
// Pre-condition: Cache is already connected
// Get product from database against given product ID
Product product = FetchProductFromDB(1001);
// Generate a unique cache key for this product
string key = $"Product:{product.ProductID}";
// Add Product object to cache
CacheItemVersion version = cache.Add(key, product);
// Item added in cache successfully
}
catch (OperationFailedException ex)
{
// NCache specific exception
if (ex.Message.Contains("The specified key already exists."))
{
// The specified key already exists in cache
}
else
{
// Exception can occur due to:
// Connection Failures
// Operation performed during state transfer
// Operation Timeout
}
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
CacheItem
CacheItem is a custom class provided by NCache which can be used to add data to the cache and also lets you set additional metadata associated with an object of this class. This metadata defines the properties of the item like expiration, dependencies and more. You can refer to all properties of CacheItem here.
Warning
If the key already exists, an "OperationFailedException" will be thrown.
Tip
One quick way to verify whether item has been added, is to use either properties of the Cache class:
The following example adds a basic CacheItem
containing the Product object into the cache; additional properties will be set against the CacheItem
in successive chapters. If the key already exists, a "Specified key already exists" exception is thrown. The code sample then checks whether the key has been successfully added to cache or not.
Recommendation: To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
try
{
// Pre-condition: Cache is already connected
// Get product from database against given product ID
Product product = FetchProductFromDB(1001);
// Generate a unique cache key for this product
string key = $"Product:{product.ProductID}";
// Create a new CacheItem for this product
// You can OPTIONALLY specify multiple properties e.g. Priority, Expiration
// These properties are explained in successive chapters
CacheItem cacheItem = new CacheItem(product);
// cacheItem.AbsoluteExpiration = DateTime.Now.AddMinutes(5);
// Add CacheItem to cache
CacheItemVersion version = cache.Add(key, cacheItem);
}
catch (OperationFailedException ex)
{
// NCache specific exception
if (ex.Message.Contains("The specified key already exists."))
{
// The specified key already exists in cache
}
else
{
// Exception can occur due to:
// Connection Failures
// Operation performed during state transfer
// Operation Timeout
}
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
Bulk Items
NCache also allows synchronous bulk addition of items in a single call to reduce network cost. AddBulk() adds an array of CacheItem to the cache with the corresponding cache keys. The method returns a dictionary of all the keys that fail to add, along with the failure reason.
Although a bulk operation is executed as a single operation, the failure of operations is treated individually. For example, if a bulk of 100 items is added to the cache and 20 of those items already exist in the cache, the remaining 80 items will be added to the cache. The keys of existing 20 items will be returned to the application as a dictionary of failed operations along with the failure reason.
Note
Any keys that fail to add and their failure reason will be returned as an IDictionary
.
The following code adds a bulk of product items to the cache. If there are any keys that failed to add, the keys can be handled according to your business needs.
Recommendation: To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
try
{
// Pre-condition: Cache is already connected
// Fetch all products from database
Product[] products = FetchProductsFromDB();
string[] keys = new string[products.Length];
CacheItem[] cacheItems = new CacheItem[products.Length];
for (int i = 0; i < products.Length; i++)
{
// Generate a unique cache key for this product
keys[i] = $"Product:{products[i].ProductID}";
// Create a new cache item for this product
// You can OPTIONALLY specify multiple properties e.g. Priority, Expiration
// These properties are explained in successive chapters
cacheItems[i] = new CacheItem(products[i]);
// cacheItems[i].AbsoluteExpiration = DateTime.Now.AddMinutes(5);
}
// Add all products in cache using bulk add
// Failed keys and failure reason returned in IDictionary
IDictionary keysFailedToAdd = cache.AddBulk(keys, cacheItems);
// Check if any keys failed to add
if (keysFailedToAdd.Count > 0)
{
foreach (DictionaryEntry entry in keysFailedToAdd)
{
// Check failure reason
if (entry.Value is OperationFailedException)
{
var ex = entry.Value as OperationFailedException;
if (ex.Message.Contains("The specified key already exists."))
{
// If same key already exists in cache
}
}
else
{
// Any other exception
}
}
}
}
catch (OperationFailedException ex)
{
// Exception can occur due to:
// Connection Failure
// Operation performed during state transfer
// Operation Timeout
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
Asynchronous API
Asynchronous operations are performed in the background, so the client does not have to wait for the response from the server to execute further operations. The control is returned to the application immediately after performing the operation. This increases overall responsiveness of the application.
Since asynchronous operations do not notify upon the failure or success of the operations themselves, NCache provides a callback mechanism which can be registered while making the operation call. These callbacks are triggered upon success or failure of the operation.
CacheItem can be added asynchronously into the cache, with or without callbacks using the AddAsync() method.
In case the key already exists in cache:
- For callback registered, the item is not added and an exception is sent through the callback as an operation failure.
- For callback not registered, the item is not added and no exception is thrown.
The following example adds a CacheItem
to the cache with its associated unique key. The AsyncItemAddedCallback
function is used to register a callback to perform appropriate functions upon completion of the add operation. If the callback is not specified, the data will be added without callback, using the same API.
Important
Note that this API also allows specifying additional parameters for Data Source Providers and Groups, so the values for those parameters have been passed as None
and null
respectively, as they are not discussed here.
// NOTE: If you are using callbacks, include:
using Alachisoft.NCache.Caching;
try
{
// Pre-condition: Cache is already connected
// Get product from database against given product ID
Product product = FetchProductFromDB(1001);
// Generate a unique cache key for this product
string key = $"Product:{product.ProductID}";
// Create a new CacheItem for this product
// You can OPTIONALLY specify multiple properties e.g. Priority, Expiration
// These properties are explained in successive chapters
CacheItem cacheItem = new CacheItem(product);
// cacheItem.AbsoluteExpiration = DateTime.Now.AddMinutes(5);
// Specify ItemAddedCallback
// If NOT specified, data will be asynchronously added WITHOUT callback
cacheItem.AsyncItemAddCallback += new AsyncItemAddedCallback(OnItemAdded);
// Add data asynchronously
cache.AddAsync(key, cacheItem, DSWriteOption.None, null);
}
catch (OperationFailedException ex)
{
// NCache specific exception
// Exception can occur due to Connection Failure
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
...
// Create a callback method
public static void OnItemAdded(string key, object status)
{
if (status is Exception ex)
{
if (ex.Message.Contains("The specified key already exists."))
{
// The same key already exists in cache
}
else
{
// Operation performed during state transfer
}
}
else
{
AsyncOpResult result = (AsyncOpResult)status;
if (result == AsyncOpResult.Success)
{
// Object added to cache successfully
}
}
}
Using Cache.Add for Distributed Locking
Due to its versatile nature, another wide use of Add operation is in locking the cache if it is being used by multiple applications.
For example, an environment is set such that as soon as any application connects to the cache, it adds a specific key which is known to all applications. And once the application is done using the cache, it removes the key from the cache. If the key is added successfully, it can proceed to use the cache according to its logic. However, if the key already exists, it means the cache is already being used by an application, and is "locked".
This is described in steps in the following diagram:
App A and App B add the "WorkStarted" key as soon as the cache is started.
The key passed by App A is added to the cache before the one passed by App B.
App B gets a "Specified key already exists" exception. In this scenario, App B will wait for App A to finish its work, i.e., until it can successfully add the "WorkStarted" key.
App A removes the key from the cache once done with its work.
App B adds the key to cache again.
The key is added by App B successfully, locking the cache for other applications.
See Also
Update Data to Cache
Retrieve Data from Cache
Remove Data from Cache
Connecting to Cache
Create Cache