Кэширование данных

Кэширование данных следует использовать для повышения производительности приложения.

В системе ELMA существует несколько типов кэша:

  • Глобальный кэш (ICacheService) – предназначен для кэширования данных между веб-запросами. Следует использовать для кэширования данных, актуальность которых по заданному времени не критична. В случае использования фермы серверов данные, хранящиеся в данном кэше, доступны и одинаковы на каждом из серверов ELMA;
  • Серверный кэш (IMemoryCacheService) – предназначен для хранения данных в памяти одного экземпляра сервера ELMA. Следует использовать для кэширования данных, которые не изменяются на всем протяжении жизни сервера (например, данные, вычисленные по рефлексии):
    • Кэш метаданных (модификация типа Серверный кэш, созданная на основе IMemoryCacheService) – специальное хранилище объектов метаданных, которое очищается при публикации. Кэш метаданных предназначен для хранения метаданных, результатов, вычисленных на основе метаданных, и рефлексии по типам, которые могут измениться при публикации;
  • Составной кэш (IComplexCacheService) – предназначен для хранения данных в памяти одного экземпляра сервера ELMA с гарантией сброса в случае использования фермы серверов и изменении данных на одном из серверов;
  • Составной кэш для хранения редко меняющихся данных (IUnionComplexCacheService) – предназначен для хранения данных в памяти одного экземпляра сервера ELMA с редким обращением к распределенному кэшу для актуализации информации. Следует использовать для кэширования данных, которые редко меняются. Для всех этих данных будет выполняться общий запрос для проверки на изменение, за счет этого уменьшается нагрузка на распределенный кэш при использовании фермы серверов;
  • Контекстный кэш (IContextBoundVariableService) – предназначен для кэширования в рамках одного веб-запроса, следует пользоваться для предотвращения повторных вычисления данных, обновление которых в рамках одного веб запроса не влияет на логику.

Глобальный кэш

Система ELMA имеет собственный API для кэширования данных, следует использовать именно его и ничто другое (ASP.NERT Cachem memecached и пр.).

Реализация данного кэша зависит от окружения, в котором запущено приложение. В случае запуска на одном сервере данные хранятся в памяти сервера. В случае фермы серверов (кластера) – в распределенном кэше – это самостоятельное приложение (служба кэша AppFabric).

Следует отметить, что разработчик AppFabric завершил обслуживание сервера и больше не выполняет его обновление. В связи с этим компания ELMA прекращает поддержку компонента. Для корректной работы рекомендуется своевременно перейти на Redis. Инструкцию по переходу см. в статье Перенос хранения пользовательских сессий в Redis.

Поэтому при использовании данного типа кэша всегда нужно помнить о распределенном кэше.

ICacheService

ICacheService регистрируется в IoC контейнере и доступен для использования во всех серверных компонентах приложения. Конкретная реализация ICacheService зависит от окружения, в котором запущено приложение - самостоятельное приложение на одном сервере IIS - ферма кластеров на базе IIS - Windows Azure.

