Как я могу кэшировать объекты в ASP.NET MVC?

51
задан George Stocker 2 November 2011 в 05:47
поделиться

6 ответов

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

мне нравится следующая "попытка, добираются от, кэшируют/создают и хранят" шаблон (c#-like псевдокод):

public static class CacheExtensions
{
  public static T GetOrStore<T>(this Cache cache, string key, Func<T> generator)
  {
    var result = cache[key];
    if(result == null)
    {
      result = generator();
      cache[key] = result;
    }
    return (T)result;
  }
}

Вы использовали бы это как так:

var user = HttpRuntime
              .Cache
              .GetOrStore<User>(
                 $"User{_userId}", 
                 () => Repository.GetUser(_userId));

можно адаптировать этот шаблон к Сессии, ViewState (тьфу) или любой другой механизм кэширования. Можно также расширить ControllerContext. HttpContext (то, которое я думаю, является одной из оберток в Системе. Сеть. Расширения), или создают новый класс, чтобы сделать это с некоторой комнатой для насмешки кэша.

71
ответ дан 7 November 2019 в 09:48
поделиться

Если Вы хотите кэшируемый для длины запроса, помещаете это в Ваш базовый класс контроллера:

public User User {
    get {
        User _user = ControllerContext.HttpContext.Items["user"] as User;

        if (_user == null) {
            _user = _repository.Get<User>(id);
            ControllerContext.HttpContext.Items["user"] = _user;
        }

        return _user;
    }
}

, Если Вы хотите кэшироваться для дольше, используйте замену вызов ControllerContext с одним для Кэширования []. Если Вы действительно примете решение использовать объект Кэша кэшироваться дольше, необходимо будет использовать уникальный ключ кэша, поскольку он будет совместно использован через запросы/пользователей.

6
ответ дан John Sheehan 7 November 2019 в 09:48
поделиться

Если Вам не нужны определенные функции аннулирования кэширования ASP.NET, статические поля довольно хороши, легки и просты в использовании. Однако, как только Вам были нужны расширенные функции, можно переключиться на ASP.NET Cache объект для устройства хранения данных.

подход, который я использую, должен создать свойство и private поле. Если поле будет null, свойство заполнит его и возвратит его. Я также обеспечиваю InvalidateCache метод, который вручную устанавливает поле на null. Преимущество этого подхода это, что механизм кэширования инкапсулируется в свойстве и можно переключиться на другой подход, если Вы хотите.

2
ответ дан Mehrdad Afshari 7 November 2019 в 09:48
поделиться

Мне нравится скрывать то, что данные кэшируются в репозитории. Можно получить доступ к кэшу через HttpContext. Текущий. Свойство Cache и хранилище информация о Пользователе с помощью "Пользователя" +id. ToString () как ключ.

Это означает, что весь доступ к Пользовательским данным из репозитория будет использовать кэшированные данные при наличии и не требует никаких изменений кода в модели, контроллере или представлении.

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

3
ответ дан Matthew 7 November 2019 в 09:48
поделиться

Я взял ответ Уилла и изменил его, чтобы сделать класс CacheExtensions статическим и предложить небольшое изменение, чтобы иметь дело с возможностью Func является null :

public static class CacheExtensions
{

    private static object sync = new object();
    public const int DefaultCacheExpiration = 20;

    /// <summary>
    /// Allows Caching of typed data
    /// </summary>
    /// <example><![CDATA[
    /// var user = HttpRuntime
    ///   .Cache
    ///   .GetOrStore<User>(
    ///      string.Format("User{0}", _userId), 
    ///      () => Repository.GetUser(_userId));
    ///
    /// ]]></example>
    /// <typeparam name="T"></typeparam>
    /// <param name="cache">calling object</param>
    /// <param name="key">Cache key</param>
    /// <param name="generator">Func that returns the object to store in cache</param>
    /// <returns></returns>
    /// <remarks>Uses a default cache expiration period as defined in <see cref="CacheExtensions.DefaultCacheExpiration"/></remarks>
    public static T GetOrStore<T>( this Cache cache, string key, Func<T> generator ) {
        return cache.GetOrStore( key, (cache[key] == null && generator != null) ? generator() : default( T ), DefaultCacheExpiration );
    }


    /// <summary>
    /// Allows Caching of typed data
    /// </summary>
    /// <example><![CDATA[
    /// var user = HttpRuntime
    ///   .Cache
    ///   .GetOrStore<User>(
    ///      string.Format("User{0}", _userId), 
    ///      () => Repository.GetUser(_userId));
    ///
    /// ]]></example>
    /// <typeparam name="T"></typeparam>
    /// <param name="cache">calling object</param>
    /// <param name="key">Cache key</param>
    /// <param name="generator">Func that returns the object to store in cache</param>
    /// <param name="expireInMinutes">Time to expire cache in minutes</param>
    /// <returns></returns>
    public static T GetOrStore<T>( this Cache cache, string key, Func<T> generator, double expireInMinutes ) {
        return cache.GetOrStore( key,  (cache[key] == null && generator != null) ? generator() : default( T ), expireInMinutes );
    }


    /// <summary>
    /// Allows Caching of typed data
    /// </summary>
    /// <example><![CDATA[
    /// var user = HttpRuntime
    ///   .Cache
    ///   .GetOrStore<User>(
    ///      string.Format("User{0}", _userId),_userId));
    ///
    /// ]]></example>
    /// <typeparam name="T"></typeparam>
    /// <param name="cache">calling object</param>
    /// <param name="key">Cache key</param>
    /// <param name="obj">Object to store in cache</param>
    /// <returns></returns>
    /// <remarks>Uses a default cache expiration period as defined in <see cref="CacheExtensions.DefaultCacheExpiration"/></remarks>
    public static T GetOrStore<T>( this Cache cache, string key, T obj ) {
        return cache.GetOrStore( key, obj, DefaultCacheExpiration );
    }

    /// <summary>
    /// Allows Caching of typed data
    /// </summary>
    /// <example><![CDATA[
    /// var user = HttpRuntime
    ///   .Cache
    ///   .GetOrStore<User>(
    ///      string.Format("User{0}", _userId), 
    ///      () => Repository.GetUser(_userId));
    ///
    /// ]]></example>
    /// <typeparam name="T"></typeparam>
    /// <param name="cache">calling object</param>
    /// <param name="key">Cache key</param>
    /// <param name="obj">Object to store in cache</param>
    /// <param name="expireInMinutes">Time to expire cache in minutes</param>
    /// <returns></returns>
    public static T GetOrStore<T>( this Cache cache, string key, T obj, double expireInMinutes ) {
        var result = cache[key];

        if ( result == null ) {

            lock ( sync ) {
                result = cache[key];
                if ( result == null ) {
                    result = obj != null ? obj : default( T );
                    cache.Insert( key, result, null, DateTime.Now.AddMinutes( expireInMinutes ), Cache.NoSlidingExpiration );
                }
            }
        }

        return (T)result;

    }

}

Я бы также подумал о том, чтобы сделать еще один шаг, чтобы реализовать тестируемое решение для сеанса, которое расширяет абстрактный класс System.Web.HttpSessionStateBase.

public static class SessionExtension
{
    /// <summary>
    /// 
    /// </summary>
    /// <example><![CDATA[
    /// var user = HttpContext
    ///   .Session
    ///   .GetOrStore<User>(
    ///      string.Format("User{0}", _userId), 
    ///      () => Repository.GetUser(_userId));
    ///
    /// ]]></example>
    /// <typeparam name="T"></typeparam>
    /// <param name="cache"></param>
    /// <param name="key"></param>
    /// <param name="generator"></param>
    /// <returns></returns>
    public static T GetOrStore<T>( this HttpSessionStateBase session, string name, Func<T> generator ) {

        var result = session[name];
        if ( result != null )
            return (T)result;

        result = generator != null ? generator() : default( T );
        session.Add( name, result );
        return (T)result;
    }

}
59
ответ дан 7 November 2019 в 09:48
поделиться

@njappboy: Хорошая реализация. Я бы только отложил вызов Generator () до последнего ответственного момента. таким образом, вы также можете кэшировать вызовы методов.

/// <summary>
/// Allows Caching of typed data
/// </summary>
/// <example><![CDATA[
/// var user = HttpRuntime
///   .Cache
///   .GetOrStore<User>(
///      string.Format("User{0}", _userId), 
///      () => Repository.GetUser(_userId));
///
/// ]]></example>
/// <typeparam name="T"></typeparam>
/// <param name="Cache">calling object</param>
/// <param name="Key">Cache key</param>
/// <param name="Generator">Func that returns the object to store in cache</param>
/// <returns></returns>
/// <remarks>Uses a default cache expiration period as defined in <see cref="CacheExtensions.DefaultCacheExpiration"/></remarks>
public static T GetOrStore<T>( this Cache Cache, string Key, Func<T> Generator )
{
    return Cache.GetOrStore( Key, Generator, DefaultCacheExpiration );
}

/// <summary>
/// Allows Caching of typed data
/// </summary>
/// <example><![CDATA[
/// var user = HttpRuntime
///   .Cache
///   .GetOrStore<User>(
///      string.Format("User{0}", _userId), 
///      () => Repository.GetUser(_userId));
///
/// ]]></example>
/// <typeparam name="T"></typeparam>
/// <param name="Cache">calling object</param>
/// <param name="Key">Cache key</param>
/// <param name="Generator">Func that returns the object to store in cache</param>
/// <param name="ExpireInMinutes">Time to expire cache in minutes</param>
/// <returns></returns>
public static T GetOrStore<T>( this Cache Cache, string Key, Func<T> Generator, double ExpireInMinutes )
{
    var Result = Cache [ Key ];

    if( Result == null )
    {
        lock( Sync )
        {
            if( Result == null )
            {
                Result = Generator( );
                Cache.Insert( Key, Result, null, DateTime.Now.AddMinutes( ExpireInMinutes ), Cache.NoSlidingExpiration );
            }
        }
    }

    return ( T ) Result;
}
3
ответ дан 7 November 2019 в 09:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: