Jak buforować dane w aplikacji MVC

Przeczytałem wiele informacji o buforowaniu stron i buforowaniu części w aplikacji MVC. Chciałbym jednak wiedzieć, jak można buforować dane.

W moim scenariuszu będę używał LINQ to Entities (entity framework). Przy pierwszym wywołaniu GetNames (czy jakakolwiek jest metoda) Chcę pobrać dane z bazy danych. Chcę zapisać wyniki w pamięci podręcznej i na drugim wywołaniu, aby użyć wersji buforowanej, jeśli istnieje.

Czy ktoś może pokazać przykład jak to pracy, gdzie to powinno być realizowane (model?) i gdyby to zadziałało.

Widziałem to w tradycyjnym ASP.NET aplikacje, zazwyczaj dla bardzo statycznych danych.

Author: Coolcoder, 2008-12-05

14 answers

Odwołaj się do systemu.Web dll w twoim modelu i systemie użytkowania.Www.Buforowanie.Cache

    public string[] GetNames()
    {
      string[] names = Cache["names"] as string[];
      if(names == null) //not in cache
      {
        names = DB.GetNames();
        Cache["names"] = names;
      }
      return names;
    }

Trochę uproszczone, ale myślę, że to zadziała. Nie jest to specyficzne dla MVC i zawsze używałem tej metody do buforowania danych.

 72
Author: terjetyl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-20 13:54:30

Oto miła i prosta klasa / usługa wspomagająca pamięć podręczną, której używam:

using System.Runtime.Caching;  

public class InMemoryCache: ICacheService
{
    public T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class
    {
        T item = MemoryCache.Default.Get(cacheKey) as T;
        if (item == null)
        {
            item = getItemCallback();
            MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddMinutes(10));
        }
        return item;
    }
}

interface ICacheService
{
    T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class;
}

Użycie:

cacheProvider.GetOrSet("cache key", (delegate method if cache is empty));

Dostawca pamięci podręcznej sprawdzi, czy w pamięci podręcznej jest coś o nazwie "Cache id", a jeśli nie ma, wywoła metodę delegata do pobierania danych i przechowywania ich w pamięci podręcznej.

Przykład:

var products=cacheService.GetOrSet("catalog.products", ()=>productRepository.GetAll())
 366
Author: Hrvoje Hudo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-21 15:08:23

Odnoszę się do posta TT i sugeruję następujące podejście:

Odwołaj się do systemu.Web dll w twoim modelu i systemie użytkowania.Www.Buforowanie.Cache

public string[] GetNames()
{ 
    var noms = Cache["names"];
    if(noms == null) 
    {    
        noms = DB.GetNames();
        Cache["names"] = noms; 
    }

    return ((string[])noms);
}

Nie powinieneś zwracać wartości ponownie odczytanej z pamięci podręcznej, ponieważ nigdy nie dowiesz się, czy w danym momencie nadal jest w pamięci podręcznej. Nawet jeśli wstawiłeś go wcześniej do instrukcji, może już go nie ma lub nigdy nie został dodany do pamięci podręcznej - po prostu nie wiesz.

Więc dodajesz dane odczytane z bazy danych i zwraca ją bezpośrednio, a nie ponownie odczytuje z pamięci podręcznej.

 41
Author: Oli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-03 12:55:59

Dla. NET 4.5+ framework

Dodaj referencję: System.Runtime.Caching

Dodaj za pomocą instrukcji: using System.Runtime.Caching;

public string[] GetNames()
{ 
    var noms = System.Runtime.Caching.MemoryCache.Default["names"];
    if(noms == null) 
    {    
        noms = DB.GetNames();
        System.Runtime.Caching.MemoryCache.Default["names"] = noms; 
    }

    return ((string[])noms);
}