/// <summary>
    /// Интерфейс работы с кэшем
    /// </summary>
    public interface ICacheService
    {

        /// <summary>
        /// Добавить или изменить элемент кэша по ключу с указанием зависимости и времени кэширования
        /// </summary>
        /// <typeparam name="T">Тип кэшируемого значения в кэше</typeparam>
        /// <param name="key">Ключ</param>
        /// <param name="value">Кэшируемый элемент</param>
        /// <param name="region">Регион</param>
        /// <param name="cacheDuration">Длительность хранения значения в кэше</param>
        void Insert<T>(string key, T value, string region, TimeSpan cacheDuration);

        /// <summary>
        /// Добавить или изменить элемент кэша по ключу с указанием времени кэширования
        /// </summary>
        /// <typeparam name="T">Тип кэшируемого значения в кэше</typeparam>
        /// <param name="key">Ключ</param>
        /// <param name="value">Кэшируемый элемент</param>
        /// <param name="cacheDuration">Длительность хранения значения в кэше</param>
        void Insert<T>(string key, T value, TimeSpan cacheDuration);

        /// <summary>
        /// Добавить или изменить элемент кэша по ключу c зависимостью
        /// </summary>
        /// <typeparam name="T">Тип кэшируемого значения в кэше</typeparam>
        /// <param name="key">Ключ</param>
        /// <param name="value">Кэшируемый элемент</param>
        /// <param name="region">Регион</param>
        void Insert<T>(string key, T value, string region);

        /// <summary>
        /// Добавить или изменить элемент кэша по ключу
        /// </summary>
        /// <typeparam name="T">Тип кэшируемого значения в кэше</typeparam>
        /// <param name="key">Ключ</param>
        /// <param name="value">Кэшируемый элемент</param>
        void Insert<T>(string key, T value);

        /// <summary>
        /// Проверить наличие элемента в кэше по ключу. !!! Не использовать без крайней необходимости (вместо Contains Get нужно использовать TryGetValue)!
        /// </summary>
        /// <param name="key">Ключ</param>
        /// <returns>True, если элемент есть в кэше</returns>
        bool Contains(string key);

        /// <summary>
        /// Проверить наличие элемента в кэше по ключу и региону. !!! Не использовать без крайней необходимости (вместо Contains Get нужно использовать TryGetValue)!
        /// </summary>
        /// <param name="key">Ключ</param>
        /// <param name="region">Регион</param>
        /// <returns>True, если элемент есть в кэше</returns>
        bool Contains(string key, string region);

        /// <summary>
        /// Получить элемент из кэша по ключу
        /// </summary>
        /// <typeparam name="T">Тип кэшируемого значения в кэше</typeparam>
        /// <param name="key">Ключ</param>
        /// <returns>Значение</returns>
        T Get<T>(string key);

        /// <summary>
        /// Получить элемент из кэша по ключу
        /// </summary>
        /// <typeparam name="T">Тип кэшируемого значения в кэше</typeparam>
        /// <param name="key">Ключ</param>
        /// <param name="region">Регион</param>
        /// <returns>Значение</returns>
        T Get<T>(string key, string region);

        /// <summary>
        /// Попытаться получить элемент из кэша по ключу
        /// </summary>
        /// <typeparam name="T">Тип кэшируемого значения в кэше</typeparam>
        /// <param name="key">Ключ</param>
        /// <param name="value">Полученный элемент (или значение по умолчанию для типа <typeparamref name="T"/>, если элемент не найден)</param>
        /// <returns>True, если элемент найден в кэше</returns>
        bool TryGetValue<T>(string key, out T value);

        /// <summary>
        /// Попытаться получить элемент из кэша по ключу и региону
        /// </summary>
        /// <typeparam name="T">Тип кэшируемого значения в кэше</typeparam>
        /// <param name="key">Ключ</param>
        /// <param name="region">Регион</param>
        /// <returns>True, если элемент найден в кэше</returns>
        bool TryGetValue<T>(string key, string region, out T value);

        /// <summary>
        /// Удалить элемент из кэша по ключу
        /// </summary>
        /// <param name="key">Ключ</param>
        void Remove(string key);

        /// <summary>
        /// Удалить элемент из кэша по ключу
        /// </summary>
        /// <param name="key">Ключ</param>
        /// <param name="region">Регион</param>
        void Remove(string key, string region);

        /// <summary>
        /// Удалить все данные из региона
        /// </summary>
        /// <param name="region">Регион</param>
        void ClearRegion(string region);

        /// <summary>
        /// Признак, что кэш распределенный
        /// </summary>
        bool IsDistributed { get; }

    }

Кэширование возвращаемых значений методов

Атрибут CacheAttribute позволяет кэшировать возвращаемые значения методов вызываемых у компонентов. В момент вызова метода составляет ключ на основе значений переданных аргументов и проверяется наличие элемента в кэше через ICacheService: если элемент в кэше уже есть, то значение возвращается из кэша, в противном случае - вызывается тело метода и результат помещается в кэш.

Метод помеченный атрибутом CacheAttribute должен удовлетворять следующим условиям:

  • объявлен с ключевым словом virtual;
  • возвращаемое значение сериализуемое (помечено атрибутом Serializable);
  • аргументы метода должны быть либо примитивными либо реализовать интерфейс IIdentified.

Пример: загрузка данных по url кэшируется на 5 секунд.

using System.Net;
using System.Xml;
using EleWise.ELMA.Cache.Attributes;
using EleWise.ELMA.ComponentModel;
 
[Service] 
public class FeedLoader
{
 
/// <summary>
/// Загрузить данные в формате xml
/// </summary>
/// <param name="url">адрес</param>
/// <returns></returns> 
[Cache("00:00:05")] 
public virtual XmlDocument Load(string url)
{
    var req = WebRequest.Create(url);
    var response = req.GetResponse();
    var stream = response.GetResponseStream();
    var xmlDocument = new XmlDocument();
    xmlDocument.Load(stream);
    return xmlDocument;
}
}

