• Webinars
  • Docs
  • Download
  • Blogs
  • Contact Us
Try NCache Live
Show / Hide Table of Contents

Read-Through Provider Configuration and Implementation

Note

This feature is only available in NCache Enterprise Edition.

To use Read-through caching, you need to implement the IReadThruProvider interface provided by NCache. NCache framework will use this custom implementation to read data from the back-end data source. Please refer to Configuring Read-through in Administrators' Guide for more details.

Note that if a read-through provider is specified in client.ncconf in the default-readthru-provider tag, and has also been specified through API, the provider in API will overwrite the one specified in client.ncconf.

Note

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.

Important

For Java, before adding Maven dependencies, you need to make sure that:

  • You have JDK 11 installed.
  • Your Environment Variable for Java is set.

Pre-Requisites

  • .NET/.NET Core
  • Java
  • Install the following NuGet package in your application.
    • Alachisoft.NCache.SDK
  • To utilize the APIs, include the following namespaces in your application:
    • Alachisoft.NCache.Runtime.DatasourceProviders
    • Alachisoft.NCache.Runtime
    • Alachisoft.NCache.Runtime.Exceptions
  • This should be a class library project using Microsoft Visual Studio.
  • Make sure to Deploy ReadThrough Provider using NCache Web Manager.
  • For API details refer to:IReadThruProvider, LoadFromSource(), LoadDataTypeFromSource().
  • Add the following Maven dependencies in your pom.xml file:
<dependency>
    <groupId>com.alachisoft.ncache</groupId>
    <artifactId>ncache-client</artifactId>
    <version>5.2.0</version>
</dependency>
  • Import the following packages in your application:
    • import com.alachisoft.ncache.runtime.exceptions.*
    • import com.alachisoft.ncache.client.*;
    • import com.alachisoft.ncache.runtime.datasourceprovider.*
  • The application must be connected to cache before performing the operation.
  • Cache must be running.
  • Make sure that the data being added is serializable.
  • Make sure to Deploy ReadThrough Provider using NCache Web Manager.
  • For API details refer to:ReadThruProvider, loadFromSource().
  • To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
  • To handle any unseen exceptions, refer to the Troubleshooting section.

Sample Implementation

The following code sample provides sample implementation to configure a read-through provider using the IReadThruProvider class. The LoadFromSource() and LoadDataTypeFromSource() methods contains logic to load an object or data type respectively from the configured data source, if the object is not found in the cache.

  • .NET/.NET Core
  • Java
public class SampleReadThruProvider : IReadThruProvider
{
    private SqlConnection _connection;

    //Perform tasks like allocating resources or acquiring connections
    public void Init(IDictionary parameters, string cacheId)
    {
        object server = parameters["server"];
        object userId = parameters["username"];
        object password = parameters["password"];
        object database = parameters["database"];

        string connString = GetConnectionString(server.ToString(), database.ToString(), userId.ToString(), password.ToString());

        if (connString != "")
            _connection = new SqlConnection(connString);
        try
        {
            _connection.Open();
        }
        catch (Exception ex)
        {
            //handle exception
        }
    }

    // Responsible for loading an item from the external data source
    public ProviderCacheItem LoadFromSource(string key)
    {
        // LoadFromDataSource loads data from data source
        object value = LoadFromDataSource(key);
        var cacheItem = new ProviderCacheItem(value);
        return cacheItem;
    }

    //Responsible for loading bulk of items from the external data source
    public IDictionary<string, ProviderCacheItem> LoadFromSource(ICollection<string> keys)
    {
        var dictionary = new Dictionary<string, ProviderCacheItem>();
        try
        {
            foreach (string key in keys)
            {
                // LoadFromDataSource loads data from data source
                dictionary.Add(key, new ProviderCacheItem(LoadFromDataSource(key)));
            }
            return dictionary;
        }
        catch (Exception exp)
        {
            // Handle exception
        }
        return dictionary;
    }

    // Adds ProviderDataTypeItem with enumerable data type
    public ProviderDataTypeItem<IEnumerable> LoadDataTypeFromSource(string key, DistributedDataType dataType)
    {
        IEnumerable value = null;
        ProviderDataTypeItem<IEnumerable> dataTypeItem = null;

        switch (dataType)
        {
            case DistributedDataType.List:
                value = new List<object>()
                {
                    LoadFromDataSource(key)
                };                 
                dataTypeItem = new ProviderDataTypeItem<IEnumerable>(value);
            break;

            case DistributedDataType.Dictionary:
                value = new Dictionary<string, object>()
                {
                    { key ,  LoadFromDataSource(key) }
                };                       
                dataTypeItem = new ProviderDataTypeItem<IEnumerable>(value);
            break;

            case DistributedDataType.Counter:
                dataTypeItem = new ProviderDataTypeItem<IEnumerable>(1000);
            break;
        }

        return dataTypeItem;
    }

