使用存储库/服务模式和MVC时caching数据对象
我有一个基于MVC的网站,使用存储库/服务模式进行数据访问。 这些服务被编写用于大多数应用程序(控制台,winform和web)。 目前,控制器直接与服务进行通信。 这限制了应用适当caching的能力。
我看到我的select如下:
- 编写一个Web应用程序的包装,它实现了caching的IWhatEverService。
- 通过caching每个操作的ViewData来caching每个控制器。
- 不要担心数据caching,只需为每个Action执行OutputCaching。
我可以看到每个人的利弊。 使用Repository / Service进行caching的最佳做法是什么?
最简单的方法是处理仓库提供者中的caching。 这样你就不必在应用程序的其余部分更改任何代码; 它会忘记数据是从caching而不是存储库提供的。
所以,我会创build一个控制器用来与后端进行通信的接口,并在这个实现中添加caching逻辑。 用一些DI将它包装在一个不错的蝴蝶结中,并且你的应用程序将被设置为易于testing。
史蒂夫·史密斯做了两篇很棒的博客post,演示了如何使用他的CachedRepository模式来实现你正在寻找的结果。
介绍CachedRepository模式
通过战略模式构build一个CachedRepository
在这两篇文章中,他向你展示了如何设置这个模式,并解释了为什么它是有用的。 通过使用这种模式,您可以在不存在您现有的代码的情况下caching任何caching逻辑。 本质上,您使用caching的存储库就好像它是任何其他存储库。
public class CachedAlbumRepository : IAlbumRepository { private readonly IAlbumRepository _albumRepository; public CachedAlbumRepository(IAlbumRepository albumRepository) { _albumRepository = albumRepository; } private static readonly object CacheLockObject = new object(); public IEnumerable<Album> GetTopSellingAlbums(int count) { Debug.Print("CachedAlbumRepository:GetTopSellingAlbums"); string cacheKey = "TopSellingAlbums-" + count; var result = HttpRuntime.Cache[cacheKey] as List<Album>; if (result == null) { lock (CacheLockObject) { result = HttpRuntime.Cache[cacheKey] as List<Album>; if (result == null) { result = _albumRepository.GetTopSellingAlbums(count).ToList(); HttpRuntime.Cache.Insert(cacheKey, result, null, DateTime.Now.AddSeconds(60), TimeSpan.Zero); } } } return result; } }
检查我的caching服务的实现:
如何在MVC应用程序中caching数据
(我不想在这里重复回答…)
随意评论!
根据Brendan提供的答案,我定义了一个通用的caching存储库,用于比较小的列表的特殊情况,这些列表很less被更改,但是被大量阅读 。
1.界面
public interface IRepository<T> : IRepository where T : class { IQueryable<T> AllNoTracking { get; } IQueryable<T> All { get; } DbSet<T> GetSet { get; } T Get(int id); void Insert(T entity); void BulkInsert(IEnumerable<T> entities); void Delete(T entity); void RemoveRange(IEnumerable<T> range); void Update(T entity); }
2.正常/非高速caching的存储库
public class Repository<T> : IRepository<T> where T : class, new() { private readonly IEfDbContext _context; public Repository(IEfDbContext context) { _context = context; } public IQueryable<T> All => _context.Set<T>().AsQueryable(); public IQueryable<T> AllNoTracking => _context.Set<T>().AsNoTracking(); public IQueryable AllNoTrackingGeneric(Type t) { return _context.GetSet(t).AsNoTracking(); } public DbSet<T> GetSet => _context.Set<T>(); public DbSet GetSetNonGeneric(Type t) { return _context.GetSet(t); } public IQueryable AllNonGeneric(Type t) { return _context.GetSet(t); } public T Get(int id) { return _context.Set<T>().Find(id); } public void Delete(T entity) { if (_context.Entry(entity).State == EntityState.Detached) _context.Set<T>().Attach(entity); _context.Set<T>().Remove(entity); } public void RemoveRange(IEnumerable<T> range) { _context.Set<T>().RemoveRange(range); } public void Insert(T entity) { _context.Set<T>().Add(entity); } public void BulkInsert(IEnumerable<T> entities) { _context.BulkInsert(entities); } public void Update(T entity) { _context.Set<T>().Attach(entity); _context.Entry(entity).State = EntityState.Modified; }
}
3.通用caching存储库基于非caching存储库
public interface ICachedRepository<T> where T : class, new() { string CacheKey { get; } void InvalidateCache(); void InsertIntoCache(T item); } public class CachedRepository<T> : ICachedRepository<T>, IRepository<T> where T : class, new() { private readonly IRepository<T> _modelRepository; private static readonly object CacheLockObject = new object(); private IList<T> ThreadSafeCacheAccessAction(Action<IList<T>> action = null) { // refresh cache if necessary var list = HttpRuntime.Cache[CacheKey] as IList<T>; if (list == null) { lock (CacheLockObject) { list = HttpRuntime.Cache[CacheKey] as IList<T>; if (list == null) { list = _modelRepository.All.ToList(); //TODO: remove hardcoding HttpRuntime.Cache.Insert(CacheKey, list, null, DateTime.UtcNow.AddMinutes(10), Cache.NoSlidingExpiration); } } } // execute custom action, if one is required if (action != null) { lock (CacheLockObject) { action(list); } } return list; } public IList<T> GetCachedItems() { IList<T> ret = ThreadSafeCacheAccessAction(); return ret; } /// <summary> /// returns value without using cache, to allow Queryable usage /// </summary> public IQueryable<T> All => _modelRepository.All; public IQueryable<T> AllNoTracking { get { var cachedItems = GetCachedItems(); return cachedItems.AsQueryable(); } } // other methods come here public void BulkInsert(IEnumerable<T> entities) { var enumerable = entities as IList<T> ?? entities.ToList(); _modelRepository.BulkInsert(enumerable); // also inserting items within the cache ThreadSafeCacheAccessAction((list) => { foreach (var item in enumerable) list.Add(item); }); } public void Delete(T entity) { _modelRepository.Delete(entity); ThreadSafeCacheAccessAction((list) => { list.Remove(entity); }); } }
使用DI框架(我使用Ninject),可以很容易地定义一个仓库是否应该被caching:
// IRepository<T> should be solved using Repository<T>, by default kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)); // IRepository<T> must be solved to Repository<T>, if used in CachedRepository<T> kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).WhenInjectedInto(typeof(CachedRepository<>)); // explicit repositories using caching var cachedTypes = new List<Type> { typeof(ImportingSystem), typeof(ImportingSystemLoadInfo), typeof(Environment) }; cachedTypes.ForEach(type => { // allow access as normal repository kernel .Bind(typeof(IRepository<>).MakeGenericType(type)) .To(typeof(CachedRepository<>).MakeGenericType(type)); // allow access as a cached repository kernel .Bind(typeof(ICachedRepository<>).MakeGenericType(type)) .To(typeof(CachedRepository<>).MakeGenericType(type)); });
所以,从caching仓库中读取是完全不知道caching。 但是,更改它们需要从ICacheRepository<>
注入并调用适当的方法。
- 以下部分已被定义,但尚未呈现布局页面“〜/ Views / Shared / _Layout.cshtml”:“脚本”
- 如何为C#MVC4 WebAPI应用程序全局logging所有exception?
- 在ASP.NET MVC的图像周围制作一个Html.ActionLink?
- 扩展方法不能dynamic分派
- 在MVC脚本包中使用CDN。 我错过了什么?
- ASP.NET MVC – 附加types“MODELNAME”的实体失败,因为另一个相同types的实体已经具有相同的主键值
- ASP.NET MVC 3 Razorrecursion函数
- 在ASP.NET MVC中logging错误
- ASP.NET MVC全局variables