Серверный кэш

Реализация данного кэша, в отличие от глобального кэша, всегда хранит свои данные в памяти сервера, и в случае фермы серверов данные между узлами не синхронизируются, поэтому хранить в данном типе кэша можно только информацию, которая со временем не изменяется.

IMemoryCacheService

IMemoryCacheService регистрируется в IoC контейнере и доступен для использования во всех серверных компонентах приложения.

/// <summary>
    /// Сервис для кэширования в памяти
    /// </summary>
    public interface IMemoryCacheService
    {

        /// <summary>
        /// Попытаться получить значение из кэша
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="key">Ключ</param>
        /// <param name="result">Значение</param>
        /// <returns></returns>
        bool TryGetValue<T>(string key, out T result);

        /// <summary>
        /// Проверить наличие элемента в кэше по ключу
        /// </summary>
        /// <param name="key">Ключ</param>
        /// <returns>True, если элемент есть в кэше</returns>
        bool Contains(string key);

        /// <summary>
        /// Добавить или изменить элемент кэша по ключу
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="key">Ключ</param>
        /// <param name="value">Значение</param>
        void Insert<T>(string key, T value);

        /// <summary>
        /// Добавить или изменить элемент кэша по ключу
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="key">Ключ</param>
        /// <param name="value">Значение</param>
        /// <param name="timeout">Время хранения значения</param>
        void Insert<T>(string key, T value, TimeSpan timeout);

        /// <summary>
        /// Удалить элемент из кэша по ключу
        /// </summary>
        /// <param name="key">Ключ</param>
        void Remove(string key);

        /// <summary>
        /// Удалить по вхождению подстроки в ключ
        /// </summary>
        /// <param name="subkey"></param>
        void RemoveBySubkey(string subkey);
    }

Кэш метаданных

Внимание!
Информация, приведенная ниже, актуальна для версий системы ELMA 3.13.7 и выше.

Кэш метаданных работает на основе кэширующих функций. Создается специальная функция, на входе которой находится лямбда-выражение с параметрами. Выражение должно производить некие операции над входными данными и возвращать результат. На выходе получаем функцию, которая запоминает результаты своих вычислений в кэше метаданных и которую в дальнейшем можно использовать у себя в коде.

Принцип работы кэширующей функции: если функция ранее уже вызывалась с этими параметрами, то выдается результат из кэша, иначе – вычисляется значение, запоминается в кэше и возвращается результат.

Использование кэша метаданных происходит с помощью методов класса MetadataLoader:

public class MetadataLoader
{

    ...

    /// <summary>
    /// Создать безусловно кэширующую функцию
    /// </summary>
    /// <typeparam name="TResult">Тип возвращаемого функцией значения</typeparam>
    /// <param name="extractValueExpr">Выражение функции</param>
    /// <returns>Кэширующую функцию</returns>
    public static Func<TResult> UseCachingForFunc<TResult>(Expression<Func<TResult>> extractValueExpr) { ... }

    /// <summary>
    /// Создать безусловно кэширующую функцию и вернуть метод очистки кэша от её значений
    /// </summary>
    /// <typeparam name="TResult">Тип возвращаемого функцией значения</typeparam>
    /// <param name="extractValueExpr">Выражение функции</param>
    /// <param name="clearAction">Метод очистки кэша</param>
    /// <returns>Кэширующую функцию</returns>
    public static Func<TResult> UseCachingForFunc<TResult>(Expression<Func<TResult>> extractValueExpr, out Action clearAction) { ... }

    /// <summary>
    /// Создать безусловно кэширующую функцию
    /// </summary>
    /// <typeparam name="T1">Тип первого параметра функции</typeparam>
    /// <typeparam name="TResult">Тип возвращаемого функцией значения</typeparam>
    /// <param name="extractValueExpr">Выражение функции</param>
    /// <returns>Кэширующую функцию</returns>
    public static Func<T1, TResult> UseCachingForFunc<T1, TResult>(Expression<Func<T1, TResult>> extractValueExpr) { ... }

