NCache 4.4 - Online Documentation

Configuring Write-Through Provider

 
To use Write-through caching you need to implement IWriteThruProvider interface provided by NCache. NCache framework will use this custom implementation to write data on backend data source.
 
Implementing IWriteThru Provider Interface
 
To implement IWriteThruProvider, add following references in provider assembly.
 
Alachisoft.NCache.Runtime.dll.
 
Create a class that implements Alachisoft.NCache.Runtime.DatasourceProviders.
IWriteThruProvider interface and deploy it using NCache Manger. NCache framework will internally use this class to perform write operation on configured data source.
 
IWriteThru Interface
 
Member
Description
Init
This method will be called by NCache framework on cache startup. User can use this method for performing tasks like allocating resources, acquiring connections of data source etc. This method takes as input the IDictionary instance of  arguments passed to the provider through NCache Manger (configuration settings). It allows you to pass list of parameters to provider. These parameters can be utilized in many ways. For example, connection string of a data source can be specified as a parameter. Thus, it provides a flexible way to change the data source settings while configuring it without code changes.
 
The other argument CacheId specifies the cache name for which read-through is configured.
WriteToDataSource
This method will be called by NCache framework to perform actual write operation on configured data source.
-For write-thru, an atomic operation with write-thru will corresponds to atomic WriteToDataSource method in provider while in case bulk operation NCache will call bulk WriteToDataSource method from provider.
-For write-behind, NCache will call atomic WriteToDataSource method if non-batch mode is enabled while bulk WriteToDataSource method will be called for batch mode.
This method should contain logic to perform operation on configured data source. The argument WriteOperation contain the  key, operation type (Add, Insert, Remove/Delete), retry count and provider cache item.
You will implement this method to perform write operations on data source according to operation type and return it to NCache as OperationResult. OperationResult holds information about:
·     WriteOperation: Operation performed on data source.
·     Update in cache flag : This flag specifies whether to update the returned write operation in cache or not. This is only applicable for Add and Insert operation types. In NCache an operation is first applied on cache store and then to data source (if write through caching is enabled). So if user wants to synchronize the cache store after updating  data source then this flag will be used.
·     Data source operation status : Write through caching basically synchronize your data source with cache store. Previously in case of operation failure on data source, item is also removed from cache, now NCache provides more flexible ways to allow user to decide whether to keep the item in cache based on these operation statuses.
·     Success: This means item was successfully added to the data source so keep it in the cache as well.
·     Failure: This means item could not be added to data source, so in case of Add/Insert operations, item will be removed from cache. Operation failure exception will be thrown to user in case of write-through and logged in case of write behind.
·     FailureDontRemove: This means item could not be added to the data source, but keep it in the cache. Operation failure exception will be thrown to user in case of write thru and logged in case of write behind.
·     FailureRetry: This means item could not be added to the data source, keep the item in cache and retry. In case of write thru retry will be performed as write behind operation.
While implementing this method, you should take care of code thread safety as multiple requests can access this method for write-through.
Dispose
This method will be called by NCache framework when cache stops. You can use this method for performing tasks like releasing resources, disposing connections etc. Here you can free the resources related to data source for effective resource utilization.
 
 
In NCache, Read-Through providers are configured on cache level i.e. for clustered caches all nodes will contain provider configurations and their deployed assemblies.
 
 
Sample Code for IWriteThruProvider
 
