我已经阅读了大量关于MVC应用程序中的页面缓存和部分页面缓存的信息。然而,我想知道你将如何缓存数据。

在我的场景中,我将使用LINQ到实体(实体框架)。在第一次调用GetNames(或任何方法)时,我想从数据库中获取数据。我想将结果保存在缓存中,并在第二次调用时使用缓存版本(如果存在)。

谁能举例说明这将如何工作,这应该在哪里实现(模型?),如果它将工作。

我在传统的ASP中见过这种情况。NET应用程序,通常用于非常静态的数据。


当前回答

扩展@Hrvoje Hudo的回答…

代码:

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;
}

例子

单项缓存(当每个项都基于其ID进行缓存时,因为为该项类型缓存整个目录将过于密集)。

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

缓存所有东西

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

何必TId

第二个帮助器特别好,因为大多数数据键都不是复合的。如果经常使用复合键,可以添加其他方法。通过这种方式,您可以避免进行各种字符串连接或字符串。格式以获取要传递给缓存助手的键。它还使传递数据访问方法更容易,因为您不必将ID传递到包装器方法中……对于大多数用例来说,整个过程变得非常简洁和一致。

其他回答

我要说的是,如果您发现以前的解决方案非常复杂,那么在这个持久化数据问题上实现Singleton可以是一个解决方案

 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

下面是对Hrvoje Hudo的回答的改进。这个实现有几个关键的改进:

缓存键是根据更新数据的函数和传入的指定依赖关系的对象自动创建的 为任何缓存持续时间传递时间跨度 使用锁来保证线程安全

注意,这依赖于Newtonsoft。Json来序列化dependsOn对象,但是可以很容易地将其替换为任何其他序列化方法。

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;
    }
}

用法:

var order = _cache.GetOrSet(
    () => _session.Set<Order>().SingleOrDefault(o => o.Id == orderId)
    , new { id = orderId }
    , new TimeSpan(0, 10, 0)
);

适用于。net 4.5+框架

添加reference: System.Runtime.Caching

添加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);
}

在. net Framework 3.5和更早的版本中,ASP。NET在System.Web.Caching命名空间中提供了内存中的缓存实现。在以前版本的. net Framework中,缓存仅在系统中可用。Web命名空间,因此需要依赖于ASP。网类。在. net Framework 4中,System.Runtime.Caching命名空间包含为Web和非Web应用程序设计的api。

更多信息:

https://msdn.microsoft.com/en-us/library/dd997357 (v = vs.110) . aspx https://learn.microsoft.com/en-us/dotnet/framework/performance/caching-in-net-framework-applications

HttpContext.Current.Cache.Insert("subjectlist", subjectlist);

扩展@Hrvoje Hudo的回答…

代码:

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;
}

例子

单项缓存(当每个项都基于其ID进行缓存时,因为为该项类型缓存整个目录将过于密集)。

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

缓存所有东西

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

何必TId

第二个帮助器特别好,因为大多数数据键都不是复合的。如果经常使用复合键,可以添加其他方法。通过这种方式,您可以避免进行各种字符串连接或字符串。格式以获取要传递给缓存助手的键。它还使传递数据访问方法更容易,因为您不必将ID传递到包装器方法中……对于大多数用例来说,整个过程变得非常简洁和一致。