在我的场景中,我将使用LINQ to Entities(实体框架) . 在第一次调用GetNames(或任何方法)时,我想从数据库中获取数据 . 我想将结果保存在缓存中,并在第二次调用时使用缓存版本(如果存在) .
任何人都可以展示一个如何工作的例子,应该在哪里实现(模型?)以及它是否可行 .
我已经在传统的ASP.NET应用程序中看到了这一点,通常用于非常静态的数据 .
14 回答
72
在模型中引用System.Web dll并使用System.Web.Caching.Cache
public string[] GetNames()
{
string[] names = Cache["names"] as string[];
if(names == null) //not in cache
{
names = DB.GetNames();
Cache["names"] = names;
}
return names;
}
有点简化,但我想这会奏效 . 这不是MVC特定的,我一直使用这种方法来缓存数据 .
371
这是我使用的一个很好的简单缓存助手类/服务:
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;
}
用法:
cacheProvider.GetOrSet("cache key", (delegate method if cache is empty));
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)
);
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
}
第二个是缓存列表对象:
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; }
}
14 回答
在模型中引用System.Web dll并使用System.Web.Caching.Cache
有点简化,但我想这会奏效 . 这不是MVC特定的,我一直使用这种方法来缓存数据 .
这是我使用的一个很好的简单缓存助手类/服务:
用法:
缓存提供程序将检查缓存中是否存在名称为“cache id”的内容,如果没有,它将调用委托方法来获取数据并将其存储在缓存中 .
示例:
我指的是TT的帖子,并建议采用以下方法:
Reference the System.Web dll in your model and use System.Web.Caching.Cache
您不应该返回从缓存中重新读取的值,因为您永远不会知道在该特定时刻它是否仍在缓存中 . 即使你之前在声明中插入它,它可能已经消失或者从未被添加到缓存中 - 你只是不知道 .
因此,您添加从数据库读取的数据并直接返回,而不是从缓存中重新读取 .
对于.NET 4.5框架
添加引用:
System.Runtime.Caching
添加使用声明:
using System.Runtime.Caching;
更多信息:
https://msdn.microsoft.com/en-us/library/dd997357(v=vs.110).aspx
https://docs.microsoft.com/en-us/dotnet/framework/performance/caching-in-net-framework-applications
史蒂夫史密斯做了两篇很棒的博客文章,演示了如何在ASP.NET MVC中使用他的CachedRepository模式 . 它有效地使用存储库模式,允许您在不必更改现有代码的情况下获得缓存 .
http://ardalis.com/Introducing-the-CachedRepository-Pattern
http://ardalis.com/building-a-cachedrepository-via-strategy-pattern
在这两篇文章中,他向您展示了如何设置此模式,并解释了它为何有用 . 通过使用此模式,您可以获得缓存,而无需现有代码查看任何缓存逻辑 . 实际上,您使用缓存的存储库就像它是任何其他存储库一样 .
AppFabric Caching 是一种分布式内存缓存技术,它使用跨多个服务器的物理内存将数据存储在键值对中 . AppFabric为.NET Framework应用程序提供了性能和可伸缩性改进 . Concepts and Architecture
扩展@Hrvoje Hudo的答案......
Code:
Examples
单项缓存(当每个项目根据其ID进行缓存时,因为缓存项目类型的整个目录将过于密集) .
缓存所有的东西
Why TId
第二个帮手特别好,因为大多数数据键不是复合的 . 如果经常使用复合键,可以添加其他方法 . 通过这种方式,您可以避免执行各种字符串连接或string.Formats以获取传递给缓存帮助程序的密钥 . 它还使得传递数据访问方法变得更容易,因为您不必将ID传递给包装器方法......对于大多数用例来说,整个事情变得非常简洁和一致 .
这是对Hrvoje Hudo的回答的改进 . 此实现有几个关键改进:
缓存键是根据更新数据的函数和传入的指定依赖关系的对象自动创建的
传递任何缓存持续时间的时间 Span
使用锁定线程安全
请注意,这依赖于Newtonsoft.Json来序列化dependsOn对象,但是可以轻松地将其替换为任何其他序列化方法 .
ICache.cs
InMemoryCache.cs
用法:
我用了两节课 . 第一个缓存核心对象:
第二个是缓存列表对象:
我会说在这个持续存在的数据问题上实现Singleton可以解决这个问题,以防您发现以前的解决方案非常复杂
我以这种方式使用它,它对我有用 . https://msdn.microsoft.com/en-us/library/system.web.caching.cache.add(v=vs.110).aspx system.web.caching.cache.add的参数信息 .
您还可以尝试使用ASP MVC中内置的缓存:
将以下属性添加到您要缓存的控制器方法:
在这种情况下,ActionResult将缓存10秒 .
更多关于此here