@@ -23,13 +23,15 @@ sealed class OutputCacheHelper {
2323 private const string Identity = "identity" ;
2424 private const string Asterisk = "*" ;
2525 private const string OutputcacheKeyprefixDependencies = "Microsoft.AspNet.OutputCache.Dependencies" ;
26+ private static CacheItemRemovedCallback s_dependencyRemovedCallback ;
2627 private static MemoryCache memoryCache = new MemoryCache ( "Microsoft.AspNet.OutputCache.MemoryCache" ) ;
2728 private static InMemoryOutputCacheProvider inMemoryOutputCacheProvider = new InMemoryOutputCacheProvider ( ) ;
2829 private HttpContext _context ;
2930 #endregion
3031
3132 public OutputCacheHelper ( HttpContext httpContext ) {
3233 _context = httpContext ;
34+ s_dependencyRemovedCallback = new CacheItemRemovedCallback ( DependencyRemovedCallback ) ;
3335 }
3436
3537 #region public methods
@@ -298,7 +300,7 @@ public bool IsAcceptableEncoding(string contentEncoding, string acceptEncoding)
298300 }
299301
300302 public bool IsResponseCacheable ( ) {
301- HttpCachePolicy cache = ( HttpCachePolicy ) _context . Response . Cache ;
303+ HttpCachePolicy cache = ( HttpCachePolicy ) _context . Response . Cache ;
302304 if ( ! cache . IsModified ( ) ) {
303305 return false ;
304306 }
@@ -455,6 +457,16 @@ public void UpdateCachedResponse(HttpCachePolicySettings settings, HttpRawRespon
455457 #endregion
456458
457459 #region private methods
460+ private async void DependencyRemovedCallback ( string key , object value , CacheItemRemovedReason reason ) {
461+ var dce = value as DependencyCacheEntry ;
462+ // TODO: invalidate kernel cache entry
463+ if ( reason == CacheItemRemovedReason . DependencyChanged ) {
464+ if ( dce . RawResponseKey != null ) {
465+ await RemoveFromProvider ( dce . RawResponseKey , dce . ProviderName ) ;
466+ }
467+ }
468+ }
469+
458470 private async Task RemoveFromProvider ( string key , string providerName ) {
459471 OutputCacheProviderAsync provider ;
460472 // we know where it is. If providerName is given,
@@ -486,10 +498,7 @@ private bool HasDependencyChanged(string depKey, string[] fileDeps, string kerne
486498 if ( depKey == null ) {
487499 return false ;
488500 }
489- // is the file dependency already in the in-memory cache?
490- if ( memoryCache . Get ( depKey ) != null ) {
491- return false ;
492- }
501+
493502 // deserialize the file dependencies
494503 var dep = new CacheDependency ( fileDeps ) ;
495504 int idStartIndex = OutputcacheKeyprefixDependencies . Length ;
@@ -500,16 +509,9 @@ private bool HasDependencyChanged(string depKey, string[] fileDeps, string kerne
500509 var dce = new DependencyCacheEntry {
501510 RawResponseKey = oceKey ,
502511 KernelCacheUrl = kernelKey ,
503- Name = providerName
504- } ;
505- var dcew = new DependencyCacheEntryWrapper {
506- DependencyCacheEntry = dce ,
507- Dependencies = dep ,
508- CacheItemPriority = System . Web . Caching . CacheItemPriority . Normal ,
509- DependencyCacheTimeSpan = Cache . NoSlidingExpiration ,
510- DependencyRemovedCallback = null
512+ ProviderName = providerName
511513 } ;
512- memoryCache . Set ( depKey , dcew , DateTimeOffset . MaxValue ) ;
514+ memoryCache . Set ( depKey , dce , GetCacheItemPolicy ( dep ) ) ;
513515 return false ;
514516 }
515517 // file dependencies have changed
@@ -557,8 +559,7 @@ private async Task InsertResponseAsync(string cachedVaryKey,
557559 CacheDependency dependencies ,
558560 DateTime absExp ,
559561 TimeSpan slidingExpiration ) {
560- // if the provider is undefined or the fragment can't be inserted in the
561- // provider, insert it in the internal cache.
562+
562563 OutputCacheProviderAsync provider = GetProvider ( ) ;
563564 // CachedVary can be serialized.
564565 // CachedRawResponse is not always serializable.
@@ -592,30 +593,44 @@ private async Task InsertResponseAsync(string cachedVaryKey,
592593 rawResponse . CachedVaryId = cachedVary . CachedVaryId ;
593594 }
594595 // Now insert into the cache
596+ string depKey = null ;
595597 if ( dependencies != null ) {
596- string depKey = OutputcacheKeyprefixDependencies + dependencies . GetUniqueID ( ) ;
597- OutputCacheEntry oce = Convert ( rawResponse , depKey , dependencies . GetFileDependencies ( ) ) ;
598- await provider . SetAsync ( rawResponseKey , oce , absExp ) ;
599- // use Add and dispose dependencies if there's already one in the cache
600- var dce = new DependencyCacheEntry {
601- RawResponseKey = rawResponseKey ,
602- KernelCacheUrl = oce . KernelCacheUrl ,
603- Name = provider . Name
604- } ;
605- var dcew = new DependencyCacheEntryWrapper {
606- DependencyCacheEntry = dce ,
607- Dependencies = dependencies ,
608- CacheItemPriority = System . Web . Caching . CacheItemPriority . Normal ,
609- DependencyCacheTimeSpan = Cache . NoSlidingExpiration ,
610- DependencyRemovedCallback = null
611- } ;
612- object d = await provider . AddAsync ( depKey , dcew , absExp ) ;
613- if ( d != null ) {
614- dependencies . Dispose ( ) ;
598+ depKey = OutputcacheKeyprefixDependencies + dependencies . GetUniqueID ( ) ;
599+ }
600+ OutputCacheEntry oce = Convert ( rawResponse , depKey , dependencies . GetFileDependencies ( ) ) ;
601+
602+ await provider . SetAsync ( rawResponseKey , oce , absExp ) ;
603+
604+ if ( dependencies != null ) {
605+
606+ // Check if Cache Dependency is supported
607+ var cacheDepHandler = provider as ICacheDependencyHandler ;
608+ if ( cacheDepHandler != null ) {
609+ var dce = new DependencyCacheEntry {
610+ RawResponseKey = rawResponseKey ,
611+ KernelCacheUrl = oce . KernelCacheUrl ,
612+ ProviderName = provider . Name
613+ } ;
614+
615+ await cacheDepHandler . AddAsync ( depKey , dce , GetCacheItemPolicy ( dependencies ) ) ;
615616 }
617+
618+ dependencies . Dispose ( ) ;
616619 }
617620 }
618621
622+ private CacheItemPolicy GetCacheItemPolicy ( CacheDependency dependency ) {
623+ CacheItemPolicy cacheItemPolicy = new CacheItemPolicy ( ) ;
624+ cacheItemPolicy . RemovedCallback = ( new RemovedCallback ( s_dependencyRemovedCallback ) ) . CacheEntryRemovedCallback ;
625+ List < string > filePaths = new List < string > ( ) ;
626+ foreach ( string fileDependency in dependency . GetFileDependencies ( ) ) {
627+ filePaths . Add ( fileDependency ) ;
628+ }
629+ var fileChangeMonitor = new HostFileChangeMonitor ( filePaths ) ;
630+ cacheItemPolicy . ChangeMonitors . Add ( fileChangeMonitor ) ;
631+ return cacheItemPolicy ;
632+ }
633+
619634 private bool IsCacheableEncoding ( Encoding contentEncoding , HttpCacheVaryByContentEncodings varyByContentEncodings ) {
620635 // return true if we are not varying by content encoding.
621636 if ( varyByContentEncodings == null ) {
@@ -1026,12 +1041,12 @@ private async Task InsertResponseAsync(string key, DateTime utcExpires, CachedVa
10261041 if ( utcExpires > DateTime . Now ) {
10271042 // Create the response object to be sent on cache hits.
10281043 HttpRawResponse httpRawResponse = GetSnapshot ( ) ;
1029- string kernelCacheUrl = OutputCacheUtility . SetupKernelCaching ( null , _context . Response ) ;
1044+ //TODO insert the response into kernel Cache
10301045 Guid cachedVaryId = cachedVary ? . CachedVaryId ?? Guid . Empty ;
10311046 var cachedRawResponse = new CachedRawResponse {
10321047 RawResponse = httpRawResponse ,
10331048 CachePolicy = settings ,
1034- KernelCacheUrl = kernelCacheUrl ,
1049+ KernelCacheUrl = null ,
10351050 CachedVaryId = cachedVaryId
10361051 } ;
10371052 using ( CacheDependency dep = OutputCacheUtility . CreateCacheDependency ( _context . Response ) ) {
0 commit comments