W. NET Framework 3.5 i wcześniejszych wersjach, ASP.NET pod warunkiem implementacji pamięci podręcznej w systemie.Www.Buforowanie przestrzeni nazw. W poprzednich wersjach. NET Framework buforowanie było dostępne tylko w systemie.Web namespace i dlatego wymagał zależności od ASP.NET klasy. W. NET Framework 4, System.Runtime.Buforowanie przestrzeni nazw zawiera interfejsy API które są przeznaczone zarówno dla aplikacji internetowych, jak i innych.

Więcej informacji:

 27
Author: juFo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-14 07:19:08

Steve Smith zrobił dwa świetne posty na blogu, które pokazują, jak używać jego wzorca CachedRepository w ASP.NET MVC. Efektywnie wykorzystuje wzorzec repozytorium i pozwala uzyskać buforowanie bez konieczności zmiany istniejącego kodu.

Http://ardalis.com/Introducing-the-CachedRepository-Pattern

Http://ardalis.com/building-a-cachedrepository-via-strategy-pattern

W tych dwóch postach pokazuje, jak ustawić ten wzór, a także wyjaśnia, dlaczego to jest przydatne. Za pomocą tego wzorca można uzyskać buforowanie bez istniejącego kodu widząc żadnej logiki buforowania. Zasadniczo używasz buforowanego repozytorium tak, jakby było ono jakimkolwiek innym repozytorium.

 24
Author: Brendan Enrick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-29 09:28:51

Pamięć podręczna AppFabric jest dystrybuowana i technika buforowania w pamięci, która przechowuje dane w parach klucz-wartość przy użyciu pamięci fizycznej na wielu serwerach. AppFabric zapewnia ulepszenia wydajności i skalowalności dla aplikacji. NET Framework. koncepcje i architektura

 4
Author: Arun Duth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-16 15:00:56

Rozszerzenie odpowiedzi @ Hrvoje Hudo...

Kod:

using System;
using System.Runtime.Caching;

public class InMemoryCache : ICacheService
{
    public TValue Get<TValue>(string cacheKey, int durationInMinutes, Func<TValue> getItemCallback) where TValue : class
    {
        TValue item = MemoryCache.Default.Get(cacheKey) as TValue;
        if (item == null)
        {
            item = getItemCallback();
            MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddMinutes(durationInMinutes));
        }
        return item;
    }

    public TValue Get<TValue, TId>(string cacheKeyFormat, TId id, int durationInMinutes, Func<TId, TValue> getItemCallback) where TValue : class
    {
        string cacheKey = string.Format(cacheKeyFormat, id);
        TValue item = MemoryCache.Default.Get(cacheKey) as TValue;
        if (item == null)
        {
            item = getItemCallback(id);
            MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddMinutes(durationInMinutes));
        }
        return item;
    }
}

interface ICacheService
{
    TValue Get<TValue>(string cacheKey, Func<TValue> getItemCallback) where TValue : class;
    TValue Get<TValue, TId>(string cacheKeyFormat, TId id, Func<TId, TValue> getItemCallback) where TValue : class;
}

Przykłady

Buforowanie pojedynczego elementu (gdy każdy element jest buforowany na podstawie jego ID, ponieważ buforowanie całego katalogu dla typu elementu byłoby zbyt intensywne).

Product product = cache.Get("product_{0}", productId, 10, productData.getProductById);

Buforowanie wszystkiego

IEnumerable<Categories> categories = cache.Get("categories", 20, categoryData.getCategories);

Dlaczego TId

Drugi helper jest szczególnie miły, ponieważ większość kluczy danych nie jest złożona. Jeśli często używasz kluczy złożonych, można dodać dodatkowe metody. W w ten sposób unikasz wykonywania wszelkiego rodzaju konkatenacji łańcuchów lub łańcuchów.Formaty, aby uzyskać klucz do przekazania do pomocnika pamięci podręcznej. Ułatwia to również przekazywanie metody dostępu do danych, ponieważ nie trzeba przekazywać ID do metody wrapper... całość staje się bardzo zwięzła i konsekwentna w większości przypadków użycia.

 3