/// Contains methods used to save/update an object to the master data source.
public class SampleWriteThruProvider : IWriteThruProvider
{
/// Object used to communicate with the Data source.
private SqlConnection _connection;
 
//Perform tasks like allocating resources or acquiring connections
public void Init(IDictionary parameters, string cacheId)
{
object connStringObject = parameters["connstring"];
string connString = connStringObject == null ? "" : connStringObject.ToString();
if (connString != "")
            _connection = new SqlConnection(connString);
try
        {
            _connection.Open();
        }
catch (Exception ex)
        {
//handle exception
        }
    }
 
//Perform tasks associated with freeing, releasing, or resetting resources.
public void Dispose()
{
if (_connection != null)
            _connection.Close();
}
 
//Responsible for write operations on data source
public OperationResult WriteToDataSource(WriteOperation operation)
{
 
Product product = (Product)operation.ProviderCacheItem.Value;
SqlCommand command = new SqlCommand();
      command.Connection = _connection;
 
if (operation.OperationType == WriteOperationType.Add)
command.CommandText = "INSERT INTO Products(ID,Name)VALUES( '" + operation.Key + "','" + product.ProductName + "')";
 
 
if (operation.OperationType == WriteOperationType.Delete)
command.CommandText = "DELETE FROM Products WHERE ID ='" + operation.Key + "'";
 
if (operation.OperationType == WriteOperationType.Update)
            command.CommandText = "UPDATE Products SET Name = '" + product.ProductName + "' WHERE ID='" + operation.Key + "'";
 
int result = command.ExecuteNonQuery();
OperationResult operationResult = new OperationResult(operation, OperationResult.Status.Success);
 
if (result < 1)
      {
            operationResult.DSOperationStatus = OperationResult.Status.Failure;
      }
 
return operationResult;
 
  }
 
public OperationResult[] WriteToDataSource(WriteOperation[] operations)
{
OperationResult[] operationResult = new OperationResult[operations.Length];
SqlCommand command = new SqlCommand();
      command.Connection = _connection;
int counter = 0;
foreach (WriteOperation operation in operations)
      {
Product product = (Product)operation.ProviderCacheItem.Value;
if (operation.OperationType == WriteOperationType.Add)
                command.CommandText = "INSERT INTO Products(ID,Name)VALUES( '" + operation.Key + "','" + product.ProductName + "')";
if (operation.OperationType == WriteOperationType.Delete)
                command.CommandText = "DELETE FROM Products WHERE ID ='" + operation.Key + "'";
if (operation.OperationType == WriteOperationType.Update)
                command.CommandText = "UPDATE Products SET Name = '" + product.ProductName + "' WHERE ID='" + operation.Key + "'";
 
int result = command.ExecuteNonQuery();
      operationResult[counter] = new OperationResult(operation, OperationResult.Status.Success);
 
if (result < 1)
      {
            operationResult[counter].DSOperationStatus = OperationResult.Status.Failure;
      }
      counter++;
      }
return operationResult;
}
 
}
 
 
After implementing and deploying this provider, you can make direct calls to NCache for write operations on data source. NCache will use "WriteToDataSource" method in specified data access class to write operations on data source.
 
Using Write-Through with Basic Operations
 
 
This feature is not available in NCache Express and Professional edition.
 
 
This section will explain the use of write-through provider after configuring and deploying it. NCache supports multiple Write-Through providers with applications.
 
The following namespaces  should be added in application:
 
using Alachisoft.NCache.Web.Caching;
using Alachisoft.NCache.Runtime.DatasourceProviders;
using Alachisoft.NCache.Runtime;
 
NCache provides Alachisoft.NCache.Web.Caching.DSWriteOption enum to specify Write thru/Write behind options in APIs. Multiple  write-through providers can be configured through NCache. Default provider will be called if specific provider name is not mentioned through API. You can also use providers other than default by using provider specific overloads of APIs.
 
  • Adding with Write-Through
 
Member
Description
CacheItemVersion Add(string key, CacheItem item, DSWriteOption dsWriteOption, DataSourceItemsAddedCallback onDataSourceItemAdded)
Adds item in cache and uses default provider
CacheItemVersion Add(string key, CacheItem item, DSWriteOption dsWriteOption, string providerName, DataSourceItemsAddedCallback onDataSourceItemAdded)
Adds item in cache and uses specified provider
 
Product product = new Product();
product.ProductID = 1001;
product.ProductName = "Chai";
 
CacheItem cacheItem = new CacheItem(product);
string key = "Product:" + product.ProductID ;
 
