Use AB_ConfiguredCacheCollection to create one or more AB_Caches that are config-driven

  • 402 Views
  • Last Post 10 August 2016
dwebb posted this 10 August 2016

In Use AB_Cache to store state information objects for a short time the low-level interface for creating and using AB_Cache is documented. To use the low-level interface, caching properties must be hardcoded or otherwise provided.

AB_ConfiguredCacheCollection allows a set of caching properties to be defined in a configuration file, and then one or more AB_Caches can be instantiated using those properties.

Usage - Set up Cache:

// Set up static service-side cache for holding custom field definitions
protected static AB_ConfiguredCacheCollection ap_WorkflowCaches = new AB_ConfiguredCacheCollection { };

// Get the custom fields cache; if the cache is disabled this will return null
protected static AB_Cache ap_CustomFieldsCache { get { return ap_WorkflowCaches["CustomFieldsCache"]; } }

The string used as an index on ap_WorkflowCaches is used to find the configuration entries. For this pool we're setting a 10 minute sliding expiration policy.

Configuration:

<add key="Feature.CustomFieldsCache.IsDisabled" value="False"/>
<add key="Feature.CustomFieldsCache.CacheMemoryLimitMegabytes" value="0"/>
<add key="Feature.CustomFieldsCache.PhysicalMemoryLimitPercentage" value="0"/>
<add key="Feature.CustomFieldsCache.PollingInterval" value="00:02:00"/>
<add key="Feature.CustomFieldsCache.SlidingExpiration" value="00:10:00"/>

Order By: Standard | Newest | Votes
dwebb posted this 10 August 2016

Usage - Populate and use cache if enabled:

This code example emulates calling am_Select() with an input entity that has ReferenceNamespace set, but no other search fields or ap_Query properties are specified. It confirms caching is enabled by making sure ap_CustomFieldsCache is not null. (If caching is not enabled, an else block must be used that performs the normal am_Select query.)

Next, the cache item, which is an ObservableCollection of all of the custom field records, is retrieved. If it is not available, a query is performed to get the records and they are stored in the cache.

The cached records are then filtered against the ReferenceNamespace value in the entity. This step will be different for each cache, and obviously simpler filters will be much easier to implement. Be wary of the number of results; there is a tradeoff here between putting load on the database and doing the filtering in SQL for each request vs loading all of the records in one request, transferring all of that data to the BP and storing it in memory, so that the per-request filtering can occur in the BP service instead of making a database call.

Finally, a new AB_SelectReturnArgs object is created to emulate am_Select's return value.

if (ap_CustomFieldsCache != null)
{
    // Custom fields are not user-specific, so cache region is set to null
    var allCustomFields = ap_CustomFieldsCache.Get("AllCustomFields", null) as ObservableCollection<CF_CustomFieldsEntity>;

    if (allCustomFields == null)
    {
        var inArgs = new AB_SelectInputArgs<CF_CustomFieldsEntity>(new CF_CustomFieldsEntity())
        {
            ap_MaxCount = int.MaxValue - 1
        };
        inArgs.am_InitializeWith(inputArgs);
        var retArgs = new CF_CustomFieldsBP().am_Select(inArgs);
        allCustomFields = retArgs.ap_IsSuccess
            ? retArgs.ap_OutputRecords as ObservableCollection<CF_CustomFieldsEntity>
            : new ObservableCollection<CF_CustomFieldsEntity>();

            ap_CustomFieldsCache.Set("AllCustomFields", allCustomFields, ap_CustomFieldsCache.am_GetPolicy(), null);

        if (!retArgs.ap_IsSuccess)
            return retArgs;
    }

    var referenceNamespace = (inputArgs.ap_InputEntity as CF_CustomFieldsEntity).ReferenceNamespace;

    var outputRecords = allCustomFields.Where(cf => cf.ReferenceNamespace == referenceNamespace).am_ToObservable();
    return new AB_SelectReturnArgs<CF_CustomFieldsEntity>(outputRecords.Count, AB_ReturnCodes.OK.ToString(), false, false, "OK", outputRecords);
}

dwebb posted this 10 August 2016

Usage - Invalidate the cache

When caching results from am_Select, you'll generally also need to clear that cache whenever the underlying data changes. am_Insert, am_Update, and am_PermDelete (and their batch versions) will usually need code like this:

// Invalidate cache if neccessary
if (ap_CustomFieldsCache != null)
{
    ap_CustomFieldsCache.Remove("AllCustomFields", null);
}

Close