Author: smdrager,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-08 17:52:17

Oto ulepszenie odpowiedzi Hrvoje Hudo. Ta implementacja ma kilka kluczowych ulepszeń:

  • klucze pamięci podręcznej są tworzone automatycznie na podstawie funkcji do aktualizacji danych i przekazywanego obiektu, który określa zależności
  • przechodzić w czasie dla dowolnego czasu trwania pamięci podręcznej
  • używa zamka do zabezpieczenia gwintu

Zauważ, że jest to zależne od Newtonsoft.JSON do serializacji obiektu dependsOn, ale można go łatwo zamienić na dowolny inny metoda serializacji.

ICache.cs
public interface ICache
{
    T GetOrSet<T>(Func<T> getItemCallback, object dependsOn, TimeSpan duration) where T : class;
}

InMemoryCache.cs

using System;
using System.Reflection;
using System.Runtime.Caching;
using Newtonsoft.Json;

public class InMemoryCache : ICache
{
    private static readonly object CacheLockObject = new object();

    public T GetOrSet<T>(Func<T> getItemCallback, object dependsOn, TimeSpan duration) where T : class
    {
        string cacheKey = GetCacheKey(getItemCallback, dependsOn);
        T item = MemoryCache.Default.Get(cacheKey) as T;
        if (item == null)
        {
            lock (CacheLockObject)
            {
                item = getItemCallback();
                MemoryCache.Default.Add(cacheKey, item, DateTime.Now.Add(duration));
            }
        }
        return item;
    }

    private string GetCacheKey<T>(Func<T> itemCallback, object dependsOn) where T: class
    {
        var serializedDependants = JsonConvert.SerializeObject(dependsOn);
        var methodType = itemCallback.GetType();
        return methodType.FullName + serializedDependants;
    }
}

Użycie:

var order = _cache.GetOrSet(
    () => _session.Set<Order>().SingleOrDefault(o => o.Id == orderId)
    , new { id = orderId }
    , new TimeSpan(0, 10, 0)
);
 3
Author: DShook,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-14 19:03:53
public sealed class CacheManager
{
    private static volatile CacheManager instance;
    private static object syncRoot = new Object();
    private ObjectCache cache = null;
    private CacheItemPolicy defaultCacheItemPolicy = null;

    private CacheEntryRemovedCallback callback = null;
    private bool allowCache = true;

    private CacheManager()
    {
        cache = MemoryCache.Default;
        callback = new CacheEntryRemovedCallback(this.CachedItemRemovedCallback);

        defaultCacheItemPolicy = new CacheItemPolicy();
        defaultCacheItemPolicy.AbsoluteExpiration = DateTime.Now.AddHours(1.0);
        defaultCacheItemPolicy.RemovedCallback = callback;
        allowCache = StringUtils.Str2Bool(ConfigurationManager.AppSettings["AllowCache"]); ;
    }
    public static CacheManager Instance
    {
        get
        {
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                    {
                        instance = new CacheManager();
                    }
                }
            }

            return instance;
        }
    }

    public IEnumerable GetCache(String Key)
    {
        if (Key == null || !allowCache)
        {
            return null;
        }

        try
        {
            String Key_ = Key;
            if (cache.Contains(Key_))
            {
                return (IEnumerable)cache.Get(Key_);
            }
            else
            {
                return null;
            }
        }
        catch (Exception)
        {
            return null;
        }
    }

    public void ClearCache(string key)
    {
        AddCache(key, null);
    }

    public bool AddCache(String Key, IEnumerable data, CacheItemPolicy cacheItemPolicy = null)
    {
        if (!allowCache) return true;
        try
        {
            if (Key == null)
            {
                return false;
            }

            if (cacheItemPolicy == null)
            {
                cacheItemPolicy = defaultCacheItemPolicy;
            }

            String Key_ = Key;

            lock (Key_)
            {
                return cache.Add(Key_, data, cacheItemPolicy);
            }
        }
        catch (Exception)
        {
            return false;
        }
    }

    private void CachedItemRemovedCallback(CacheEntryRemovedArguments arguments)
    {
        String strLog = String.Concat("Reason: ", arguments.RemovedReason.ToString(), " | Key-Name: ", arguments.CacheItem.Key, " | Value-Object: ", arguments.CacheItem.Value.ToString());
        LogManager.Instance.Info(strLog);
    }
}
 3