try
{
CacheItemVersion itemVersion = cache.Add(key, cacheItem, DSWriteOption.WriteThru, null);
}
catch (OperationFailedException exp)
{
// handle exception
}
 
  • Updating with Write-Through
 
Member
Description
CacheItemVersion Insert(string key, CacheItem item, DSWriteOption dsWriteOption, DataSourceItemsAddedCallback onDataSourceItemAdded)
Inserts item in cache and uses default provider
CacheItemVersion Insert(string key, CacheItem item, DSWriteOption dsWriteOption, string providerName, DataSourceItemsUpdatedCallback onDataSourceItemUpdatedCallback)
Inserts item in cache and uses specified provider
 
Product product = new Product();
product.ProductID = 1001;
product.ProductName = "Chai";
 
CacheItem cacheItem = new CacheItem(product);
string key = "Product:" +product.ProductID ;
 
CacheItemVersion updatedItemVersion;
try
{
updatedItemVersion = cache.Insert(key, cacheItem, DSWriteOption.WriteThru, "XmlWriteThruProvider", null);
if (updatedItemVersion.Version> 1)
    {
//Item updated in cache. Perform further tasks.
    }
}
catch (OperationFailedException exp)
{
//handle exception
}
 
 
  • Deleting an Existing Item with Write-Through
   
Member
Description
Delete(string key, DSWriteOption dsWriteOption, DataSourceItemsRemovedCallback onDataSourceItemRemovedCallback)
Deletes item from cache and uses default provider
Delete(string key, DSWriteOption dsWriteOption, string providerName, DataSourceItemsRemovedCallback onDataSourceItemRemovedCallback);
Deletes item from cache and uses specified provider
 
string key = "Product:1001";
try
{
cache.Delete(key, DSWriteOption.WriteThru, null);
}
catch (OperationFailedException exp)
{
// handle exception
}
 
  • Removing an Existing Item with Write-Through
 
Member
Description
object Remove(string key, DSWriteOption dsWriteOption, DataSourceItemsRemovedCallback onDataSourceItemRemovedCallback)
Removes item from cache and uses default provider
object Remove(string key, DSWriteOption dsWriteOption, string providerName, DataSourceItemsRemovedCallback onDataSourceItemRemovedCallback);
 
Removes item from cache and uses specified provider.
 
