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.
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
}
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
}
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
}
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 }
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
}
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
}
}
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
}
}
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
}
}
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
}
}
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