Author: Chau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-01 10:53:51

Używam dwóch klas. Pierwszy obiekt Cache core:

public class Cacher<TValue>
    where TValue : class
{
    #region Properties
    private Func<TValue> _init;
    public string Key { get; private set; }
    public TValue Value
    {
        get
        {
            var item = HttpRuntime.Cache.Get(Key) as TValue;
            if (item == null)
            {
                item = _init();
                HttpContext.Current.Cache.Insert(Key, item);
            }
            return item;
        }
    }
    #endregion

    #region Constructor
    public Cacher(string key, Func<TValue> init)
    {
        Key = key;
        _init = init;
    }
    #endregion

    #region Methods
    public void Refresh()
    {
        HttpRuntime.Cache.Remove(Key);
    }
    #endregion
}

Druga to lista obiektów pamięci podręcznej:

public static class Caches
{
    static Caches()
    {
        Languages = new Cacher<IEnumerable<Language>>("Languages", () =>
                                                          {
                                                              using (var context = new WordsContext())
                                                              {
                                                                  return context.Languages.ToList();
                                                              }
                                                          });
    }
    public static Cacher<IEnumerable<Language>> Languages { get; private set; }
}
 1
Author: Berezh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-27 13:32:27

Powiem, że implementacja Singletona w tym problemie z utrzymującymi się danymi może być rozwiązaniem w tej sprawie, jeśli znajdziesz poprzednie rozwiązania znacznie skomplikowane

 public class GPDataDictionary
{
    private Dictionary<string, object> configDictionary = new Dictionary<string, object>();

    /// <summary>
    /// Configuration values dictionary
    /// </summary>
    public Dictionary<string, object> ConfigDictionary
    {
        get { return configDictionary; }
    }

    private static GPDataDictionary instance;
    public static GPDataDictionary Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new GPDataDictionary();
            }
            return instance;
        }
    }

    // private constructor
    private GPDataDictionary() { }

}  // singleton
 0
Author: GeraGamo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-05 04:55:25
HttpContext.Current.Cache.Insert("subjectlist", subjectlist);
 0
Author: Md. Akhtar Uzzaman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-24 18:11:19

Użyłem go w ten sposób i działa na mnie. https://msdn.microsoft.com/en-us/library/system.web.caching.cache.add (v=vs.110). aspx parametry info dla systemu.www.buforowanie.cache.add.

public string GetInfo()
{
     string name = string.Empty;
     if(System.Web.HttpContext.Current.Cache["KeyName"] == null)
     {
         name = GetNameMethod();
         System.Web.HttpContext.Current.Cache.Add("KeyName", name, null, DateTime.Noew.AddMinutes(5), Cache.NoSlidingExpiration, CacheitemPriority.AboveNormal, null);
     }
     else
     {
         name = System.Web.HttpContext.Current.Cache["KeyName"] as string;
     }

      return name;

}
 0
Author: user3776645,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 21:17:54

Możesz również spróbować użyć buforowania wbudowanego w ASP MVC:

Dodaj następujący atrybut do metody kontrolera, którą chcesz buforować:

[OutputCache(Duration=10)]

W tym przypadku wynik działania będzie buforowany przez 10 sekund.

Więcej na ten temat tutaj

 -8
Author: qui,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-09 17:12:01