string key = "Product:1001";
Product product = null;
try
{
Object returnObject = cache.Remove(key, DSWriteOption.WriteThru, null);
//Verify the removed item from both cache and data source
if (returnObject != null)
    {
product = (Product)returnObject;
    }
}
catch (OperationFailedException exp)
{ // handle exception }
 
  • Adding New Item Asynchronously
 
Member
Description
AddAsync(string key, CacheItem item, DSWriteOption dsWriteOption, DataSourceItemsAddedCallback onDataSourceItemAdded);
 
Uses default provider and add item in cache asynchronously.
 
Product product = new Product();
product.ProductID = 1001;
product.ProductName = "Chai";
 
CacheItem cacheItem = new CacheItem(product);
string key = "Product:" + product.ProductID ;
 
try
{
    cache.AddAsync(key, cacheItem, DSWriteOption.WriteThru, null);
}
catch (OperationFailedException exp)
{
//handle exception
}
 
 
  • Adding with Write-Behind
 
Member
Description
CacheItemVersion Add(string key, CacheItem item, DSWriteOption dsWriteOption, string providerName, DataSourceItemsAddedCallback onDataSourceItemAdded)
 
Adds item in cache by using Custom Provider and Write-Behind.
 
i. Add without Callback Method
 
string key = "Customer:David:1001";
CacheItem cacheItem = new CacheItem(new Product());
   
try
{
        cache.Add(key, cacheItem, DSWriteOption.WriteBehind, null);
}
catch (Exception exp)
{
    //Operation fails if the item already exists
    // Request is not sent to the backing source in
}
 
ii. Add with Callback Method
 
protected void OnDataSourceItemsAdded(IDictionary iDict)
{
//Perform appropriate actions upon response
}
 
private void AddTest()
{
string key = "Customer:David:1001";
CacheItem cacheItem = new CacheItem(new Product());
   
try
{
        cache.Add(key, cacheItem, DSWriteOption.WriteBehind, OnDataSourceItemsAdded);
//Verify item added in cache and in main source
}
catch (Exception exp)
{
    //Operation fails if the item already exists
}
}
 
  • Updating Existing Data with Write-Behind
 
Member
Description
CacheItemVersion Insert(string key, CacheItem item, DSWriteOption dsWriteOption, string providerName, DataSourceItemsUpdatedCallback onDataSourceItemUpdatedCallback);
 
Adds item in cache by using default provider and write-behind.
CacheItemVersion Insert(string key, CacheItem item, DSWriteOption dsWriteOption, string providerName, DataSourceItemsUpdatedCallback onDataSourceItemUpdatedCallback);
Adds item in cache by using custom provider and write-behind.
 
protected void OnDataSourceItemsUpdated(IDictionary iDict)
{
//Perform appropriate actions upon response
}
private void UpdateTest()
{
string key = "Customer:David:1001";
 cacheItem.SubGroup = "WriteThru-Test";
   
  try
 {
cache.Insert(key, cacheItem, DSWriteOption.WriteBehind,OnDataSourceItemsUpdated);
 }
 catch (Exception exp)
 {
    //handle exception
 }
}
 
  • Deleting Existing Data with Write-Behind
   
Member
Description
Delete(string key, DSWriteOption dsWriteOption, DataSourceItemsRemovedCallback onDataSourceItemRemovedCallback);
 
Deletes item in cache with default provider and write-behind option.
Delete(string key, DSWriteOption dsWriteOption, string providerName,DataSourceItemsRemovedCallback onDataSourceItemRemovedCallback);
 
Deletes item in cache with custom provider and write-behind option.
 
protected void OnDataSourceItemsRemoved(IDictionary iDict)
{
//Perform appropriate actions upon response
}
 
private void DeleteTest()
{
string key = "Customer:David:1001";
try
{
     cache.Delete(key, DSWriteOption.WriteBehind, OnDataSourceItemsRemoved);
    //Verify the removed item from both cache and data source
}
catch (OperationFailedException exp)
{
    //Operation fails if key does not exist in the cache
}
}
 
  • Asynchronous Operations with Write-Behind
 
i. Add New Item Asynchronously
 
Member
Description
AddAsync(string key, CacheItem item, DSWriteOption dsWriteOption, DataSourceItemsAddedCallback onDataSourceItemAdded);
 
Add item asynchronously in cache by using default provider and write-behind option.
void AddAsync(string key, CacheItem item, DSWriteOption dsWriteOption, string providerName, DataSourceItemsAddedCallback onDataSourceItemAdded)
Add item asynchronously in cache by using custom provider and write-behind option.
 
protected void OnDataSourceItemsAdded(IDictionary iDict)
{
//Perform appropriate actions upon response
}
 
private void AsyncAddTest()
{
try
    {
    string key = "Customer:David:1001";
    CacheItem cacheItem = new CacheItem(new Product());
    cache.AddAsync(key, cacheItem, DSWriteOption.WriteBehind,OnDataSourceItemsAdded);
//verify that the key is added in Cache and master source
 
    }
    catch (Exception exp)
    {
      //handle exception
    }
}
 
ii. Update Existing Item Asynchronously
 
Member
Description
void InsertAsync(string key, CacheItem item, DSWriteOption dsWriteOption, DataSourceItemsUpdatedCallback onDataSourceItemUpdatedCallback)
 
Updates existing item asynchronously in cache by using default provider
void InsertAsync(string key, CacheItem item, string providerName, DSWriteOption dsWriteOption, DataSourceItemsUpdatedCallback onDataSourceItemUpdatedCallback)
Updates existing item asynchronously in cache by using custom provider
 
protected void OnDataSourceItemsUpdated(IDictionary iDict)
{
//Perform appropriate actions upon response
}
 
private void AsyncUpdateTest()
{
 
Cache mycache = NCache.InitializeCache("myreplicatedcache");
try
{
string key = "Customer:David:1001";
CacheItem cacheItem = new CacheItem(new Product());
    cacheItem.SubGroup = "Async-WriteThru-Test";
cache.InsertAsync(key, cacheItem, DSWriteOption.WriteBehind, OnDataSourceItemsUpdated);
 
//verify that the key is updated in Cache and master source
}
catch (Exception exp)
{
    //handle exception
}
    }
 
  • Bulk Operations with Write-Behind
 
i. Add New Items Using AddBulk Call
   
Member
Description
IDictionary AddBulk(string[] keys, CacheItem[] items, DSWriteOption dsWriteOption, DataSourceItemsAddedCallback onDataSourceItemsAdded)
Adds items in cache by using default provider
IDictionary AddBulk(string[] keys, CacheItem[] items, DSWriteOption dsWriteOption, string providerName, DataSourceItemsAddedCallback onDataSourceItemsAdded)
Adds item in cache by using specific provider
 
protected void OnDataSourceItemsAdded(IDictionary iDict)
{
//Perform appropriate actions upon response
}
 
private void BulkAddTest()
{
try
{
String[] key = {"Customer:David:1001","Customer:Paul:1002","Customer:Dave:1003","Customer:Mathew:1004"};
//create custom objects of Product type
CacheItem[] data = GetCacheItems(keys.Length);
IDictionary failedItems = cache.AddBulk(keys, data, DSWriteOption.WriteBehind, OnDataSourceItemsAdded);
//verify updated items in the main source
}
catch (Exception exp)
{
  //handle exception
}
}
 
ii. Update Existing Items Using InsertBulk API
 
Member
Description
IDictionary InsertBulk(string[] keys, CacheItem[] items, DSWriteOption dsWriteOption, DataSourceItemsUpdatedCallback onDataSourceItemUpdatedCallback)
 
Updates items in cache by using default provider and providing callback
IDictionary InsertBulk(string[] keys, CacheItem[] items, DSWriteOption dsWriteOption, string providerName, DataSourceItemsAddedCallback onDataSourceItemsAdded)
Updates items in cache by using specific provider and providing callback
 
protected void OnDataSourceItemsUpdated(IDictionary iDict)
{
//Perform appropriate actions upon response
}
 
private void BulkUpdateTest()
{
try
{
String[] key = {"Customer:David:1001","Customer:Paul:1002","Customer:Dave:1003","Customer:Mathew:1004"};
//create new  custom objects for above mentioned keys of Product type
CacheItem[] data = cache.GetCacheItems(keys.Length);
 
IDictionary failedItems = cache.InsertBulk(keys, data, DSWriteOption.WriteBehind, OnDataSourceItemsUpdated);
 
//verify updated items in the main source
 
}
catch (Exception exp)
{
  //handle exception
}
 
}
 
iii. Delete Existing Items Using DeleteBulk API
 
Member
Description
void DeleteBulk(string[] keys, DSWriteOption dsWriteOption, DataSourceItemsRemovedCallback onDataSourceItemsRemovedCallback)
 
Deletes items in cache by using default provider and providing callback
 
protected void OnDataSourceItemsRemoved(IDictionary iDict)
{
//Perform appropriate actions upon response
}
 
private void BulkDeleteTest()
{
try    
{
 
String[] key = {"Customer:David:1001","Customer:Paul:1002","Customer:Dave:1003","Customer:Mathew:1004"};
IDictionary failedItems = cache.DeleteBulk(keys, DSWriteOption.WriteBehind,  OnDataSourceItemsRemoved );
//verify items deleted from the main source
}
catch (Exception exp)
{
    //handle exception
}
}
 
 
See Also