@@ -23,13 +23,15 @@ sealed class OutputCacheHelper {
23
23
private const string Identity = "identity" ;
24
24
private const string Asterisk = "*" ;
25
25
private const string OutputcacheKeyprefixDependencies = "Microsoft.AspNet.OutputCache.Dependencies" ;
26
+ private static CacheItemRemovedCallback s_dependencyRemovedCallback ;
26
27
private static MemoryCache memoryCache = new MemoryCache ( "Microsoft.AspNet.OutputCache.MemoryCache" ) ;
27
28
private static InMemoryOutputCacheProvider inMemoryOutputCacheProvider = new InMemoryOutputCacheProvider ( ) ;
28
29
private HttpContext _context ;
29
30
#endregion
30
31
31
32
public OutputCacheHelper ( HttpContext httpContext ) {
32
33
_context = httpContext ;
34
+ s_dependencyRemovedCallback = new CacheItemRemovedCallback ( DependencyRemovedCallback ) ;
33
35
}
34
36
35
37
#region public methods
@@ -298,7 +300,7 @@ public bool IsAcceptableEncoding(string contentEncoding, string acceptEncoding)
298
300
}
299
301
300
302
public bool IsResponseCacheable ( ) {
301
- HttpCachePolicy cache = ( HttpCachePolicy ) _context . Response . Cache ;
303
+ HttpCachePolicy cache = ( HttpCachePolicy ) _context . Response . Cache ;
302
304
if ( ! cache . IsModified ( ) ) {
303
305
return false ;
304
306
}
@@ -455,6 +457,16 @@ public void UpdateCachedResponse(HttpCachePolicySettings settings, HttpRawRespon
455
457
#endregion
456
458
457
459
#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
+
458
470
private async Task RemoveFromProvider ( string key , string providerName ) {
459
471
OutputCacheProviderAsync provider ;
460
472
// we know where it is. If providerName is given,
@@ -486,10 +498,7 @@ private bool HasDependencyChanged(string depKey, string[] fileDeps, string kerne
486
498
if ( depKey == null ) {
487
499
return false ;
488
500
}
489
- // is the file dependency already in the in-memory cache?
490
- if ( memoryCache . Get ( depKey ) != null ) {
491
- return false ;
492
- }
501
+
493
502
// deserialize the file dependencies
494
503
var dep = new CacheDependency ( fileDeps ) ;
495
504
int idStartIndex = OutputcacheKeyprefixDependencies . Length ;
@@ -500,16 +509,9 @@ private bool HasDependencyChanged(string depKey, string[] fileDeps, string kerne
500
509
var dce = new DependencyCacheEntry {
501
510
RawResponseKey = oceKey ,
502
511
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
511
513
} ;
512
- memoryCache . Set ( depKey , dcew , DateTimeOffset . MaxValue ) ;
514
+ memoryCache . Set ( depKey , dce , GetCacheItemPolicy ( dep ) ) ;
513
515
return false ;
514
516
}
515
517
// file dependencies have changed
@@ -557,8 +559,7 @@ private async Task InsertResponseAsync(string cachedVaryKey,
557
559
CacheDependency dependencies ,
558
560
DateTime absExp ,
559
561
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
+
562
563
OutputCacheProviderAsync provider = GetProvider ( ) ;
563
564
// CachedVary can be serialized.
564
565
// CachedRawResponse is not always serializable.
@@ -592,30 +593,44 @@ private async Task InsertResponseAsync(string cachedVaryKey,
592
593
rawResponse . CachedVaryId = cachedVary . CachedVaryId ;
593
594
}
594
595
// Now insert into the cache
596
+ string depKey = null ;
595
597
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 ) ) ;
615
616
}
617
+
618
+ dependencies . Dispose ( ) ;
616
619
}
617
620
}
618
621
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
+
619
634
private bool IsCacheableEncoding ( Encoding contentEncoding , HttpCacheVaryByContentEncodings varyByContentEncodings ) {
620
635
// return true if we are not varying by content encoding.
621
636
if ( varyByContentEncodings == null ) {
@@ -1026,12 +1041,12 @@ private async Task InsertResponseAsync(string key, DateTime utcExpires, CachedVa
1026
1041
if ( utcExpires > DateTime . Now ) {
1027
1042
// Create the response object to be sent on cache hits.
1028
1043
HttpRawResponse httpRawResponse = GetSnapshot ( ) ;
1029
- string kernelCacheUrl = OutputCacheUtility . SetupKernelCaching ( null , _context . Response ) ;
1044
+ //TODO insert the response into kernel Cache
1030
1045
Guid cachedVaryId = cachedVary ? . CachedVaryId ?? Guid . Empty ;
1031
1046
var cachedRawResponse = new CachedRawResponse {
1032
1047
RawResponse = httpRawResponse ,
1033
1048
CachePolicy = settings ,
1034
- KernelCacheUrl = kernelCacheUrl ,
1049
+ KernelCacheUrl = null ,
1035
1050
CachedVaryId = cachedVaryId
1036
1051
} ;
1037
1052
using ( CacheDependency dep = OutputCacheUtility . CreateCacheDependency ( _context . Response ) ) {
0 commit comments