Orchard缓存的优点和机制:
多级缓存:
Orchard缓存的多级缓存控制机制是非常值得称道的,他可以将有依赖关系的对象自动关联起来进行自动控制,比如:A对象是从B对象得到的,这时候如果B对象过期,那么A对象也会自动过期;这里可以看到所有的缓存是存放在一个ConcurrentDictionary结构里的,这个ConcurrentDictionary可以保证线程安全。
使用简单:
Orchard抛弃传统的传统get set的缓存方式,Orchard缓存的管理都只提供了一个Get方面没有其他Add、Update等等的东西.从缓存类里Get的方法的实现我们知道, 当程序无法根据TKey获取到结果的时候,就会创建一个新的结果同时保存到缓存里。
过期机制:
Orchard的缓存拥有强大的过期机制,实际上他的根本是一个失效令牌的机制,令牌只有一个属性: bool IsCurrent 如果IsCurrent==false时Cache过期,而客户代码可以通过实现不同的IVolatileProvider来实现各种不同的过期机制。
优雅的代码风格:
在Orchard.Framework的Caching目录下有18个文件,有兴趣的同学可以读读源码,写的非常不错。
下面我们用一段简单的代码来演示一下怎么使用其缓存:
private PackagesStatusResult GetPackages(PackagingSource packagingSource) { // Refresh every 23 hours or when signal was triggered return _cacheManager.Get(packagingSource.FeedUrl, ctx => { ctx.Monitor(_clock.When(TimeSpan.FromMinutes(60 * 23))); ctx.Monitor(_signals.When("PackageUpdateService")); // We cache exception because we are calling on a network feed, and failure may // take quite some time. var result = new PackagesStatusResult { DateTimeUtc = _clock.UtcNow, Entries = new List<UpdatePackageEntry>(), Errors = new List<Exception>() }; try { result.Entries = GetPackagesWorker(packagingSource); } catch (Exception e) { result.Errors = new[] { e }; } return result; }); }
上面展示的是基于时间的缓存过期机制,您也可以监测数据和其他环境变量的变化,来改变其机制蛤需要将_clock换成_Signals,比如下面这个使用:
private ContentTypeRecord AcquireContentTypeRecord(string contentType) { var contentTypeId = _cacheManager.Get(contentType + "_Record", ctx => { ctx.Monitor(_signals.When(contentType + "_Record")); var contentTypeRecord = _contentTypeRepository.Get(x => x.Name == contentType); if (contentTypeRecord == null) { //TEMP: this is not safe... ContentItem types could be created concurrently? contentTypeRecord = new ContentTypeRecord { Name = contentType }; _contentTypeRepository.Create(contentTypeRecord); } return contentTypeRecord.Id; }); // There is a case when a content type record is created locally but the transaction is actually // cancelled. In this case we are caching an Id which is none existent, or might represent another // content type. Thus we need to ensure that the cache is valid, or invalidate it and retrieve it // another time. var result = _contentTypeRepository.Get(contentTypeId); if (result != null && result.Name.Equals(contentType, StringComparison.OrdinalIgnoreCase) ) { return result; } // invalidate the cache entry and load it again _signals.Trigger(contentType + "_Record"); return AcquireContentTypeRecord(contentType); }
上面的代码中28行:_signals.Trigger(contentType + “_Record”); 作用为使其缓存过期。