Comment mettre en cache des données dans une application MVC

J’ai lu beaucoup d’informations sur la mise en cache des pages et la mise en cache partielle des pages dans une application MVC. Cependant, j’aimerais savoir comment vous mettrez vos données en cache.

Dans mon scénario, j’utiliserai LINQ to Entities (framework d’entités). Lors du premier appel à GetNames (ou quelle que soit la méthode), je souhaite récupérer les données de la firebase database. Je veux enregistrer les résultats dans le cache et sur le deuxième appel pour utiliser la version mise en cache si elle existe.

Quelqu’un peut-il montrer comment cela fonctionnerait, où cela devrait être implémenté (modèle?) Et si cela fonctionnerait.

Je l’ai vu dans les applications ASP.NET traditionnelles, généralement pour des données très statiques.

Référencez la DLL System.Web dans votre modèle et utilisez System.Web.Caching.Cache

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

Un peu simplifié mais je suppose que ça marcherait. Ce n’est pas spécifique à MVC et j’ai toujours utilisé cette méthode pour mettre en cache les données.

Voici une classe / service d’assistance de cache simple et efficace que j’utilise:

 using System.Runtime.Caching; public class InMemoryCache: ICacheService { public T GetOrSet(ssortingng cacheKey, Func 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(ssortingng cacheKey, Func getItemCallback) where T : class; } 

Usage:

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

Le fournisseur de cache vérifiera s’il y a quelque chose sous le nom de “cache id” dans le cache et s’il n’y en a pas, il appellera une méthode de délégué pour extraire les données et les stocker dans le cache.

Exemple:

 var products=cacheService.GetOrSet("catalog.products", ()=>productRepository.GetAll()) 

Je fais référence au poste de TT et suggère l’approche suivante:

Référencez la DLL System.Web dans votre modèle et utilisez System.Web.Caching.Cache

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

Vous ne devez pas renvoyer une valeur relue depuis le cache, car vous ne saurez jamais si, à ce moment précis, il se trouve toujours dans le cache. Même si vous l’avez déjà inséré dans la déclaration, il est peut-être déjà parti ou n’a jamais été ajouté au cache – vous ne savez tout simplement pas.

Vous ajoutez donc les données lues à partir de la firebase database et les renvoyez directement, sans les relire depuis le cache.

Steve Smith a fait deux excellents articles de blog montrant comment utiliser son modèle CachedRepository dans ASP.NET MVC. Il utilise efficacement le modèle de référentiel et vous permet d’obtenir la mise en cache sans avoir à modifier votre code existant.

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

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

Dans ces deux articles, il vous montre comment configurer ce modèle et explique également pourquoi il est utile. En utilisant ce modèle, vous obtenez la mise en cache sans que votre code existant ne détecte la logique de mise en cache. Essentiellement, vous utilisez le référentiel en cache comme s’il s’agissait d’un autre référentiel.

Pour le framework .NET 4.5+

append une référence: System.Runtime.Caching

Ajouter une instruction using System.Runtime.Caching; : using System.Runtime.Caching;

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

Dans le .NET Framework 3.5 et les versions antérieures, ASP.NET fournissait une implémentation de cache en mémoire dans l’espace de noms System.Web.Caching. Dans les versions précédentes du .NET Framework, la mise en cache n’était disponible que dans l’espace de noms System.Web et nécessitait donc une dépendance sur les classes ASP.NET. Dans .NET Framework 4, l’espace de noms System.Runtime.Caching contient des API conçues pour les applications Web et non Web.

Plus d’informations:

La mise en cache AppFabric est dissortingbuée et une technique de mise en cache en mémoire qui stocke les données dans des paires clé-valeur à l’aide de la mémoire physique sur plusieurs serveurs. AppFabric fournit des améliorations de performances et d’évolutivité pour les applications .NET Framework. Concepts et Architecture

Extension de la réponse de @Hrvoje Hudo …

Code:

 using System; using System.Runtime.Caching; public class InMemoryCache : ICacheService { public TValue Get(ssortingng cacheKey, int durationInMinutes, Func 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(ssortingng cacheKeyFormat, TId id, int durationInMinutes, Func getItemCallback) where TValue : class { ssortingng cacheKey = ssortingng.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(ssortingng cacheKey, Func getItemCallback) where TValue : class; TValue Get(ssortingng cacheKeyFormat, TId id, Func getItemCallback) where TValue : class; } 

Exemples

Mise en cache d’un seul élément (lorsque chaque élément est mis en cache en fonction de son ID car la mise en cache du catalogue entier pour le type d’élément est trop intensive).

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

Mettre tout en cache

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

Pourquoi TId

Le second assistant est particulièrement intéressant car la plupart des clés de données ne sont pas composées. Des méthodes supplémentaires pourraient être ajoutées si vous utilisez souvent des clés composites. De cette façon, vous évitez de faire toutes sortes de concaténation de chaîne ou de chaîne.Formats pour que la clé soit transmise à l’assistant de cache. Cela facilite également le passage de la méthode d’access aux données car vous n’avez pas à passer l’ID dans la méthode wrapper … le tout devient très concis et cohérent pour la majorité des cas d’utilisation.

Voici une amélioration de la réponse de Hrvoje Hudo. Cette implémentation comporte quelques améliorations clés:

  • Les clés de cache sont créées automatiquement en fonction de la fonction de mise à jour des données et de l’object transmis qui spécifie les dépendances.
  • Passer l’intervalle de temps pour toute durée de cache
  • Utilise un verrou pour la sécurité des fils

Notez que ceci a une dépendance sur Newtonsoft.Json pour sérialiser l’object Celle-ci, mais cela peut être facilement échangé pour toute autre méthode de sérialisation.

ICache.cs

 public interface ICache { T GetOrSet(Func 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(Func getItemCallback, object dependsOn, TimeSpan duration) where T : class { ssortingng 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 ssortingng GetCacheKey(Func itemCallback, object dependsOn) where T: class { var serializedDependants = JsonConvert.SerializeObject(dependsOn); var methodType = itemCallback.GetType(); return methodType.FullName + serializedDependants; } } 

Usage:

 var order = _cache.GetOrSet( () => _session.Set().SingleOrDefault(o => o.Id == orderId) , new { id = orderId } , new TimeSpan(0, 10, 0) ); 
 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 = SsortingngUtils.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(Ssortingng Key) { if (Key == null || !allowCache) { return null; } try { Ssortingng Key_ = Key; if (cache.Contains(Key_)) { return (IEnumerable)cache.Get(Key_); } else { return null; } } catch (Exception) { return null; } } public void ClearCache(ssortingng key) { AddCache(key, null); } public bool AddCache(Ssortingng Key, IEnumerable data, CacheItemPolicy cacheItemPolicy = null) { if (!allowCache) return true; try { if (Key == null) { return false; } if (cacheItemPolicy == null) { cacheItemPolicy = defaultCacheItemPolicy; } Ssortingng Key_ = Key; lock (Key_) { return cache.Add(Key_, data, cacheItemPolicy); } } catch (Exception) { return false; } } private void CachedItemRemovedCallback(CacheEntryRemovedArguments arguments) { Ssortingng strLog = Ssortingng.Concat("Reason: ", arguments.RemovedReason.ToSsortingng(), " | Key-Name: ", arguments.CacheItem.Key, " | Value-Object: ", arguments.CacheItem.Value.ToSsortingng()); LogManager.Instance.Info(strLog); } } 

J’utilise deux classes. Le premier object de cache:

 public class Cacher where TValue : class { #region Properties private Func _init; public ssortingng 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(ssortingng key, Func init) { Key = key; _init = init; } #endregion #region Methods public void Refresh() { HttpRuntime.Cache.Remove(Key); } #endregion } 

La deuxième est la liste des objects de cache:

 public static class Caches { static Caches() { Languages = new Cacher>("Languages", () => { using (var context = new WordsContext()) { return context.Languages.ToList(); } }); } public static Cacher> Languages { get; private set; } } 

Je dirai que l’implémentation de Singleton sur ce problème persistant de données peut être une solution à ce problème au cas où vous trouveriez des solutions beaucoup plus complexes

  public class GPDataDictionary { private Dictionary configDictionary = new Dictionary(); ///  /// Configuration values dictionary ///  public Dictionary 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 
 HttpContext.Current.Cache.Insert("subjectlist", subjectlist); 

Je l’ai utilisé de cette façon et cela fonctionne pour moi. https://msdn.microsoft.com/en-us/library/system.web.caching.cache.add(v=vs.110).aspx informations sur les parameters de system.web.caching.cache.add.

 public ssortingng GetInfo() { ssortingng name = ssortingng.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 ssortingng; } return name; } 

Vous pouvez également essayer d’utiliser la mise en cache intégrée à ASP MVC:

Ajoutez l’atsortingbut suivant à la méthode de contrôleur que vous souhaitez mettre en cache:

 [OutputCache(Duration=10)] 

Dans ce cas, ActionResult sera mis en cache pendant 10 secondes.

Plus à ce sujet ici