Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / xsp / System / Web / Cache / CacheDependency.cs / 1 / CacheDependency.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- /* * CacheDependency.cs * * Copyright (c) 1998-1999, Microsoft Corporation * */ namespace System.Web.Caching { using System.Collections; using System.Text; using System.IO; using System.Threading; using System.Web.Util; using System.Security.Permissions; using System.Globalization; internal interface ICacheDependencyChanged { void DependencyChanged(Object sender, EventArgs e); } ////// // Overhead is 24 bytes + object header [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)] public class CacheDependency : IDisposable { #if DBG bool _isUniqueIDInitialized; #endif string _uniqueID; // used by HttpCachePolicy for the ETag object _depFileInfos; // files to monitor for changes, either a DepFileInfo or array of DepFileInfos object _entries; // cache entries we are dependent on, either a string or array of strings ICacheDependencyChanged _objNotify; // Associated object to notify when a change occurs SafeBitVector32 _bits; // status bits for ready, used, changed, disposed DateTime _utcLastModified; // Time of last modified item static readonly string[] s_stringsEmpty; static readonly CacheEntry[] s_entriesEmpty; static readonly CacheDependency s_dependencyEmpty; static readonly DepFileInfo[] s_depFileInfosEmpty; static readonly TimeSpan FUTURE_FILETIME_BUFFER = new TimeSpan(0, 1, 0); // See VSWhidbey 400917 const int BASE_INIT = 0x01; const int USED = 0x02; const int CHANGED = 0x04; const int BASE_DISPOSED = 0x08; const int WANTS_DISPOSE = 0x10; const int DERIVED_INIT = 0x20; const int DERIVED_DISPOSED = 0x40; internal class DepFileInfo { internal string _filename; internal FileAttributesData _fad; } static CacheDependency() { s_stringsEmpty = new string[0]; s_entriesEmpty = new CacheEntry[0]; s_dependencyEmpty = new CacheDependency(0); s_depFileInfosEmpty = new DepFileInfo[0]; } // creates an empty dependency which is used only by s_dependencyEmpty private CacheDependency(int bogus) { Debug.Assert(s_dependencyEmpty == null, "s_dependencyEmpty == null"); } protected CacheDependency() { Init(true, null, null, null, DateTime.MaxValue); } ///The ///class tracks cache dependencies, which can be files, /// directories, or keys to other objects in the System.Web.Cache.Cache. When an object of this class /// is constructed, it immediately begins monitoring objects on which it is /// dependent for changes. This avoids losing the changes made between the time the /// object to cache is created and the time it is inserted into the /// . /// public CacheDependency(string filename) : this (filename, DateTime.MaxValue) { } public CacheDependency(string filename, DateTime start) { if (filename == null) { return; } DateTime utcStart = DateTimeUtil.ConvertToUniversalTime(start); string[] filenames = new string[1] {filename}; Init(true, filenames, null, null, utcStart); } ///Initializes a new instance of the System.Web.Cache.CacheDependency class. The new instance /// monitors a file or directory for changes. ////// public CacheDependency(string[] filenames) { Init(true, filenames, null, null, DateTime.MaxValue); } public CacheDependency(string[] filenames, DateTime start) { DateTime utcStart = DateTimeUtil.ConvertToUniversalTime(start); Init(true, filenames, null, null, utcStart); } ///Initializes a new instance of the System.Web.Cache.CacheDependency class. The new instance monitors an array /// files or directories for changes. ////// public CacheDependency(string[] filenames, string[] cachekeys) { Init(true, filenames, cachekeys, null, DateTime.MaxValue); } public CacheDependency(string[] filenames, string[] cachekeys, DateTime start) { DateTime utcStart = DateTimeUtil.ConvertToUniversalTime(start); Init(true, filenames, cachekeys, null, utcStart); } public CacheDependency(string[] filenames, string[] cachekeys, CacheDependency dependency) { Init(true, filenames, cachekeys, dependency, DateTime.MaxValue); } public CacheDependency(string[] filenames, string[] cachekeys, CacheDependency dependency, DateTime start) { DateTime utcStart = DateTimeUtil.ConvertToUniversalTime(start); Init(true, filenames, cachekeys, dependency, utcStart); } internal CacheDependency(int dummy, string filename) : this(dummy, filename, DateTime.MaxValue) { } internal CacheDependency(int dummy, string filename, DateTime utcStart) { if (filename == null) { return; } string[] filenames = new string[1] {filename}; Init(false, filenames, null, null, utcStart); } internal CacheDependency(int dummy, string[] filenames) { Init(false, filenames, null, null, DateTime.MaxValue); } internal CacheDependency(int dummy, string[] filenames, DateTime utcStart) { Init(false, filenames, null, null, utcStart); } internal CacheDependency(int dummy, string[] filenames, string[] cachekeys) { Init(false, filenames, cachekeys, null, DateTime.MaxValue); } internal CacheDependency(int dummy, string[] filenames, string[] cachekeys, DateTime utcStart) { Init(false, filenames, cachekeys, null, utcStart); } internal CacheDependency(int dummy, string[] filenames, string[] cachekeys, CacheDependency dependency) { Init(false, filenames, cachekeys, dependency, DateTime.MaxValue); } internal CacheDependency(int dummy, string[] filenames, string[] cachekeys, CacheDependency dependency, DateTime utcStart) { Init(false, filenames, cachekeys, dependency, utcStart); } void Init(bool isPublic, string[] filenamesArg, string[] cachekeysArg, CacheDependency dependency, DateTime utcStart) { DepFileInfo[] depFileInfos = s_depFileInfosEmpty; CacheEntry[] depEntries = s_entriesEmpty; string [] filenames, cachekeys; CacheInternal cacheInternal; _bits = new SafeBitVector32(0); // copy array argument contents so they can't be changed beneath us if (filenamesArg != null) { filenames = (string []) filenamesArg.Clone(); } else { filenames = null; } if (cachekeysArg != null) { cachekeys = (string []) cachekeysArg.Clone(); } else { cachekeys = null; } _utcLastModified = DateTime.MinValue; try { // validate filenames array if (filenames == null) { filenames = s_stringsEmpty; } else { foreach (string f in filenames) { if (f == null) { throw new ArgumentNullException("filenamesArg"); } // demand PathDiscovery if public if (isPublic) { InternalSecurityPermissions.PathDiscovery(f).Demand(); } } } if (cachekeys == null) { cachekeys = s_stringsEmpty; } else { // validate cachekeys array foreach (string k in cachekeys) { if (k == null) { throw new ArgumentNullException("cachekeysArg"); } } } // copy all parts of another dependency if provided if (dependency == null) { dependency = s_dependencyEmpty; } else { if (dependency.GetType() != s_dependencyEmpty.GetType()) { throw new ArgumentException(SR.GetString(SR.Invalid_Dependency_Type)); } // Copy the parts of the dependency we need before // we reference them, as the dependency can change // underneath us. object d_depFileInfos = dependency._depFileInfos; object d_entries = dependency._entries; DateTime d_lastModified = dependency._utcLastModified; // if the dependency we're copying has changed, we're done if (dependency._bits[CHANGED]) { _bits[CHANGED] = true; // There is nothing to dispose because we haven't started // monitoring anything yet. But we call DisposeInternal in // order to set the WANTS_DISPOSE bit. DisposeInternal(); return; } // copy depFileInfos if (d_depFileInfos != null) { if (d_depFileInfos is DepFileInfo) { depFileInfos = new DepFileInfo[1] {(DepFileInfo) d_depFileInfos}; } else { depFileInfos = (DepFileInfo[]) (d_depFileInfos); } // verify that the object was fully constructed // and that we have permission to discover the file foreach (DepFileInfo depFileInfo in depFileInfos) { string f = depFileInfo._filename; if (f == null) { _bits[CHANGED] = true; // There is nothing to dispose because we haven't started // monitoring anything yet. But we call DisposeInternal in // order to set the WANTS_DISPOSE bit. DisposeInternal(); return; } // demand PathDiscovery if public if (isPublic) { InternalSecurityPermissions.PathDiscovery(f).Demand(); } } } // copy cache entries if (d_entries != null) { if (d_entries is CacheEntry) { depEntries = new CacheEntry[1] {(CacheEntry) (d_entries)}; } else { depEntries = (CacheEntry[]) (d_entries); // verify that the object was fully constructed foreach (CacheEntry entry in depEntries) { if (entry == null) { _bits[CHANGED] = true; // There is nothing to dispose because we haven't started // monitoring anything yet. But we call DisposeInternal in // order to set the WANTS_DISPOSE bit. DisposeInternal(); return; } } } } _utcLastModified = d_lastModified; } // Monitor files for changes int lenMyDepFileInfos = depFileInfos.Length + filenames.Length; if (lenMyDepFileInfos > 0) { DepFileInfo[] myDepFileInfos = new DepFileInfo[lenMyDepFileInfos]; FileChangeEventHandler handler = new FileChangeEventHandler(this.FileChange); FileChangesMonitor fmon = HttpRuntime.FileChangesMonitor; int i; for (i = 0; i < lenMyDepFileInfos; i++) { myDepFileInfos[i] = new DepFileInfo(); } // monitor files from the existing dependency // note that we don't check for start times in the existing dependency i = 0; foreach (DepFileInfo depFileInfo in depFileInfos) { string f = depFileInfo._filename; fmon.StartMonitoringPath(f, handler, out myDepFileInfos[i]._fad); myDepFileInfos[i]._filename = f; i++; } // monitor new files DateTime utcNow = DateTime.MinValue; foreach (string f in filenames) { DateTime utcLastWrite = fmon.StartMonitoringPath(f, handler, out myDepFileInfos[i]._fad); myDepFileInfos[i]._filename = f; i++; if (utcLastWrite > _utcLastModified) { _utcLastModified = utcLastWrite; } // check if file has changed since the start time if (utcStart < DateTime.MaxValue) { if (utcNow == DateTime.MinValue) { utcNow = DateTime.UtcNow; } Debug.Trace("CacheDependencyInit", "file=" + f + "; utcStart=" + utcStart + "; utcLastWrite=" + utcLastWrite); if (utcLastWrite >= utcStart && !(utcLastWrite - utcNow > FUTURE_FILETIME_BUFFER)) { // See VSWhidbey 400917 Debug.Trace("CacheDependencyInit", "changes occurred since start time for file " + f); _bits[CHANGED] = true; break; } } } if (myDepFileInfos.Length == 1) { _depFileInfos = myDepFileInfos[0]; } else { _depFileInfos = myDepFileInfos; } } // Monitor other cache entries for changes int lenMyEntries = depEntries.Length + cachekeys.Length; if (lenMyEntries > 0 && !_bits[CHANGED]) { CacheEntry[] myEntries = new CacheEntry[lenMyEntries]; // Monitor entries from the existing cache dependency int i = 0; foreach (CacheEntry entry in depEntries) { entry.AddCacheDependencyNotify(this); myEntries[i++] = entry; } // Monitor new entries specified for this depenedency // Entries must be added to cache, and created before the startTime cacheInternal = HttpRuntime.CacheInternal; foreach (string k in cachekeys) { CacheEntry entry = (CacheEntry) cacheInternal.DoGet(isPublic, k, CacheGetOptions.ReturnCacheEntry); if (entry != null) { entry.AddCacheDependencyNotify(this); myEntries[i++] = entry; if (entry.UtcCreated > _utcLastModified) { _utcLastModified = entry.UtcCreated; } if ( entry.State != CacheEntry.EntryState.AddedToCache || entry.UtcCreated > utcStart) { #if DBG if (entry.State != CacheEntry.EntryState.AddedToCache) { Debug.Trace("CacheDependencyInit", "Entry is not in cache, considered changed:" + k); } else { Debug.Trace("CacheDependencyInit", "Changes occurred to entry since start time:" + k); } #endif _bits[CHANGED] = true; break; } } else { Debug.Trace("CacheDependencyInit", "Cache item not found to create dependency on:" + k); _bits[CHANGED] = true; break; } } if (myEntries.Length == 1) { _entries = myEntries[0]; } else { _entries = myEntries; } } _bits[BASE_INIT] = true; if (dependency._bits[CHANGED]) { _bits[CHANGED] = true; } if (_bits[WANTS_DISPOSE] || _bits[CHANGED]) { DisposeInternal(); } Debug.Assert(_objNotify == null, "_objNotify == null"); } catch { // derived constructor will not execute due to the throw, // so we just force a dispose on ourselves _bits[BASE_INIT] = true; DisposeInternal(); throw; } finally { InitUniqueID(); } } public void Dispose() { // Set this bit just in case our derived ctor forgot to call FinishInit() _bits[DERIVED_INIT] = true; if (Use()) { // Do the dispose only if the cache has not already used us DisposeInternal(); } } protected internal void FinishInit() { _bits[DERIVED_INIT] = true; if (_bits[WANTS_DISPOSE]) { DisposeInternal(); } } /* * Shutdown all dependency monitoring and firing of NotifyDependencyChanged notification. */ internal void DisposeInternal() { _bits[WANTS_DISPOSE] = true; if (_bits[DERIVED_INIT]) { if (_bits.ChangeValue(DERIVED_DISPOSED, true)) { // Dispose derived classes DependencyDispose(); } } if (_bits[BASE_INIT]) { if (_bits.ChangeValue(BASE_DISPOSED, true)) { // Dispose ourself DisposeOurself(); } } } // Allow derived class to dispose itself protected virtual void DependencyDispose() { // We do our own dispose work in DisposeOurself, so that // we don't rely on derived classes calling their base // DependencyDispose for us to function correctly. } void DisposeOurself() { // guarantee that we execute only once if an exception // is thrown from this function by nulling fields before // we access them object l_depFileInfos = _depFileInfos; object l_entries = _entries; _objNotify = null; _depFileInfos = null; _entries = null; // stop monitoring files if (l_depFileInfos != null) { FileChangesMonitor fmon = HttpRuntime.FileChangesMonitor; DepFileInfo oneDepFileInfo = l_depFileInfos as DepFileInfo; if (oneDepFileInfo != null) { fmon.StopMonitoringPath(oneDepFileInfo._filename, this); } else { DepFileInfo[] depFileInfos = (DepFileInfo[]) l_depFileInfos; foreach (DepFileInfo depFileInfo in depFileInfos) { // ensure that we handle partially contructed // objects by checking filename for null string filename = depFileInfo._filename; if (filename != null) { fmon.StopMonitoringPath(filename, this); } } } } // stop monitoring cache items if (l_entries != null) { CacheEntry oneEntry = l_entries as CacheEntry; if (oneEntry != null) { oneEntry.RemoveCacheDependencyNotify(this); } else { CacheEntry[] entries = (CacheEntry[]) l_entries; foreach (CacheEntry entry in entries) { // ensure that we handle partially contructed // objects by checking entry for null if (entry != null) { entry.RemoveCacheDependencyNotify(this); } } } } } // allow the first user to declare ownership internal bool Use() { return _bits.ChangeValue(USED, true); } // // Has a dependency changed? // public bool HasChanged { get {return _bits[CHANGED];} } public DateTime UtcLastModified { get { return _utcLastModified; } } protected void SetUtcLastModified(DateTime utcLastModified) { _utcLastModified = utcLastModified; } // // Add/remove an NotifyDependencyChanged notification. // internal void SetCacheDependencyChanged(ICacheDependencyChanged objNotify) { Debug.Assert(_objNotify == null, "_objNotify == null"); // Set this bit just in case our derived ctor forgot to call FinishInit() _bits[DERIVED_INIT] = true; if (!_bits[BASE_DISPOSED]) { _objNotify = objNotify; } } internal void AppendFileUniqueId(DepFileInfo depFileInfo, StringBuilder sb) { FileAttributesData fad = depFileInfo._fad; if (fad == null) { fad = FileAttributesData.NonExistantAttributesData; } sb.Append(depFileInfo._filename); sb.Append(fad.UtcLastWriteTime.Ticks.ToString("d", NumberFormatInfo.InvariantInfo)); sb.Append(fad.FileSize.ToString(CultureInfo.InvariantCulture)); } void InitUniqueID() { StringBuilder sb = null; object l_depFileInfos, l_entries; #if !FEATURE_PAL // no File Change Monitoring // get unique id from files l_depFileInfos = _depFileInfos; if (l_depFileInfos != null) { DepFileInfo oneDepFileInfo = l_depFileInfos as DepFileInfo; if (oneDepFileInfo != null) { sb = new StringBuilder(); AppendFileUniqueId(oneDepFileInfo, sb); } else { DepFileInfo[] depFileInfos = (DepFileInfo[]) l_depFileInfos; foreach (DepFileInfo depFileInfo in depFileInfos) { // ensure that we handle partially contructed // objects by checking filename for null if (depFileInfo._filename != null) { if (sb == null) sb = new StringBuilder(); AppendFileUniqueId(depFileInfo, sb); } } } } #endif // !FEATURE_PAL // get unique id from cache entries l_entries = _entries; if (l_entries != null) { CacheEntry oneEntry = l_entries as CacheEntry; if (oneEntry != null) { if (sb == null) sb = new StringBuilder(); sb.Append(oneEntry.Key); sb.Append(oneEntry.UtcCreated.Ticks.ToString(CultureInfo.InvariantCulture)); } else { CacheEntry[] entries = (CacheEntry[]) l_entries; foreach (CacheEntry entry in entries) { // ensure that we handle partially contructed // objects by checking entry for null if (entry != null) { if (sb == null) sb = new StringBuilder(); sb.Append(entry.Key); sb.Append(entry.UtcCreated.Ticks.ToString(CultureInfo.InvariantCulture)); } } } } if (sb != null) _uniqueID = sb.ToString(); #if DBG _isUniqueIDInitialized = true; #endif } public virtual string GetUniqueID() { #if DBG Debug.Assert(_isUniqueIDInitialized == true, "_isUniqueIDInitialized == true"); #endif return _uniqueID; } // // Return the cacheEntries monitored by this dependency // internal CacheEntry[] CacheEntries { get { if (_entries == null) { return null; } CacheEntry oneEntry = _entries as CacheEntry; if (oneEntry != null) { return new CacheEntry[1] {oneEntry}; } return (CacheEntry[]) _entries; } } // // This object has changed, so fire the NotifyDependencyChanged event. // We only allow this event to be fired once. // protected void NotifyDependencyChanged(Object sender, EventArgs e) { if (_bits.ChangeValue(CHANGED, true)) { _utcLastModified = DateTime.UtcNow; ICacheDependencyChanged objNotify = _objNotify; if (objNotify != null && !_bits[BASE_DISPOSED]) { Debug.Trace("CacheDependencyNotifyDependencyChanged", "change occurred"); objNotify.DependencyChanged(sender, e); } DisposeInternal(); } } // // ItemRemoved is called when a cache entry we are monitoring has been removed. // internal void ItemRemoved() { NotifyDependencyChanged(this, EventArgs.Empty); } // // FileChange is called when a file we are monitoring has changed. // void FileChange(Object sender, FileChangeEvent e) { Debug.Trace("CacheDependencyFileChange", "FileChange file=" + e.FileName + ";Action=" + e.Action); NotifyDependencyChanged(sender, e); } // // This will examine the dependency and determine if it's ONLY a file dependency or not // internal virtual bool IsFileDependency() { object depInfos, l_entries; // Check and see if we are dependent on any cache entries l_entries = _entries; if (l_entries != null) { CacheEntry oneEntry = l_entries as CacheEntry; if (oneEntry != null) { return false; } else { CacheEntry[] entries = (CacheEntry[]) l_entries; if (entries != null && entries.Length > 0) { return false; } } } depInfos = _depFileInfos; if (depInfos != null) { DepFileInfo oneDepFileInfo = depInfos as DepFileInfo; if (oneDepFileInfo != null) { return true; } else { DepFileInfo[] depFileInfos = (DepFileInfo[]) depInfos; if (depFileInfos != null && depFileInfos.Length > 0) { return true; } } } return false; } // // This method will return only the file dependencies from this dependency // internal virtual string[] GetFileDependencies() { object depInfos = _depFileInfos; if (depInfos != null) { DepFileInfo oneDepFileInfo = depInfos as DepFileInfo; if (oneDepFileInfo != null) { return new string[] {oneDepFileInfo._filename}; } else { DepFileInfo[] depFileInfos = (DepFileInfo[]) depInfos; string[] names = new string[depFileInfos.Length]; for (int i = 0; i < depFileInfos.Length; i++) { names[i] = depFileInfos[i]._filename; } return names; } } return null; } } [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] public sealed class AggregateCacheDependency : CacheDependency, ICacheDependencyChanged { ArrayList _dependencies; bool _disposed; public AggregateCacheDependency() { // The ctor of every class derived from CacheDependency must call this. FinishInit(); } public void Add(params CacheDependency [] dependencies) { DateTime utcLastModified = DateTime.MinValue; if (dependencies == null) { throw new ArgumentNullException("dependencies"); } // copy array argument contents so they can't be changed beneath us dependencies = (CacheDependency []) dependencies.Clone(); // validate contents foreach (CacheDependency d in dependencies) { if (d == null) { throw new ArgumentNullException("dependencies"); } if (!d.Use()) { throw new InvalidOperationException(SR.GetString(SR.Cache_dependency_used_more_that_once)); } } // add dependencies, and check if any have changed bool hasChanged = false; lock (this) { if (!_disposed) { if (_dependencies == null) { _dependencies = new ArrayList(); } _dependencies.AddRange(dependencies); foreach (CacheDependency d in dependencies) { d.SetCacheDependencyChanged(this); if (d.UtcLastModified > utcLastModified) { utcLastModified = d.UtcLastModified; } if (d.HasChanged) { hasChanged = true; break; } } } } SetUtcLastModified(utcLastModified); // if a dependency has changed, notify others that we have changed. if (hasChanged) { NotifyDependencyChanged(this, EventArgs.Empty); } } // Dispose our dependencies. Note that the call to this // function is thread safe. protected override void DependencyDispose() { CacheDependency[] dependencies = null; lock (this) { _disposed = true; if (_dependencies != null) { dependencies = (CacheDependency[]) _dependencies.ToArray(typeof(CacheDependency)); _dependencies = null; } } if (dependencies != null) { foreach (CacheDependency d in dependencies) { d.DisposeInternal(); } } } // Forward call from the aggregate to the CacheEntry ///Initializes a new instance of the System.Web.Cache.CacheDependency class. The new instance monitors an /// array files, directories, and cache keys for changes. ///void ICacheDependencyChanged.DependencyChanged(Object sender, EventArgs e) { NotifyDependencyChanged(sender, e); } public override string GetUniqueID() { StringBuilder sb = null; CacheDependency[] dependencies = null; //VSWhidbey 354570: return null if this AggregateCacheDependency cannot otherwise return a unique ID if (_dependencies == null) { return null; } lock (this) { if (_dependencies != null) { dependencies = (CacheDependency[]) _dependencies.ToArray(typeof(CacheDependency)); } } if (dependencies != null) { foreach (CacheDependency dependency in dependencies) { string id = dependency.GetUniqueID(); if (id == null) { // When AggregateCacheDependency contains a dependency for which GetUniqueID() returns null, // it should return null itself. This is because it can no longer generate a UniqueID that // is guaranteed to be different when any of the dependencies change. return null; } if (sb == null) { sb = new StringBuilder(); } sb.Append(id); sb.Append(";"); } } return sb != null ? sb.ToString() : null; } internal CacheDependency[] GetDependencyArray() { CacheDependency[] dependencies = null; lock (this) { if (_dependencies != null) { dependencies = (CacheDependency[]) _dependencies.ToArray(typeof(CacheDependency)); } } return dependencies; } // // This will examine the dependencies and only return true if ALL dependencies are file dependencies // internal override bool IsFileDependency() { CacheDependency[] dependencies = null; dependencies = GetDependencyArray(); if (dependencies == null) { return false; } foreach (CacheDependency d in dependencies) { // We should only check if the type is either CacheDependency or the Aggregate. // Anything else, we can't guarantee that it's a file only dependency. if ( ! object.ReferenceEquals(d.GetType(), typeof(CacheDependency)) && ! object.ReferenceEquals(d.GetType(), typeof(AggregateCacheDependency)) ) { return false; } if (! d.IsFileDependency()) { return false; } } return true; } // // This method will return only the file dependencies from this dependency // internal override string[] GetFileDependencies() { ArrayList fileNames = null; CacheDependency[] dependencies = null; dependencies = GetDependencyArray(); if (dependencies == null) { return null; } foreach (CacheDependency d in dependencies) { // Check if the type is either CacheDependency or an Aggregate; // for anything else, we can't guarantee it's a file only dependency. if (object.ReferenceEquals(d.GetType(), typeof(CacheDependency)) || object.ReferenceEquals(d.GetType(), typeof(AggregateCacheDependency))) { string[] tmpFileNames = d.GetFileDependencies(); if (tmpFileNames != null) { if (fileNames == null) { fileNames = new ArrayList(); } fileNames.AddRange(tmpFileNames); } } } if (fileNames != null) { return (string[])fileNames.ToArray(typeof(string)); } else { return null; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- /* * CacheDependency.cs * * Copyright (c) 1998-1999, Microsoft Corporation * */ namespace System.Web.Caching { using System.Collections; using System.Text; using System.IO; using System.Threading; using System.Web.Util; using System.Security.Permissions; using System.Globalization; internal interface ICacheDependencyChanged { void DependencyChanged(Object sender, EventArgs e); } ////// // Overhead is 24 bytes + object header [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)] public class CacheDependency : IDisposable { #if DBG bool _isUniqueIDInitialized; #endif string _uniqueID; // used by HttpCachePolicy for the ETag object _depFileInfos; // files to monitor for changes, either a DepFileInfo or array of DepFileInfos object _entries; // cache entries we are dependent on, either a string or array of strings ICacheDependencyChanged _objNotify; // Associated object to notify when a change occurs SafeBitVector32 _bits; // status bits for ready, used, changed, disposed DateTime _utcLastModified; // Time of last modified item static readonly string[] s_stringsEmpty; static readonly CacheEntry[] s_entriesEmpty; static readonly CacheDependency s_dependencyEmpty; static readonly DepFileInfo[] s_depFileInfosEmpty; static readonly TimeSpan FUTURE_FILETIME_BUFFER = new TimeSpan(0, 1, 0); // See VSWhidbey 400917 const int BASE_INIT = 0x01; const int USED = 0x02; const int CHANGED = 0x04; const int BASE_DISPOSED = 0x08; const int WANTS_DISPOSE = 0x10; const int DERIVED_INIT = 0x20; const int DERIVED_DISPOSED = 0x40; internal class DepFileInfo { internal string _filename; internal FileAttributesData _fad; } static CacheDependency() { s_stringsEmpty = new string[0]; s_entriesEmpty = new CacheEntry[0]; s_dependencyEmpty = new CacheDependency(0); s_depFileInfosEmpty = new DepFileInfo[0]; } // creates an empty dependency which is used only by s_dependencyEmpty private CacheDependency(int bogus) { Debug.Assert(s_dependencyEmpty == null, "s_dependencyEmpty == null"); } protected CacheDependency() { Init(true, null, null, null, DateTime.MaxValue); } ///The ///class tracks cache dependencies, which can be files, /// directories, or keys to other objects in the System.Web.Cache.Cache. When an object of this class /// is constructed, it immediately begins monitoring objects on which it is /// dependent for changes. This avoids losing the changes made between the time the /// object to cache is created and the time it is inserted into the /// . /// public CacheDependency(string filename) : this (filename, DateTime.MaxValue) { } public CacheDependency(string filename, DateTime start) { if (filename == null) { return; } DateTime utcStart = DateTimeUtil.ConvertToUniversalTime(start); string[] filenames = new string[1] {filename}; Init(true, filenames, null, null, utcStart); } ///Initializes a new instance of the System.Web.Cache.CacheDependency class. The new instance /// monitors a file or directory for changes. ////// public CacheDependency(string[] filenames) { Init(true, filenames, null, null, DateTime.MaxValue); } public CacheDependency(string[] filenames, DateTime start) { DateTime utcStart = DateTimeUtil.ConvertToUniversalTime(start); Init(true, filenames, null, null, utcStart); } ///Initializes a new instance of the System.Web.Cache.CacheDependency class. The new instance monitors an array /// files or directories for changes. ////// public CacheDependency(string[] filenames, string[] cachekeys) { Init(true, filenames, cachekeys, null, DateTime.MaxValue); } public CacheDependency(string[] filenames, string[] cachekeys, DateTime start) { DateTime utcStart = DateTimeUtil.ConvertToUniversalTime(start); Init(true, filenames, cachekeys, null, utcStart); } public CacheDependency(string[] filenames, string[] cachekeys, CacheDependency dependency) { Init(true, filenames, cachekeys, dependency, DateTime.MaxValue); } public CacheDependency(string[] filenames, string[] cachekeys, CacheDependency dependency, DateTime start) { DateTime utcStart = DateTimeUtil.ConvertToUniversalTime(start); Init(true, filenames, cachekeys, dependency, utcStart); } internal CacheDependency(int dummy, string filename) : this(dummy, filename, DateTime.MaxValue) { } internal CacheDependency(int dummy, string filename, DateTime utcStart) { if (filename == null) { return; } string[] filenames = new string[1] {filename}; Init(false, filenames, null, null, utcStart); } internal CacheDependency(int dummy, string[] filenames) { Init(false, filenames, null, null, DateTime.MaxValue); } internal CacheDependency(int dummy, string[] filenames, DateTime utcStart) { Init(false, filenames, null, null, utcStart); } internal CacheDependency(int dummy, string[] filenames, string[] cachekeys) { Init(false, filenames, cachekeys, null, DateTime.MaxValue); } internal CacheDependency(int dummy, string[] filenames, string[] cachekeys, DateTime utcStart) { Init(false, filenames, cachekeys, null, utcStart); } internal CacheDependency(int dummy, string[] filenames, string[] cachekeys, CacheDependency dependency) { Init(false, filenames, cachekeys, dependency, DateTime.MaxValue); } internal CacheDependency(int dummy, string[] filenames, string[] cachekeys, CacheDependency dependency, DateTime utcStart) { Init(false, filenames, cachekeys, dependency, utcStart); } void Init(bool isPublic, string[] filenamesArg, string[] cachekeysArg, CacheDependency dependency, DateTime utcStart) { DepFileInfo[] depFileInfos = s_depFileInfosEmpty; CacheEntry[] depEntries = s_entriesEmpty; string [] filenames, cachekeys; CacheInternal cacheInternal; _bits = new SafeBitVector32(0); // copy array argument contents so they can't be changed beneath us if (filenamesArg != null) { filenames = (string []) filenamesArg.Clone(); } else { filenames = null; } if (cachekeysArg != null) { cachekeys = (string []) cachekeysArg.Clone(); } else { cachekeys = null; } _utcLastModified = DateTime.MinValue; try { // validate filenames array if (filenames == null) { filenames = s_stringsEmpty; } else { foreach (string f in filenames) { if (f == null) { throw new ArgumentNullException("filenamesArg"); } // demand PathDiscovery if public if (isPublic) { InternalSecurityPermissions.PathDiscovery(f).Demand(); } } } if (cachekeys == null) { cachekeys = s_stringsEmpty; } else { // validate cachekeys array foreach (string k in cachekeys) { if (k == null) { throw new ArgumentNullException("cachekeysArg"); } } } // copy all parts of another dependency if provided if (dependency == null) { dependency = s_dependencyEmpty; } else { if (dependency.GetType() != s_dependencyEmpty.GetType()) { throw new ArgumentException(SR.GetString(SR.Invalid_Dependency_Type)); } // Copy the parts of the dependency we need before // we reference them, as the dependency can change // underneath us. object d_depFileInfos = dependency._depFileInfos; object d_entries = dependency._entries; DateTime d_lastModified = dependency._utcLastModified; // if the dependency we're copying has changed, we're done if (dependency._bits[CHANGED]) { _bits[CHANGED] = true; // There is nothing to dispose because we haven't started // monitoring anything yet. But we call DisposeInternal in // order to set the WANTS_DISPOSE bit. DisposeInternal(); return; } // copy depFileInfos if (d_depFileInfos != null) { if (d_depFileInfos is DepFileInfo) { depFileInfos = new DepFileInfo[1] {(DepFileInfo) d_depFileInfos}; } else { depFileInfos = (DepFileInfo[]) (d_depFileInfos); } // verify that the object was fully constructed // and that we have permission to discover the file foreach (DepFileInfo depFileInfo in depFileInfos) { string f = depFileInfo._filename; if (f == null) { _bits[CHANGED] = true; // There is nothing to dispose because we haven't started // monitoring anything yet. But we call DisposeInternal in // order to set the WANTS_DISPOSE bit. DisposeInternal(); return; } // demand PathDiscovery if public if (isPublic) { InternalSecurityPermissions.PathDiscovery(f).Demand(); } } } // copy cache entries if (d_entries != null) { if (d_entries is CacheEntry) { depEntries = new CacheEntry[1] {(CacheEntry) (d_entries)}; } else { depEntries = (CacheEntry[]) (d_entries); // verify that the object was fully constructed foreach (CacheEntry entry in depEntries) { if (entry == null) { _bits[CHANGED] = true; // There is nothing to dispose because we haven't started // monitoring anything yet. But we call DisposeInternal in // order to set the WANTS_DISPOSE bit. DisposeInternal(); return; } } } } _utcLastModified = d_lastModified; } // Monitor files for changes int lenMyDepFileInfos = depFileInfos.Length + filenames.Length; if (lenMyDepFileInfos > 0) { DepFileInfo[] myDepFileInfos = new DepFileInfo[lenMyDepFileInfos]; FileChangeEventHandler handler = new FileChangeEventHandler(this.FileChange); FileChangesMonitor fmon = HttpRuntime.FileChangesMonitor; int i; for (i = 0; i < lenMyDepFileInfos; i++) { myDepFileInfos[i] = new DepFileInfo(); } // monitor files from the existing dependency // note that we don't check for start times in the existing dependency i = 0; foreach (DepFileInfo depFileInfo in depFileInfos) { string f = depFileInfo._filename; fmon.StartMonitoringPath(f, handler, out myDepFileInfos[i]._fad); myDepFileInfos[i]._filename = f; i++; } // monitor new files DateTime utcNow = DateTime.MinValue; foreach (string f in filenames) { DateTime utcLastWrite = fmon.StartMonitoringPath(f, handler, out myDepFileInfos[i]._fad); myDepFileInfos[i]._filename = f; i++; if (utcLastWrite > _utcLastModified) { _utcLastModified = utcLastWrite; } // check if file has changed since the start time if (utcStart < DateTime.MaxValue) { if (utcNow == DateTime.MinValue) { utcNow = DateTime.UtcNow; } Debug.Trace("CacheDependencyInit", "file=" + f + "; utcStart=" + utcStart + "; utcLastWrite=" + utcLastWrite); if (utcLastWrite >= utcStart && !(utcLastWrite - utcNow > FUTURE_FILETIME_BUFFER)) { // See VSWhidbey 400917 Debug.Trace("CacheDependencyInit", "changes occurred since start time for file " + f); _bits[CHANGED] = true; break; } } } if (myDepFileInfos.Length == 1) { _depFileInfos = myDepFileInfos[0]; } else { _depFileInfos = myDepFileInfos; } } // Monitor other cache entries for changes int lenMyEntries = depEntries.Length + cachekeys.Length; if (lenMyEntries > 0 && !_bits[CHANGED]) { CacheEntry[] myEntries = new CacheEntry[lenMyEntries]; // Monitor entries from the existing cache dependency int i = 0; foreach (CacheEntry entry in depEntries) { entry.AddCacheDependencyNotify(this); myEntries[i++] = entry; } // Monitor new entries specified for this depenedency // Entries must be added to cache, and created before the startTime cacheInternal = HttpRuntime.CacheInternal; foreach (string k in cachekeys) { CacheEntry entry = (CacheEntry) cacheInternal.DoGet(isPublic, k, CacheGetOptions.ReturnCacheEntry); if (entry != null) { entry.AddCacheDependencyNotify(this); myEntries[i++] = entry; if (entry.UtcCreated > _utcLastModified) { _utcLastModified = entry.UtcCreated; } if ( entry.State != CacheEntry.EntryState.AddedToCache || entry.UtcCreated > utcStart) { #if DBG if (entry.State != CacheEntry.EntryState.AddedToCache) { Debug.Trace("CacheDependencyInit", "Entry is not in cache, considered changed:" + k); } else { Debug.Trace("CacheDependencyInit", "Changes occurred to entry since start time:" + k); } #endif _bits[CHANGED] = true; break; } } else { Debug.Trace("CacheDependencyInit", "Cache item not found to create dependency on:" + k); _bits[CHANGED] = true; break; } } if (myEntries.Length == 1) { _entries = myEntries[0]; } else { _entries = myEntries; } } _bits[BASE_INIT] = true; if (dependency._bits[CHANGED]) { _bits[CHANGED] = true; } if (_bits[WANTS_DISPOSE] || _bits[CHANGED]) { DisposeInternal(); } Debug.Assert(_objNotify == null, "_objNotify == null"); } catch { // derived constructor will not execute due to the throw, // so we just force a dispose on ourselves _bits[BASE_INIT] = true; DisposeInternal(); throw; } finally { InitUniqueID(); } } public void Dispose() { // Set this bit just in case our derived ctor forgot to call FinishInit() _bits[DERIVED_INIT] = true; if (Use()) { // Do the dispose only if the cache has not already used us DisposeInternal(); } } protected internal void FinishInit() { _bits[DERIVED_INIT] = true; if (_bits[WANTS_DISPOSE]) { DisposeInternal(); } } /* * Shutdown all dependency monitoring and firing of NotifyDependencyChanged notification. */ internal void DisposeInternal() { _bits[WANTS_DISPOSE] = true; if (_bits[DERIVED_INIT]) { if (_bits.ChangeValue(DERIVED_DISPOSED, true)) { // Dispose derived classes DependencyDispose(); } } if (_bits[BASE_INIT]) { if (_bits.ChangeValue(BASE_DISPOSED, true)) { // Dispose ourself DisposeOurself(); } } } // Allow derived class to dispose itself protected virtual void DependencyDispose() { // We do our own dispose work in DisposeOurself, so that // we don't rely on derived classes calling their base // DependencyDispose for us to function correctly. } void DisposeOurself() { // guarantee that we execute only once if an exception // is thrown from this function by nulling fields before // we access them object l_depFileInfos = _depFileInfos; object l_entries = _entries; _objNotify = null; _depFileInfos = null; _entries = null; // stop monitoring files if (l_depFileInfos != null) { FileChangesMonitor fmon = HttpRuntime.FileChangesMonitor; DepFileInfo oneDepFileInfo = l_depFileInfos as DepFileInfo; if (oneDepFileInfo != null) { fmon.StopMonitoringPath(oneDepFileInfo._filename, this); } else { DepFileInfo[] depFileInfos = (DepFileInfo[]) l_depFileInfos; foreach (DepFileInfo depFileInfo in depFileInfos) { // ensure that we handle partially contructed // objects by checking filename for null string filename = depFileInfo._filename; if (filename != null) { fmon.StopMonitoringPath(filename, this); } } } } // stop monitoring cache items if (l_entries != null) { CacheEntry oneEntry = l_entries as CacheEntry; if (oneEntry != null) { oneEntry.RemoveCacheDependencyNotify(this); } else { CacheEntry[] entries = (CacheEntry[]) l_entries; foreach (CacheEntry entry in entries) { // ensure that we handle partially contructed // objects by checking entry for null if (entry != null) { entry.RemoveCacheDependencyNotify(this); } } } } } // allow the first user to declare ownership internal bool Use() { return _bits.ChangeValue(USED, true); } // // Has a dependency changed? // public bool HasChanged { get {return _bits[CHANGED];} } public DateTime UtcLastModified { get { return _utcLastModified; } } protected void SetUtcLastModified(DateTime utcLastModified) { _utcLastModified = utcLastModified; } // // Add/remove an NotifyDependencyChanged notification. // internal void SetCacheDependencyChanged(ICacheDependencyChanged objNotify) { Debug.Assert(_objNotify == null, "_objNotify == null"); // Set this bit just in case our derived ctor forgot to call FinishInit() _bits[DERIVED_INIT] = true; if (!_bits[BASE_DISPOSED]) { _objNotify = objNotify; } } internal void AppendFileUniqueId(DepFileInfo depFileInfo, StringBuilder sb) { FileAttributesData fad = depFileInfo._fad; if (fad == null) { fad = FileAttributesData.NonExistantAttributesData; } sb.Append(depFileInfo._filename); sb.Append(fad.UtcLastWriteTime.Ticks.ToString("d", NumberFormatInfo.InvariantInfo)); sb.Append(fad.FileSize.ToString(CultureInfo.InvariantCulture)); } void InitUniqueID() { StringBuilder sb = null; object l_depFileInfos, l_entries; #if !FEATURE_PAL // no File Change Monitoring // get unique id from files l_depFileInfos = _depFileInfos; if (l_depFileInfos != null) { DepFileInfo oneDepFileInfo = l_depFileInfos as DepFileInfo; if (oneDepFileInfo != null) { sb = new StringBuilder(); AppendFileUniqueId(oneDepFileInfo, sb); } else { DepFileInfo[] depFileInfos = (DepFileInfo[]) l_depFileInfos; foreach (DepFileInfo depFileInfo in depFileInfos) { // ensure that we handle partially contructed // objects by checking filename for null if (depFileInfo._filename != null) { if (sb == null) sb = new StringBuilder(); AppendFileUniqueId(depFileInfo, sb); } } } } #endif // !FEATURE_PAL // get unique id from cache entries l_entries = _entries; if (l_entries != null) { CacheEntry oneEntry = l_entries as CacheEntry; if (oneEntry != null) { if (sb == null) sb = new StringBuilder(); sb.Append(oneEntry.Key); sb.Append(oneEntry.UtcCreated.Ticks.ToString(CultureInfo.InvariantCulture)); } else { CacheEntry[] entries = (CacheEntry[]) l_entries; foreach (CacheEntry entry in entries) { // ensure that we handle partially contructed // objects by checking entry for null if (entry != null) { if (sb == null) sb = new StringBuilder(); sb.Append(entry.Key); sb.Append(entry.UtcCreated.Ticks.ToString(CultureInfo.InvariantCulture)); } } } } if (sb != null) _uniqueID = sb.ToString(); #if DBG _isUniqueIDInitialized = true; #endif } public virtual string GetUniqueID() { #if DBG Debug.Assert(_isUniqueIDInitialized == true, "_isUniqueIDInitialized == true"); #endif return _uniqueID; } // // Return the cacheEntries monitored by this dependency // internal CacheEntry[] CacheEntries { get { if (_entries == null) { return null; } CacheEntry oneEntry = _entries as CacheEntry; if (oneEntry != null) { return new CacheEntry[1] {oneEntry}; } return (CacheEntry[]) _entries; } } // // This object has changed, so fire the NotifyDependencyChanged event. // We only allow this event to be fired once. // protected void NotifyDependencyChanged(Object sender, EventArgs e) { if (_bits.ChangeValue(CHANGED, true)) { _utcLastModified = DateTime.UtcNow; ICacheDependencyChanged objNotify = _objNotify; if (objNotify != null && !_bits[BASE_DISPOSED]) { Debug.Trace("CacheDependencyNotifyDependencyChanged", "change occurred"); objNotify.DependencyChanged(sender, e); } DisposeInternal(); } } // // ItemRemoved is called when a cache entry we are monitoring has been removed. // internal void ItemRemoved() { NotifyDependencyChanged(this, EventArgs.Empty); } // // FileChange is called when a file we are monitoring has changed. // void FileChange(Object sender, FileChangeEvent e) { Debug.Trace("CacheDependencyFileChange", "FileChange file=" + e.FileName + ";Action=" + e.Action); NotifyDependencyChanged(sender, e); } // // This will examine the dependency and determine if it's ONLY a file dependency or not // internal virtual bool IsFileDependency() { object depInfos, l_entries; // Check and see if we are dependent on any cache entries l_entries = _entries; if (l_entries != null) { CacheEntry oneEntry = l_entries as CacheEntry; if (oneEntry != null) { return false; } else { CacheEntry[] entries = (CacheEntry[]) l_entries; if (entries != null && entries.Length > 0) { return false; } } } depInfos = _depFileInfos; if (depInfos != null) { DepFileInfo oneDepFileInfo = depInfos as DepFileInfo; if (oneDepFileInfo != null) { return true; } else { DepFileInfo[] depFileInfos = (DepFileInfo[]) depInfos; if (depFileInfos != null && depFileInfos.Length > 0) { return true; } } } return false; } // // This method will return only the file dependencies from this dependency // internal virtual string[] GetFileDependencies() { object depInfos = _depFileInfos; if (depInfos != null) { DepFileInfo oneDepFileInfo = depInfos as DepFileInfo; if (oneDepFileInfo != null) { return new string[] {oneDepFileInfo._filename}; } else { DepFileInfo[] depFileInfos = (DepFileInfo[]) depInfos; string[] names = new string[depFileInfos.Length]; for (int i = 0; i < depFileInfos.Length; i++) { names[i] = depFileInfos[i]._filename; } return names; } } return null; } } [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] public sealed class AggregateCacheDependency : CacheDependency, ICacheDependencyChanged { ArrayList _dependencies; bool _disposed; public AggregateCacheDependency() { // The ctor of every class derived from CacheDependency must call this. FinishInit(); } public void Add(params CacheDependency [] dependencies) { DateTime utcLastModified = DateTime.MinValue; if (dependencies == null) { throw new ArgumentNullException("dependencies"); } // copy array argument contents so they can't be changed beneath us dependencies = (CacheDependency []) dependencies.Clone(); // validate contents foreach (CacheDependency d in dependencies) { if (d == null) { throw new ArgumentNullException("dependencies"); } if (!d.Use()) { throw new InvalidOperationException(SR.GetString(SR.Cache_dependency_used_more_that_once)); } } // add dependencies, and check if any have changed bool hasChanged = false; lock (this) { if (!_disposed) { if (_dependencies == null) { _dependencies = new ArrayList(); } _dependencies.AddRange(dependencies); foreach (CacheDependency d in dependencies) { d.SetCacheDependencyChanged(this); if (d.UtcLastModified > utcLastModified) { utcLastModified = d.UtcLastModified; } if (d.HasChanged) { hasChanged = true; break; } } } } SetUtcLastModified(utcLastModified); // if a dependency has changed, notify others that we have changed. if (hasChanged) { NotifyDependencyChanged(this, EventArgs.Empty); } } // Dispose our dependencies. Note that the call to this // function is thread safe. protected override void DependencyDispose() { CacheDependency[] dependencies = null; lock (this) { _disposed = true; if (_dependencies != null) { dependencies = (CacheDependency[]) _dependencies.ToArray(typeof(CacheDependency)); _dependencies = null; } } if (dependencies != null) { foreach (CacheDependency d in dependencies) { d.DisposeInternal(); } } } // Forward call from the aggregate to the CacheEntry ///Initializes a new instance of the System.Web.Cache.CacheDependency class. The new instance monitors an /// array files, directories, and cache keys for changes. ///void ICacheDependencyChanged.DependencyChanged(Object sender, EventArgs e) { NotifyDependencyChanged(sender, e); } public override string GetUniqueID() { StringBuilder sb = null; CacheDependency[] dependencies = null; //VSWhidbey 354570: return null if this AggregateCacheDependency cannot otherwise return a unique ID if (_dependencies == null) { return null; } lock (this) { if (_dependencies != null) { dependencies = (CacheDependency[]) _dependencies.ToArray(typeof(CacheDependency)); } } if (dependencies != null) { foreach (CacheDependency dependency in dependencies) { string id = dependency.GetUniqueID(); if (id == null) { // When AggregateCacheDependency contains a dependency for which GetUniqueID() returns null, // it should return null itself. This is because it can no longer generate a UniqueID that // is guaranteed to be different when any of the dependencies change. return null; } if (sb == null) { sb = new StringBuilder(); } sb.Append(id); sb.Append(";"); } } return sb != null ? sb.ToString() : null; } internal CacheDependency[] GetDependencyArray() { CacheDependency[] dependencies = null; lock (this) { if (_dependencies != null) { dependencies = (CacheDependency[]) _dependencies.ToArray(typeof(CacheDependency)); } } return dependencies; } // // This will examine the dependencies and only return true if ALL dependencies are file dependencies // internal override bool IsFileDependency() { CacheDependency[] dependencies = null; dependencies = GetDependencyArray(); if (dependencies == null) { return false; } foreach (CacheDependency d in dependencies) { // We should only check if the type is either CacheDependency or the Aggregate. // Anything else, we can't guarantee that it's a file only dependency. if ( ! object.ReferenceEquals(d.GetType(), typeof(CacheDependency)) && ! object.ReferenceEquals(d.GetType(), typeof(AggregateCacheDependency)) ) { return false; } if (! d.IsFileDependency()) { return false; } } return true; } // // This method will return only the file dependencies from this dependency // internal override string[] GetFileDependencies() { ArrayList fileNames = null; CacheDependency[] dependencies = null; dependencies = GetDependencyArray(); if (dependencies == null) { return null; } foreach (CacheDependency d in dependencies) { // Check if the type is either CacheDependency or an Aggregate; // for anything else, we can't guarantee it's a file only dependency. if (object.ReferenceEquals(d.GetType(), typeof(CacheDependency)) || object.ReferenceEquals(d.GetType(), typeof(AggregateCacheDependency))) { string[] tmpFileNames = d.GetFileDependencies(); if (tmpFileNames != null) { if (fileNames == null) { fileNames = new ArrayList(); } fileNames.AddRange(tmpFileNames); } } } if (fileNames != null) { return (string[])fileNames.ToArray(typeof(string)); } else { return null; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DataDesignUtil.cs
- DesignBindingConverter.cs
- TriggerAction.cs
- webclient.cs
- CountdownEvent.cs
- DelayedRegex.cs
- Win32.cs
- TemplateModeChangedEventArgs.cs
- FrameworkElementFactory.cs
- X509IssuerSerialKeyIdentifierClause.cs
- SafeRightsManagementQueryHandle.cs
- MorphHelper.cs
- WmlPageAdapter.cs
- ScrollChrome.cs
- SerialPort.cs
- StructuredTypeEmitter.cs
- TimeSpanMinutesConverter.cs
- LineSegment.cs
- Substitution.cs
- ToolStripPanelRenderEventArgs.cs
- ProfilePropertySettingsCollection.cs
- HttpCacheVaryByContentEncodings.cs
- MailFileEditor.cs
- DiagnosticsConfiguration.cs
- TrackingProfileDeserializationException.cs
- IconHelper.cs
- CheckPair.cs
- BooleanKeyFrameCollection.cs
- PreDigestedSignedInfo.cs
- Mapping.cs
- Wizard.cs
- NetTcpSecurity.cs
- DynamicPropertyReader.cs
- AssemblyHash.cs
- EtwTrace.cs
- ViewCellRelation.cs
- OrderedHashRepartitionStream.cs
- CodeCatchClause.cs
- XamlTemplateSerializer.cs
- QueryCreatedEventArgs.cs
- Vector3D.cs
- HttpCachePolicy.cs
- EntityDataSourceUtil.cs
- XamlFxTrace.cs
- TaskCanceledException.cs
- RuleSettingsCollection.cs
- SqlFacetAttribute.cs
- SqlTransaction.cs
- SecondaryIndex.cs
- ContextBase.cs
- TextFormatterImp.cs
- ActivitySurrogate.cs
- SQLBytesStorage.cs
- ImageButton.cs
- DescriptionCreator.cs
- EventLogPermissionAttribute.cs
- DPTypeDescriptorContext.cs
- ScaleTransform3D.cs
- WrapPanel.cs
- SqlSelectStatement.cs
- WhitespaceRuleReader.cs
- ExceptionTrace.cs
- DesignTimeParseData.cs
- LocalizationParserHooks.cs
- VectorAnimation.cs
- WindowsFormsSectionHandler.cs
- FloaterParagraph.cs
- BCryptNative.cs
- RecognizerStateChangedEventArgs.cs
- FrameworkContentElementAutomationPeer.cs
- MarkupExtensionParser.cs
- DoubleLinkListEnumerator.cs
- UnauthorizedWebPart.cs
- PerSessionInstanceContextProvider.cs
- StandardToolWindows.cs
- HttpAsyncResult.cs
- AnimationTimeline.cs
- WpfXamlMember.cs
- XmlFormatWriterGenerator.cs
- CornerRadiusConverter.cs
- DrawListViewSubItemEventArgs.cs
- WindowsAltTab.cs
- ValueSerializer.cs
- ConfigXmlText.cs
- NavigationProgressEventArgs.cs
- Pens.cs
- SolidBrush.cs
- FixedSOMPage.cs
- ExpressionLexer.cs
- PerspectiveCamera.cs
- RecordConverter.cs
- SchemaName.cs
- SerializationFieldInfo.cs
- SchemaCollectionCompiler.cs
- WebPartZone.cs
- RuleRef.cs
- TableItemStyle.cs
- EntityReference.cs
- SafeArrayRankMismatchException.cs
- ExpressionBindings.cs