    //Perform tasks associated with freeing, releasing, or resetting resources.
    public void Dispose()
    {
        if (_connection != null)
        _connection.Close();
    }

    private object LoadFromDataSource(string key)
    {
        object retrievedObject = null;

        // Load item from your data source and populate retrieved Object
        return retrievedObject;
    }

    private string GetConnectionString(string server, string database, string userName, string password)
    {
        string connectionString = null;
        try
        {
            if (!string.IsNullOrEmpty(server))
                connectionString = "Server=" + server + ";";
            else
                //Server name is empty

            if (!string.IsNullOrEmpty(database))
                connectionString = connectionString + "Database=" + database + ";";
            else
                //Database is empty;

            if (!string.IsNullOrEmpty(userName))
                connectionString = connectionString + "User ID=" + userName + ";";
            else
                connectionString = connectionString + "User ID=" + "" + ";";

            if (!string.IsNullOrEmpty(password))
                connectionString = connectionString + "Password=" + password + ";";
            else
                connectionString = connectionString + "Password=" + "" + ";";
        }
        catch (Exception exp)
        {
            // Handle exception
        }

        return connectionString;
    } 

    // Deploy this class on cache
}
public class SampleReadThruProvider implements ReadThruProvider
{  
    private Connection _connection;

    //Perform tasks like allocating resources or acquiring connections
    public void init(Map<String,String> parameters, String cacheId) throws SQLException 
    {      
        String connString = getConnectionString(parameters);

        if (connString.isEmpty())
        {
            _connection.prepareStatement(connString);
            _connection.beginRequest();
        }
    }

    // Responsible for loading an item from the external data source
    public ProviderCacheItem loadFromSource(String key)
    {
        // LoadFromDataSource loads data from data source
        var value = loadFromDataSource(key);
        var cacheItem = new ProviderCacheItem(value);
        return cacheItem;
    }

    //Responsible for loading bulk of items from the external data source
    public Map<String,ProviderCacheItem> loadFromSource(Collection<String> keys)
    {
       var dictionary = new HashMap<String,ProviderCacheItem>();

        try
        {
            for (String key: keys)
            {
                // LoadFromDataSource loads data from data source
                dictionary.put(key,new ProviderCacheItem(loadFromDataSource(key)));
            }
            return dictionary;
        }
        catch (Exception ex)
        {
            // Handle exception
        }
        return dictionary;
    }

    // Adds ProviderDataTypeItem with enumerable data type
    public ProviderDataStructureItem<Iterator> loadDataStructureFromSource(String key, DistributedDataStructureType distributedDataStructureType) throws OperationFailedException
    {      
        Iterator value = null;
        ProviderDataStructureItem<Iterator> dataStructureItem = null;

        switch (distributedDataStructureType)
        {
            case List:
                // provide your own logic here
                 value = (Iterator) new ArrayList<String>();
                dataStructureItem = new ProviderDataStructureItem<Iterator>(value);
                break;
            case Map:
                value = (Iterator) new HashMap<String,Object>();
                // provide your own logic here
                dataStructureItem = new ProviderDataStructureItem<Iterator>(value);
                break;
            case Counter:
                // provide your own logic here
                dataStructureItem = new ProviderDataStructureItem<Iterator>(1000);
                break;
        }
        return dataStructureItem;
    }

    //Perform tasks associated with freeing, releasing, or resetting resources.
    public void close() throws SQLException 
    {       
        if (_connection != null)
        {
            _connection.close();
        }
    }

    private Object loadFromDataSource(String key)
    {       
        Object retrievedObject = null;

        // Load item from your data source and populate retrieved Object
        return retrievedObject;
    }

    public String getConnectionString(Map parameters)
    {

        String connectionString = null;
        try
        {        
            String server = parameters.get("server").toString();
            String database = parameters.get("database").toString();
            String userName = parameters.get("username").toString();
            String password = parameters.get("password").toString();

            if (!server.isEmpty())
            {
                connectionString = "Server=" + server + ";";
            }
            else
            {
                // Server name is empty
            }
            if (!database.isEmpty())
            {
                connectionString = connectionString + "Database=" + database + ";";
            }
            else
            {
                // Database is empty
            }
            if (!userName.isEmpty())
            {
                connectionString = connectionString + "User ID=" + userName + ";";
            }
            else
            {
                connectionString = connectionString + "User ID=" + "" + ";";
            }
            if (!password.isEmpty())
            {
                connectionString = connectionString + "Password=" + password + ";";
            }
            else
            {
                connectionString = connectionString + "Password=" + "" + ";";
            }
        }
        catch (Exception ex)
        {
            // Handle exception
        }
        return connectionString;
    }
} 

Additional Resources

NCache provides sample application for read-through on GitHub.

See Also

Using Read-Through with Cache Operations
Configuring Read-Through Provider
Write-Through Caching
Cache Startup Loader and Refresher
Custom Cache Dependencies

Back to top Copyright © 2017 Alachisoft