    /// <summary>
    /// Создать условно кэширующую функцию. Условием (кэшировать или нет полученное значение) управляет выражение функции.
    /// </summary>
    /// <typeparam name="T1">Тип первого параметра функции</typeparam>
    /// <typeparam name="TResult">Тип возвращаемого функцией значения</typeparam>
    /// <param name="extractValueExpr">Выражение функции</param>
    /// <returns>Кэширующую функцию</returns>
    public static Func<T1, TResult> UseConditionalCachingForFunc<T1, TResult>(Expression<Func<T1, Tuple<TResult, bool>>> extractValueExpr) { ... }

    /// <summary>
    /// Создать безусловно кэширующую функцию и вернуть метод очистки кэша от её значений
    /// </summary>
    /// <typeparam name="T1">Тип первого параметра функции</typeparam>
    /// <typeparam name="TResult">Тип возвращаемого функцией значения</typeparam>
    /// <param name="extractValueExpr">Выражение функции</param>
    /// <param name="clearAction">Метод очистки кэша</param>
    /// <returns>Кэширующую функцию</returns>
    public static Func<T1, TResult> UseCachingForFunc<T1, TResult>(Expression<Func<T1, TResult>> extractValueExpr, out Action clearAction) { ... }

    /// <summary>
    /// Создать безусловно кэширующую функцию
    /// </summary>
    /// <typeparam name="T1">Тип первого параметра функции</typeparam>
    /// <typeparam name="T2">Тип второго параметра функции</typeparam>
    /// <typeparam name="TResult">Тип возвращаемого функцией значения</typeparam>
    /// <param name="extractValueExpr">Выражение функции</param>
    /// <returns>Кэширующую функцию</returns>
    public static Func<T1, T2, TResult> UseCachingForFunc<T1, T2, TResult>(Expression<Func<T1, T2, TResult>> extractValueExpr) { ... }

    /// <summary>
    /// Создать безусловно кэширующую функцию и вернуть метод очистки кэша от её значений
    /// </summary>
    /// <typeparam name="T1">Тип первого параметра функции</typeparam>
    /// <typeparam name="T2">Тип второго параметра функции</typeparam>
    /// <typeparam name="TResult">Тип возвращаемого функцией значения</typeparam>
    /// <param name="extractValueExpr">Выражение функции</param>
    /// <param name="clearAction">Метод очистки кэша</param>
    /// <returns>Кэширующую функцию</returns>
    public static Func<T1, T2, TResult> UseCachingForFunc<T1, T2, TResult>(Expression<Func<T1, T2, TResult>> extractValueExpr, out Action clearAction) { ... }

    /// <summary>
    /// Создать безусловно кэширующую функцию
    /// </summary>
    /// <typeparam name="T1">Тип первого параметра функции</typeparam>
    /// <typeparam name="T2">Тип второго параметра функции</typeparam>
    /// <typeparam name="T3">Тип третьего параметра функции</typeparam>
    /// <typeparam name="TResult">Тип возвращаемого функцией значения</typeparam>
    /// <param name="extractValueExpr">Выражение функции</param>
    /// <returns>Кэширующую функцию</returns>
    public static Func<T1, T2, T3, TResult> UseCachingForFunc<T1, T2, T3, TResult>(Expression<Func<T1, T2, T3, TResult>> extractValueExpr) { ... }

    /// <summary>
    /// Создать безусловно кэширующую функцию и вернуть метод очистки кэша от её значений
    /// </summary>
    /// <typeparam name="T1">Тип первого параметра функции</typeparam>
    /// <typeparam name="T2">Тип второго параметра функции</typeparam>
    /// <typeparam name="T3">Тип третьего параметра функции</typeparam>
    /// <typeparam name="TResult">Тип возвращаемого функцией значения</typeparam>
    /// <param name="extractValueExpr">Выражение функции</param>
    /// <param name="clearAction">Метод очистки кэша</param>
    /// <returns>Кэширующую функцию</returns>
    public static Func<T1, T2, T3, TResult> UseCachingForFunc<T1, T2, T3, TResult>(Expression<Func<T1, T2, T3, TResult>> extractValueExpr, out Action clearAction) { ... }

    ...
}
Примечание
В данном способе есть ограничения:
  • параметры лямбда-выражения, поступающие на вход, должны быть простыми: Type, string, Guid, int, uint, long, ulong, bool, sbyte, byte, short, ushort, char, float, double, decimal и их перечисления (производные от IEnumerable);
  • лямбда-выражение должно быть однострочным, т.е. использование блока операций с фигурными скобками невозможно.

Перечень типов метаданных, для которых актуально применение кэша метаданных, приведен ниже:

