RetrieveOptionsCreateHandler Property

ScaleOut Software NamedCache API
Gets/sets the optional, custom object creation callback to use when an attempt is made to retrieve an object that is not in the cache. The default is null.

Namespace:  Soss.Client
Assembly:  soss_namedcache (in soss_namedcache.dll) Version:

public CreateHandler CreateHandler { get; set; }

Property Value

Type: CreateHandler

This property specifies logic that can be invoked when an object is not found in the StateServer store and needs to be transparently created and returned to the caller of the Retrieve(String, RetrieveOptions) method. The assigned method must return the object that is to be added to the cache.

If multiple clients and/or threads simultaneously attempt to read the missing object, only one thread in one client will be permitted to execute the CreateHandler method so as to prevent multiple clients/thread from simultaneously creating the object--this behavior is valuable when creating the cached object involves expensive calls to a database or when it is otherwise undesirable for an object to be repeatedly created in the cache. Other clients/threads that try to retrieve the object while the callback is executing will be blocked while the object is being created, and, once the object has been added to the cache, those other threads will be unblocked and the newly-cached object will be returned to all of them.

If this callback is non-null then it will override any existing read-though backing store behavior that has been specified at the named cache level through the SetBackingStoreAdapter(IBackingStore, BackingStorePolicy) method.


Configuring NamedCache.Retrieve to create a missing object
// CREATE TABLE Pricelist (ProductId nvarchar(50) NOT NULL, Price money NOT NULL)
// INSERT INTO PriceList (ProductId, Price) VALUES ('TickleMeElmo', 33.44)

using System;
using System.Data;
using System.Data.SqlClient;
using Soss.Client;

class Program
    /// <summary>
    /// Retrieves a dataset of products within a price range from the StateServer
    /// cache, creating the object in the cache if necessary.
    /// </summary>
    static void Main(string[] args)
        NamedCache priceCache = CacheFactory.GetCache("Products");

        // Configure the RetrieveOptions to perform automatic object creation in case
        // the requested object isn't found in the cache. This is accomplished by assigning
        // a CreateHandler delegate that is capable of returning the missing object.
        // Note that RetrieveOptions will override any backing store configuration 
        // that was set up at the named cache level (via NamedCache.SetBackingStoreAdapter).

        // This approach allows for fine-grained control over read-though logic in cases
        // where read-though behavior needs to be modified on a call-by-call basis.

        RetrieveOptions options = new RetrieveOptions();
        options.CreateHandler = ObjectCreationCallback;
        options.CreateArgument = new PriceRange() { MinPrice = 0.00m, MaxPrice = 50.00m };
        options.CreatePolicy = new CreatePolicy(TimeSpan.FromMinutes(5));

        // Retrieve the dataset from the cache. Using the provided options, the Retrieve call will 
        // transparently retrieve the object from the DB and add it to the cache if it's missing. 
        // While the first thread is executing the callback, other threads/clients requesting this 
        // object will block until the callback has completed adding the object to the cache.
        DataSet priceList = priceCache.Retrieve("Inexpensive Products", options) as DataSet;

        if (priceList != null)
            Console.WriteLine("{0} rows in dataset", priceList.Tables[0].Rows.Count);
            Console.WriteLine("Object create callback did not retrieve the object from the DB.");

        Console.WriteLine("Hit ENTER to exit.");

    /// <summary>
    /// Custom callback used to perform a database retrieval operation. Returns
    /// a DataSet of products that falls within a price range.
    /// </summary>
    /// <param name="id">The identifier of the object to retrieve from the database.</param>
    /// <param name="argument">
    /// Additional argument that can be used to perform the database retrieval
    /// (a range of product prices, in this case). This argument is provided by the
    /// RetrieveOptions.CreateArgument property that is passed into the
    /// NamedCache.Retrieve method.
    /// </param>
    /// <returns>The object from the database that is to be stored is ScaleOut StateServer.</returns>
    static object ObjectCreationCallback(CachedObjectId id, object argument)
            Console.WriteLine("Cache miss. Retrieving '{0}' from database.", id.GetStringKey());
            PriceRange priceRange = argument as PriceRange;

            string connString = "Data Source=localhost;Initial Catalog=BackingStoreSample;Integrated Security=true";
            string cmdText = string.Format("SELECT ProductId, Price FROM PriceList WHERE Price >= {0} AND Price <= {1}",
                                            priceRange.MinPrice, priceRange.MaxPrice);

            DataSet priceDataSet = new DataSet();
            SqlConnection conn = new SqlConnection(connString);
            SqlCommand selectCommand = new SqlCommand(cmdText, conn);
            SqlDataAdapter adapter = new SqlDataAdapter(selectCommand);


            return priceDataSet;
        catch (Exception ex)
            // *Always* catch exceptions from a the object-creation callback and return null
            // immediately, otherwise other threads/clients that are waiting for this object
            // to be inserted into the cache will continue to poll.
            Console.WriteLine("Database retrieval failed: " + ex.Message);
            return null;


/// <summary>
/// Class representing a range of prices. Used as an argument for database
/// retrieval operations.
/// </summary>
class PriceRange
    public decimal MinPrice { get; set; }
    public decimal MaxPrice { get; set; }
See Also