ClassMetadata
EntityFilterMetadata
EntityMetadata
FormContextMetadata
CustomActivityParameters
DocumentMetadata
RegistrationCardMetadata
ProcessContext
ProcessInstanceMetricsContainer
ProcessMetricsContainer
ProjectMetadata
ReportParametersContainer
TablePartMetadata
Class1CMetadata
EnumMetadata
EntityActionsMetadata
EnumValueMetadata
PropertyMetadata
EntityPropertyMetadata
DocumentAttributeMetadata
ProcessInstanceMetric
ProcessMetric

Пример использования кэша метаданных:

// объявление кэширующей функции
private static Func<Type, string, bool, PropertyMetadata> getPropertyMetadata =
    MetadataLoader.UseCachingForFunc<Type, string, bool, PropertyMetadata>((type, name, inherit) => GetPropertyMetadata(type, name, inherit));

// основная функция, где производится вычисление результата
private static PropertyMetadata GetPropertyMetadata(Type type, string propName, bool inherit)
{
    var metadata = MetadataLoader.LoadMetadata(type, inherit) as ClassMetadata;
    return (metadata != null)
        ? metadata.Properties.FirstOrDefault(p => p.Name == propName)
        : null;
}

public static PropertyMetadata LoadPropertyMetadata(Type type, string propName, bool inherit)
{
    // вызов кэширующей функции
    return getPropertyMetadata(type, propName, inherit);
}

Пример использования условного кэширования:

// объявление кэширующей функции
private Func<Guid, long?> getProjectTemplateIdCached;

{
    ...
    // создание условно кэширующей функции
    getProjectTemplateIdCached = MetadataLoader.UseConditionalCachingForFunc<Guid, long?>(uid => GetProjectTemplateId(uid));
    ...
}

// функция, в которой производится вычисление результата и необходимость его кэширования
private Tuple<long?, bool> GetProjectTemplateId(Guid projectTypeUid)
{
    var template = ProjectMetadataHeadManager.GetMetadataHeadWithElevatedPrivilegies(projectTypeUid).ProjectTemplate;
    return template != null
        // это значение идентификатора шаблона проекта будет закэшировано
        ? new Tuple<long?, bool>(template.Id, true)
        // а это значение - не будет
        : new Tuple<long?, bool>(null, false);
}

private bool IsProjectTemplateInternal(T project)
{
    if (project == null)
    {
        return false;
    }

    // использование условно кэширующей функции
    var templateId = getProjectTemplateIdCached(project.TypeUid);
    // Если возвращается null, то он в кэше не запоминается.
    // И тогда при следующем вызове кэширующей функции с тем же значением project.TypeUid
    // снова производится вычисление результата

    return !templateId.HasValue || templateId == (long)project.GetId();
}

Составной кэш

При использовании составного кэша данные хранятся в памяти сервера, но в глобальном кэше хранится отпечаток времени для синхронизации между серверами фермы. Для использования данного вида кэша нужно задавать 2 ключа: для хранения данных в серверном кэше и для хранения отпечатка времени в глобальном кэше.

IComplexCacheService

IComplexCacheService регистрируется в IoC контейнере и доступен для использования во всех серверных компонентах приложения.

/// <summary>
    /// Составной кэш
    /// </summary>
    public interface IComplexCacheService
    {

        /// <summary>
        /// Получить значение из кэша или вычислить значение и записать в кэш, если не найдено
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="key">Ключ для хранения в кэше</param>
        /// <param name="timestampKey">Ключ для временного отпечатка</param>
        /// <param name="valueAccessor">Функция, возвращающая значение. Вызывается, когда в кэше информация не найдена.</param>
        /// <returns>Значение</returns>
        T GetOrAdd<T>(string key, string timestampKey, Func<T> valueAccessor);

        /// <summary>
        /// Получить значение из кэша или вычислить значение и записать в кэш, если не найдено
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="key">Ключ для хранения в кэше</param>
        /// <param name="timestampKey">Ключ для временного отпечатка</param>
        /// <param name="valueAccessor">Функция, возвращающая значение. Вызывается, когда в кэше информация не найдена.</param>
        /// <param name="timeout">Время хранения значения</param>
        /// <returns>Значение</returns>
        T GetOrAdd<T>(string key, string timestampKey, Func<T> valueAccessor, TimeSpan timeout);

        /// <summary>
        /// Получить значение из кэша или вычислить значение и записать в кэш, если не найдено
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="key">Ключ для хранения в кэше</param>
        /// <param name="timestampKey">Ключ для временного отпечатка</param>
        /// <param name="timestampRegionKey">Ключ для временного отпечатка региона</param>
        /// <param name="valueAccessor">Функция, возвращающая значение. Вызывается, когда в кэше информация не найдена.</param>
        /// <returns>Значение</returns>
        T GetOrAdd<T>(string key, string timestampKey, string timestampRegionKey, Func<T> valueAccessor);

        /// <summary>
        /// Получить значение из кэша или вычислить значение и записать в кэш, если не найдено
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="key">Ключ для хранения в кэше</param>
        /// <param name="timestampKey">Ключ для временного отпечатка</param>
        /// <param name="timestampRegionKey">Ключ для временного отпечатка региона</param>
        /// <param name="valueAccessor">Функция, возвращающая значение. Вызывается, когда в кэше информация не найдена.</param>
        /// <param name="timeout">Время хранения значения</param>
        /// <returns>Значение</returns>
        T GetOrAdd<T>(string key, string timestampKey, string timestampRegionKey, Func<T> valueAccessor, TimeSpan timeout);

        /// <summary>
        /// Обновить временной отпечаток
        /// </summary>
        /// <param name="timestampKey">Ключ для временного отпечатка</param>
        void RefreshTimestamp(string timestampKey);

        /// <summary>
        /// Обновить временной отпечаток
        /// </summary>
        /// <param name="timestampKey">Ключ для временного отпечатка</param>
        /// <param name="timestampRegionKey">Ключ для временного отпечатка региона</param>
        void RefreshTimestamp(string timestampKey, string timestampRegionKey);

        /// <summary>
        /// Обновить временной отпечаток региона
        /// </summary>
        /// <param name="timestampRegionKey">Ключ для временного отпечатка региона</param>
        void RefreshTimestampRegion(string timestampRegionKey);

    }

Кэширование возвращаемых значений методов

Атрибут ComplexCacheAttribute позволяет кэшировать возвращаемые значения методов, вызываемых у компонентов. В параметрах атрибута передается ключ для хранения отпечатка времени в глобальном кэше. В момент вызова метода составляет ключ на основе значений переданных аргументов и проверяется наличие элемента в кэше через IComplexCacheService: если элемент в кэше уже есть, то значение возвращается из кэша, в противном случае - вызывается тело метода и результат помещается в кэш.

Метод, помеченный атрибутом ComplexCacheAttribute, должен удовлетворять следующим условиям:

  • объявлен с ключевым словом virtual;
  • аргументы метода должны быть либо примитивными либо реализовать интерфейс IIdentified.

Составной кэш для хранения редко меняющихся данных

При использовании данного типа кэша данные также хранятся в памяти сервера, а в глобальном кэше хранятся отпечатки времени для синхронизации между серверами фермы для каждого элемента кэша отдельно и общий на все записи кэша. Для использования данного вида кэша, как и для составного кэша, нужно задавать 2 ключа: для хранения данных в серверном кэше и для хранения отпечатка времени в глобальном кэше.

IUnionComplexCacheService

IUnionComplexCacheService регистрируется в IoC контейнере и доступен для использования во всех серверных компонентах приложения.

/// <summary>
    /// Составной кэш для хранения редко меняющихся данных (для редкого обращения к распределенному кэшу)
    /// </summary>
    public interface IUnionComplexCacheService
    {

        /// <summary>
        /// Получить значение из кэша или вычислить значение и записать в кэш, если не найдено
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="key">Ключ для хранения в кэше</param>
        /// <param name="timestampKey">Ключ для временного отпечатка</param>
        /// <param name="valueAccessor">Функция, возвращающая значение. Вызывается, когда в кэше информация не найдена.</param>
        /// <returns>Значение</returns>
        T GetOrAdd<T>(string key, string timestampKey, Func<T> valueAccessor);

        /// <summary>
        /// Получить значение из кэша или вычислить значение и записать в кэш, если не найдено
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="key">Ключ для хранения в кэше</param>
        /// <param name="timestampKey">Ключ для временного отпечатка</param>
        /// <param name="valueAccessor">Функция, возвращающая значение. Вызывается, когда в кэше информация не найдена.</param>
        /// <param name="timeout">Время хранения значения</param>
        /// <returns>Значение</returns>
        T GetOrAdd<T>(string key, string timestampKey, Func<T> valueAccessor, TimeSpan timeout);

        /// <summary>
        /// Обновить временной отпечаток
        /// </summary>
        /// <param name="timestampKey">Ключ для временного отпечатка</param>
        void RefreshTimestamp(string timestampKey);

    }

Контекстный кэш

Контекстный кэш хранит данные в памяти только на текущий запрос (текущий поток исполнения).

Для использования контекстного кэша можно воспользоваться сервисом IContextBoundVariableService, или статическим классом ContextVars.

IContextBoundVariableService

IContextBoundVariableService регистрируется в IoC контейнере и доступен для использования во всех серверных компонентах приложения.

/// <summary>
    /// Абстракный сервис для работы с переменными
    /// </summary>
    public interface IAbstractBoundVariableService
    {

        /// <summary>
        /// Содержится ли значение переменной
        /// </summary>
        /// <param name="name">Имя переменной</param>
        /// <returns>True, если содержится</returns>
        bool Contains(string name);

        /// <summary>
        /// Получить значение переменной. Если не установлено - выдается исключение VariableNotFoundException
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="name">Имя переменной</param>
        /// <returns>Значение переменной</returns>
        T Get<T>(string name);

        /// <summary>
        /// Попытаться получить значение переменной
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="name">Имя переменной</param>
        /// <param name="value">Полученное значение (или значение по умолчанию для типа <typeparamref name="T"/>, если элемент не найден)</param>
        /// <returns>True, если переменная найдена</returns>
        bool TryGetValue<T>(string name, out T value);

        /// <summary>
        /// Установить значение переменной
        /// </summary>
        /// <param name="name">Имя переменной</param>
        /// <param name="value">Значение переменной</param>
        void Set(string name, object value);

        /// <summary>
        /// Удалить значение переменной
        /// </summary>
        /// <param name="key"></param>
        void Remove(string key);
    }

    /// <summary>
    /// Интерфейс сервиса работы со значениями переменных в рамках контекста (например, веб-запроса)
    /// </summary>
    public interface IContextBoundVariableService : IAbstractBoundVariableService
    {
        /// <summary>
        /// Очистить все переменные
        /// </summary>
        void Clear();
    }

ContextVars

ContextVars является статическим классом для более удобной работы с IContextBoundVariableService.

/// <summary>
    /// Статический класс для работы со значениями переменных в рамках контекста (например, веб-запроса)
    /// </summary>
    /// <remarks>
    /// Для работы с ним требуется установить реализующую службу через метод SetImpl
    /// </remarks>
    public static class ContextVars
    {

        /// <summary>
        /// Содержится ли значение переменной
        /// </summary>
        /// <param name="name">Имя переменной</param>
        /// <returns>True, если содержится</returns>
        public static bool Contains(string name);

        /// <summary>
        /// Получить значение переменной. 
        /// Если не установлено - выдается исключение VariableNotFoundException
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="name">Имя переменной</param>
        /// <returns>Значение переменной</returns>
        public static T Get<T>(string name);

        /// <summary>
        /// Попытаться получить значение переменной
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="name">Имя переменной</param>
        /// <param name="value">Полученное значение (или значение по умолчанию для типа <typeparamref name="T"/>, если элемент не найден)</param>
        /// <returns>True, если переменная найдена</returns>
        public static bool TryGetValue<T>(string name, out T value);

        /// <summary>
        /// Получить значение переменной, или установить из функции.
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="name">Имя переменной</param>
        /// <param name="val">Функция для получения значения</param>
        /// <returns>Значение переменной</returns>
        public static T GetOrAdd<T>(string name, Func<T> val);

        /// <summary>
        /// Установить значение переменной
        /// </summary>
        /// <typeparam name="T">Тип значения</typeparam>
        /// <param name="name">Имя переменной</param>
        /// <param name="value">Значение переменной</param>
        public static void Set<T>(string name, T value);

        /// <summary>
        /// Удалить значение переменной
        /// </summary>
        /// <param name="name"></param>
        public static void Remove(string name);

    }

Кэширование возвращаемых значений методов

Атрибут ContextCacheAttribute позволяет кэшировать возвращаемые значения методов, вызываемых у компонентов на время жизни одного HTTP запроса или другого контекста выполнения.

Ссылки на элементы API

Интерфейс ICacheService;

Интерфейс IComplexCacheService;

Интерфейс IMemoryCacheService.