private static void OnCacheItemRemoved(string key, object value, CacheItemRemovedReason reason) { CachedPathData data = (CachedPathData)value; data._flags[0x40] = true; data.Close(); }
internal static void RemoveBadPathData(CachedPathData pathData) { CacheInternal cacheInternal = HttpRuntime.CacheInternal; string configPath = pathData._configPath; string key = CreateKey(configPath); while (((pathData != null) && !pathData.CompletedFirstRequest) && !pathData.Exists) { cacheInternal.Remove(key); configPath = System.Configuration.ConfigPathUtility.GetParent(configPath); if (configPath == null) { return; } key = CreateKey(configPath); pathData = (CachedPathData)cacheInternal.Get(key); } }
internal static void MarkCompleted(CachedPathData pathData) { CacheInternal cacheInternal = HttpRuntime.CacheInternal; string configPath = pathData._configPath; Label_000D: pathData.CompletedFirstRequest = true; configPath = System.Configuration.ConfigPathUtility.GetParent(configPath); if (configPath != null) { string key = CreateKey(configPath); pathData = (CachedPathData)cacheInternal.Get(key); if ((pathData != null) && !pathData.CompletedFirstRequest) { goto Label_000D; } } }
// Mark CachedPathData as completed when the first request for the path results in a // status outside the 400 range. We need to mark all data up the path to account for // virtual files. static internal void MarkCompleted(CachedPathData pathData) { CacheStoreProvider cacheInternal = HttpRuntime.Cache.InternalCache; string configPath = pathData._configPath; do { pathData.CompletedFirstRequest = true; configPath = ConfigPathUtility.GetParent(configPath); if (configPath == null) { break; } string key = CreateKey(configPath); pathData = (CachedPathData)cacheInternal.Get(key); } while (pathData != null && !pathData.CompletedFirstRequest); }
private void Init(CachedPathData parentData) { if (!HttpConfigurationSystem.UseHttpConfigurationSystem) { this._runtimeConfig = null; } else { IInternalConfigRecord uniqueConfigRecord = HttpConfigurationSystem.GetUniqueConfigRecord(this._configPath); if (uniqueConfigRecord.ConfigPath.Length == this._configPath.Length) { this._flags[0x10] = true; this._runtimeConfig = new System.Web.Configuration.RuntimeConfig(uniqueConfigRecord); } else { this._runtimeConfig = parentData._runtimeConfig; } } }
// Remove CachedPathData when the first request for the path results in a // 400 range error. We need to remove all data up the path to account for // virtual files. // An example of a 400 range error is "path not found". static internal void RemoveBadPathData(CachedPathData pathData) { CacheStoreProvider cacheInternal = HttpRuntime.Cache.InternalCache; string configPath = pathData._configPath; string key = CreateKey(configPath); while (pathData != null && !pathData.CompletedFirstRequest && !pathData.Exists) { cacheInternal.Remove(key); configPath = ConfigPathUtility.GetParent(configPath); if (configPath == null) { break; } key = CreateKey(configPath); pathData = (CachedPathData)cacheInternal.Get(key); } }
// Initialize the data void Init(CachedPathData parentData) { // Note that _runtimeConfig will be set to the singleton instance of ErrorRuntimeConfig // if a ThreadAbortException is thrown during this method. Debug.Assert(_runtimeConfig == RuntimeConfig.GetErrorRuntimeConfig(), "_runtimeConfig == RuntimeConfig.GetErrorRuntimeConfig()"); if (!HttpConfigurationSystem.UseHttpConfigurationSystem) { // // configRecord may legitimately be null if we are not using the HttpConfigurationSystem. // _runtimeConfig = null; } else { IInternalConfigRecord configRecord = HttpConfigurationSystem.GetUniqueConfigRecord(_configPath); Debug.Assert(configRecord != null, "configRecord != null"); if (configRecord.ConfigPath.Length == _configPath.Length) { // // The config is unique to this path, so this make this record the owner of the config. // _flags[FOwnsConfigRecord] = true; _runtimeConfig = new RuntimeConfig(configRecord); } else { // // The config record is the same as an ancestor's, so use the parent's RuntimeConfig. // Debug.Assert(parentData != null, "parentData != null"); _runtimeConfig = parentData._runtimeConfig; } } }
// Remove CachedPathData when the first request for the path results in a // 400 range error. We need to remove all data up the path to account for // virtual files. // An example of a 400 range error is "path not found". static internal void RemoveBadPathData(CachedPathData pathData) { CacheInternal cacheInternal = HttpRuntime.CacheInternal; string configPath = pathData._configPath; string key = CreateKey(configPath); while (pathData != null && !pathData.CompletedFirstRequest && !pathData.Exists) { cacheInternal.Remove(key); configPath = ConfigPathUtility.GetParent(configPath); if (configPath == null) break; key = CreateKey(configPath); pathData = (CachedPathData) cacheInternal.Get(key); } }
// Example of configPath = "machine/webroot/1/fxtest/sub/foo.aspx" // The configPath parameter must be lower case. static private CachedPathData GetConfigPathData(string configPath) { Debug.Assert(ConfigPathUtility.IsValid(configPath), "ConfigPathUtility.IsValid(configPath)"); Debug.Assert(configPath == configPath.ToLower(CultureInfo.InvariantCulture), "configPath == configPath.ToLower(CultureInfo.InvariantCulture)"); bool exists = false; bool isDirectory = false; bool isRemovable = IsCachedPathDataRemovable(configPath); // if the sliding expiration is zero, we won't cache it unless it is a configPath for root web.config or above if (isRemovable && DoNotCacheUrlMetadata) { string pathSiteID = null; VirtualPath virtualFilePath = null; string physicalFilePath = null; WebConfigurationHost.GetSiteIDAndVPathFromConfigPath(configPath, out pathSiteID, out virtualFilePath); physicalFilePath = GetPhysicalPath(virtualFilePath); string parentConfigPath = ConfigPathUtility.GetParent(configPath); CachedPathData pathParentData = GetConfigPathData(parentConfigPath); if (!String.IsNullOrEmpty(physicalFilePath)) { FileUtil.PhysicalPathStatus(physicalFilePath, false, false, out exists, out isDirectory); } CachedPathData pathData = new CachedPathData(configPath, virtualFilePath, physicalFilePath, exists); pathData.Init(pathParentData); return pathData; } // // First, see if the CachedPathData is in the cache. // we don't use Add for this lookup, as doing so requires // creating a CacheDependency, which can be slow as it may hit // the filesystem. // string key = CreateKey(configPath); CacheInternal cacheInternal = HttpRuntime.CacheInternal; CachedPathData data = (CachedPathData) cacheInternal.Get(key); // if found, return the data if (data != null) { data.WaitForInit(); return data; } // WOS bool cacheEntryIsNotRemovable = false; // if not found, try to add it string siteID = null; VirtualPath virtualPath = null; CachedPathData parentData = null; CacheDependency dependency = null; string physicalPath = null; string[] fileDependencies = null; string[] cacheItemDependencies = null; if (WebConfigurationHost.IsMachineConfigPath(configPath)) { cacheEntryIsNotRemovable = true; } else { // Make sure we have the parent data so we can create a dependency on the parent. // The parent dependency will ensure that configuration data in the parent // will be referenced by a cache hit on the child. (see UtcUpdateUsageRecursive in Cache.cs) string parentConfigPath = ConfigPathUtility.GetParent(configPath); parentData = GetConfigPathData(parentConfigPath); string parentKey = CreateKey(parentConfigPath); cacheItemDependencies = new string[1] {parentKey}; if (!WebConfigurationHost.IsVirtualPathConfigPath(configPath)) { // assume hardcoded levels above the path, such as root web.config, exist cacheEntryIsNotRemovable = true; } else { cacheEntryIsNotRemovable = !isRemovable; WebConfigurationHost.GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out virtualPath); physicalPath = GetPhysicalPath(virtualPath); // Add a dependency on the path itself, if it is a file, // to handle the case where a file is deleted and replaced // with a directory of the same name. if (!String.IsNullOrEmpty(physicalPath)) { FileUtil.PhysicalPathStatus(physicalPath, false, false, out exists, out isDirectory); if (exists && !isDirectory) { fileDependencies = new string[1] {physicalPath}; } } } try { dependency = new CacheDependency(0, fileDependencies, cacheItemDependencies); } catch { // CacheDependency ctor could fail because of bogus file path // and it is ok not to watch those } } // Try to add the CachedPathData to the cache. CachedPathData dataAdd = null; bool isDataCreator = false; bool initCompleted = false; CacheItemPriority priority = cacheEntryIsNotRemovable ? CacheItemPriority.NotRemovable : CacheItemPriority.Normal; TimeSpan slidingExpiration = cacheEntryIsNotRemovable ? Cache.NoSlidingExpiration : UrlMetadataSlidingExpiration; try { using (dependency) { dataAdd = new CachedPathData(configPath, virtualPath, physicalPath, exists); try { } finally { data = (CachedPathData) cacheInternal.UtcAdd(key, dataAdd, dependency, Cache.NoAbsoluteExpiration, slidingExpiration, priority, s_callback); if (data == null) { isDataCreator = true; } } } // If another thread added it first, return the data if (!isDataCreator) { data.WaitForInit(); return data; } // This thread is the creator of the CachedPathData, initialize it lock (dataAdd) { try { dataAdd.Init(parentData); initCompleted = true; } finally { // free waiters dataAdd._flags[FInited] = true; // Wake up waiters. Monitor.PulseAll(dataAdd); if (dataAdd._flags[FCloseNeeded]) { // If we have received a call back to close, then lets // make sure that our config object is cleaned up dataAdd.Close(); } } } } finally { // All the work in this finally block is for the case where we're the // creator of the CachedPathData. if (isDataCreator) { // if (!dataAdd._flags[FInited]) { lock (dataAdd) { // free waiters dataAdd._flags[FInited] = true; // Wake up waiters. Monitor.PulseAll(dataAdd); if (dataAdd._flags[FCloseNeeded]) { // If we have received a call back to close, then lets // make sure that our config object is cleaned up dataAdd.Close(); } } } // // Even though there is a try/catch handler surrounding the call to Init, // a ThreadAbortException can still cause the handler to be bypassed. // // If there is an error, either a thread abort or an error in the config // file itself, we do want to leave the item cached for a short period // so that we do not revisit the error and potentially reparse the config file // on every request. // // The reason we simply do not leave the item in the cache forever is that the // problem that caused the configuration exception may be fixed without touching // the config file in a way that causes a file change notification (for example, an // acl change in a parent directory, or a change of path mapping in the metabase). // // NOTE: It is important to reinsert the item into the cache AFTER dropping // the lock on dataAdd, in order to prevent the possibility of deadlock. // Debug.Assert(dataAdd._flags[FInited], "_flags[FInited]"); if (!initCompleted || (dataAdd.ConfigRecord != null && dataAdd.ConfigRecord.HasInitErrors)) { // // Create a new dependency object as the old one cannot be reused. // Do not include a file dependency if initialization could not be completed, // as invoking the file system could lead to further errors during a thread abort. // if (dependency != null) { if (!initCompleted) { dependency = new CacheDependency(0, null, cacheItemDependencies); } else { dependency = new CacheDependency(0, fileDependencies, cacheItemDependencies); } } using (dependency) { cacheInternal.UtcInsert(key, dataAdd, dependency, DateTime.UtcNow.AddSeconds(5), Cache.NoSlidingExpiration, CacheItemPriority.Normal, s_callback); } } } } return dataAdd; }
internal CachedPathData GetConfigurationPathData() { if (_configurationPath == null) { return GetFilePathData(); } // if (_configurationPathData == null) { _configurationPathData = CachedPathData.GetVirtualPathData(_configurationPath, true); } return _configurationPathData; }
internal CachedPathData GetFilePathData() { if (_filePathData == null) { _filePathData = CachedPathData.GetVirtualPathData(_request.FilePathObject, false); } return _filePathData; }
private static CachedPathData GetConfigPathData(string configPath) { bool exists = false; bool isDirectory = false; bool flag3 = IsCachedPathDataRemovable(configPath); if (flag3 && DoNotCacheUrlMetadata) { string str = null; VirtualPath path = null; string physicalPath = null; WebConfigurationHost.GetSiteIDAndVPathFromConfigPath(configPath, out str, out path); physicalPath = GetPhysicalPath(path); CachedPathData configPathData = GetConfigPathData(System.Configuration.ConfigPathUtility.GetParent(configPath)); if (!string.IsNullOrEmpty(physicalPath)) { System.Web.Util.FileUtil.PhysicalPathStatus(physicalPath, false, false, out exists, out isDirectory); } CachedPathData data2 = new CachedPathData(configPath, path, physicalPath, exists); data2.Init(configPathData); return(data2); } string key = CreateKey(configPath); CacheInternal cacheInternal = HttpRuntime.CacheInternal; CachedPathData data3 = (CachedPathData)cacheInternal.Get(key); if (data3 != null) { data3.WaitForInit(); return(data3); } bool flag4 = false; string siteID = null; VirtualPath vpath = null; CachedPathData parentData = null; CacheDependency dependencies = null; string str6 = null; string[] filenames = null; string[] cachekeys = null; if (WebConfigurationHost.IsMachineConfigPath(configPath)) { flag4 = true; } else { string parent = System.Configuration.ConfigPathUtility.GetParent(configPath); parentData = GetConfigPathData(parent); string str8 = CreateKey(parent); cachekeys = new string[] { str8 }; if (!WebConfigurationHost.IsVirtualPathConfigPath(configPath)) { flag4 = true; } else { flag4 = !flag3; WebConfigurationHost.GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out vpath); str6 = GetPhysicalPath(vpath); if (!string.IsNullOrEmpty(str6)) { System.Web.Util.FileUtil.PhysicalPathStatus(str6, false, false, out exists, out isDirectory); if (exists && !isDirectory) { filenames = new string[] { str6 }; } } } try { dependencies = new CacheDependency(0, filenames, cachekeys); } catch { } } CachedPathData data5 = null; bool flag5 = false; bool flag6 = false; CacheItemPriority priority = flag4 ? CacheItemPriority.NotRemovable : CacheItemPriority.Normal; TimeSpan slidingExpiration = flag4 ? Cache.NoSlidingExpiration : UrlMetadataSlidingExpiration; try { using (dependencies) { data5 = new CachedPathData(configPath, vpath, str6, exists); try { } finally { data3 = (CachedPathData)cacheInternal.UtcAdd(key, data5, dependencies, Cache.NoAbsoluteExpiration, slidingExpiration, priority, s_callback); if (data3 == null) { flag5 = true; } } } if (!flag5) { data3.WaitForInit(); return(data3); } lock (data5) { try { data5.Init(parentData); flag6 = true; } finally { data5._flags[1] = true; Monitor.PulseAll(data5); if (data5._flags[0x40]) { data5.Close(); } } return(data5); } } finally { if (flag5) { if (!data5._flags[1]) { lock (data5) { data5._flags[1] = true; Monitor.PulseAll(data5); if (data5._flags[0x40]) { data5.Close(); } } } if (!flag6 || ((data5.ConfigRecord != null) && data5.ConfigRecord.HasInitErrors)) { if (dependencies != null) { if (!flag6) { dependencies = new CacheDependency(0, null, cachekeys); } else { dependencies = new CacheDependency(0, filenames, cachekeys); } } using (dependencies) { cacheInternal.UtcInsert(key, data5, dependencies, DateTime.UtcNow.AddSeconds(5.0), Cache.NoSlidingExpiration, CacheItemPriority.Normal, s_callback); } } } } return(data5); }
internal CachedPathData GetConfigurationPathData() { if (this._configurationPath == null) { return this.GetFilePathData(); } if (this._configurationPathData == null) { this._configurationPathData = CachedPathData.GetVirtualPathData(this._configurationPath, true); } return this._configurationPathData; }
// Mark CachedPathData as completed when the first request for the path results in a // status outside the 400 range. We need to mark all data up the path to account for // virtual files. static internal void MarkCompleted(CachedPathData pathData) { CacheInternal cacheInternal = HttpRuntime.CacheInternal; string configPath = pathData._configPath; do { pathData.CompletedFirstRequest = true; configPath = ConfigPathUtility.GetParent(configPath); if (configPath == null) break; string key = CreateKey(configPath); pathData = (CachedPathData) cacheInternal.Get(key); } while (pathData != null && !pathData.CompletedFirstRequest); }
private static CachedPathData GetConfigPathData(string configPath) { bool exists = false; bool isDirectory = false; bool flag3 = IsCachedPathDataRemovable(configPath); if (flag3 && DoNotCacheUrlMetadata) { string str = null; VirtualPath path = null; string physicalPath = null; WebConfigurationHost.GetSiteIDAndVPathFromConfigPath(configPath, out str, out path); physicalPath = GetPhysicalPath(path); CachedPathData configPathData = GetConfigPathData(System.Configuration.ConfigPathUtility.GetParent(configPath)); if (!string.IsNullOrEmpty(physicalPath)) { System.Web.Util.FileUtil.PhysicalPathStatus(physicalPath, false, false, out exists, out isDirectory); } CachedPathData data2 = new CachedPathData(configPath, path, physicalPath, exists); data2.Init(configPathData); return data2; } string key = CreateKey(configPath); CacheInternal cacheInternal = HttpRuntime.CacheInternal; CachedPathData data3 = (CachedPathData) cacheInternal.Get(key); if (data3 != null) { data3.WaitForInit(); return data3; } bool flag4 = false; string siteID = null; VirtualPath vpath = null; CachedPathData parentData = null; CacheDependency dependencies = null; string str6 = null; string[] filenames = null; string[] cachekeys = null; if (WebConfigurationHost.IsMachineConfigPath(configPath)) { flag4 = true; } else { string parent = System.Configuration.ConfigPathUtility.GetParent(configPath); parentData = GetConfigPathData(parent); string str8 = CreateKey(parent); cachekeys = new string[] { str8 }; if (!WebConfigurationHost.IsVirtualPathConfigPath(configPath)) { flag4 = true; } else { flag4 = !flag3; WebConfigurationHost.GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out vpath); str6 = GetPhysicalPath(vpath); if (!string.IsNullOrEmpty(str6)) { System.Web.Util.FileUtil.PhysicalPathStatus(str6, false, false, out exists, out isDirectory); if (exists && !isDirectory) { filenames = new string[] { str6 }; } } } try { dependencies = new CacheDependency(0, filenames, cachekeys); } catch { } } CachedPathData data5 = null; bool flag5 = false; bool flag6 = false; CacheItemPriority priority = flag4 ? CacheItemPriority.NotRemovable : CacheItemPriority.Normal; TimeSpan slidingExpiration = flag4 ? Cache.NoSlidingExpiration : UrlMetadataSlidingExpiration; try { using (dependencies) { data5 = new CachedPathData(configPath, vpath, str6, exists); try { } finally { data3 = (CachedPathData) cacheInternal.UtcAdd(key, data5, dependencies, Cache.NoAbsoluteExpiration, slidingExpiration, priority, s_callback); if (data3 == null) { flag5 = true; } } } if (!flag5) { data3.WaitForInit(); return data3; } lock (data5) { try { data5.Init(parentData); flag6 = true; } finally { data5._flags[1] = true; Monitor.PulseAll(data5); if (data5._flags[0x40]) { data5.Close(); } } return data5; } } finally { if (flag5) { if (!data5._flags[1]) { lock (data5) { data5._flags[1] = true; Monitor.PulseAll(data5); if (data5._flags[0x40]) { data5.Close(); } } } if (!flag6 || ((data5.ConfigRecord != null) && data5.ConfigRecord.HasInitErrors)) { if (dependencies != null) { if (!flag6) { dependencies = new CacheDependency(0, null, cachekeys); } else { dependencies = new CacheDependency(0, filenames, cachekeys); } } using (dependencies) { cacheInternal.UtcInsert(key, data5, dependencies, DateTime.UtcNow.AddSeconds(5.0), Cache.NoSlidingExpiration, CacheItemPriority.Normal, s_callback); } } } } return data5; }
internal static void RemoveBadPathData(CachedPathData pathData) { CacheInternal cacheInternal = HttpRuntime.CacheInternal; string configPath = pathData._configPath; string key = CreateKey(configPath); while (((pathData != null) && !pathData.CompletedFirstRequest) && !pathData.Exists) { cacheInternal.Remove(key); configPath = System.Configuration.ConfigPathUtility.GetParent(configPath); if (configPath == null) { return; } key = CreateKey(configPath); pathData = (CachedPathData) cacheInternal.Get(key); } }
internal static void MarkCompleted(CachedPathData pathData) { CacheInternal cacheInternal = HttpRuntime.CacheInternal; string configPath = pathData._configPath; Label_000D: pathData.CompletedFirstRequest = true; configPath = System.Configuration.ConfigPathUtility.GetParent(configPath); if (configPath != null) { string key = CreateKey(configPath); pathData = (CachedPathData) cacheInternal.Get(key); if ((pathData != null) && !pathData.CompletedFirstRequest) { goto Label_000D; } } }
private void Init(CachedPathData parentData) { if (!HttpConfigurationSystem.UseHttpConfigurationSystem) { this._runtimeConfig = null; } else { IInternalConfigRecord uniqueConfigRecord = HttpConfigurationSystem.GetUniqueConfigRecord(this._configPath); if (uniqueConfigRecord.ConfigPath.Length == this._configPath.Length) { this._flags[0x10] = true; this._runtimeConfig = new System.Web.Configuration.RuntimeConfig(uniqueConfigRecord); } else { this._runtimeConfig = parentData._runtimeConfig; } } }
// Initialize the data void Init(CachedPathData parentData) { // Note that _runtimeConfig will be set to the singleton instance of ErrorRuntimeConfig // if a ThreadAbortException is thrown during this method. Debug.Assert(_runtimeConfig == RuntimeConfig.GetErrorRuntimeConfig(), "_runtimeConfig == RuntimeConfig.GetErrorRuntimeConfig()"); if (!HttpConfigurationSystem.UseHttpConfigurationSystem) { // // configRecord may legitimately be null if we are not using the HttpConfigurationSystem. // _runtimeConfig = null; } else { IInternalConfigRecord configRecord = HttpConfigurationSystem.GetUniqueConfigRecord(_configPath); Debug.Assert(configRecord != null, "configRecord != null"); if (configRecord.ConfigPath.Length == _configPath.Length) { // // The config is unique to this path, so this make this record the owner of the config. // _flags[FOwnsConfigRecord] = true; _runtimeConfig = new RuntimeConfig(configRecord); } else { // // The config record is the same as an ancestor's, so use the parent's RuntimeConfig. // Debug.Assert(parentData != null, "parentData != null"); _runtimeConfig = parentData._runtimeConfig; } } }
// Example of configPath = "machine/webroot/1/fxtest/sub/foo.aspx" // The configPath parameter must be lower case. static private CachedPathData GetConfigPathData(string configPath) { Debug.Assert(ConfigPathUtility.IsValid(configPath), "ConfigPathUtility.IsValid(configPath)"); Debug.Assert(configPath == configPath.ToLower(CultureInfo.InvariantCulture), "configPath == configPath.ToLower(CultureInfo.InvariantCulture)"); bool exists = false; bool isDirectory = false; bool isRemovable = IsCachedPathDataRemovable(configPath); // if the sliding expiration is zero, we won't cache it unless it is a configPath for root web.config or above if (isRemovable && DoNotCacheUrlMetadata) { string pathSiteID = null; VirtualPath virtualFilePath = null; string physicalFilePath = null; WebConfigurationHost.GetSiteIDAndVPathFromConfigPath(configPath, out pathSiteID, out virtualFilePath); physicalFilePath = GetPhysicalPath(virtualFilePath); string parentConfigPath = ConfigPathUtility.GetParent(configPath); CachedPathData pathParentData = GetConfigPathData(parentConfigPath); if (!String.IsNullOrEmpty(physicalFilePath)) { FileUtil.PhysicalPathStatus(physicalFilePath, false, false, out exists, out isDirectory); } CachedPathData pathData = new CachedPathData(configPath, virtualFilePath, physicalFilePath, exists); pathData.Init(pathParentData); return(pathData); } // // First, see if the CachedPathData is in the cache. // we don't use Add for this lookup, as doing so requires // creating a CacheDependency, which can be slow as it may hit // the filesystem. // string key = CreateKey(configPath); CacheStoreProvider cacheInternal = HttpRuntime.Cache.InternalCache; CachedPathData data = (CachedPathData)cacheInternal.Get(key); // if found, return the data if (data != null) { data.WaitForInit(); return(data); } // WOS bool cacheEntryIsNotRemovable = false; // if not found, try to add it string siteID = null; VirtualPath virtualPath = null; CachedPathData parentData = null; CacheDependency dependency = null; string physicalPath = null; string[] fileDependencies = null; string[] cacheItemDependencies = null; if (WebConfigurationHost.IsMachineConfigPath(configPath)) { cacheEntryIsNotRemovable = true; } else { // Make sure we have the parent data so we can create a dependency on the parent. // The parent dependency will ensure that configuration data in the parent // will be referenced by a cache hit on the child. (see UtcUpdateUsageRecursive in Cache.cs) string parentConfigPath = ConfigPathUtility.GetParent(configPath); parentData = GetConfigPathData(parentConfigPath); string parentKey = CreateKey(parentConfigPath); cacheItemDependencies = new string[1] { parentKey }; if (!WebConfigurationHost.IsVirtualPathConfigPath(configPath)) { // assume hardcoded levels above the path, such as root web.config, exist cacheEntryIsNotRemovable = true; } else { cacheEntryIsNotRemovable = !isRemovable; WebConfigurationHost.GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out virtualPath); physicalPath = GetPhysicalPath(virtualPath); // Add a dependency on the path itself, if it is a file, // to handle the case where a file is deleted and replaced // with a directory of the same name. if (!String.IsNullOrEmpty(physicalPath)) { FileUtil.PhysicalPathStatus(physicalPath, false, false, out exists, out isDirectory); if (exists && !isDirectory) { fileDependencies = new string[1] { physicalPath }; } } } try { dependency = new CacheDependency(0, fileDependencies, cacheItemDependencies); } catch { // CacheDependency ctor could fail because of bogus file path // and it is ok not to watch those } } // Try to add the CachedPathData to the cache. CachedPathData dataAdd = null; bool isDataCreator = false; bool initCompleted = false; CacheItemPriority priority = cacheEntryIsNotRemovable ? CacheItemPriority.NotRemovable : CacheItemPriority.Normal; TimeSpan slidingExpiration = cacheEntryIsNotRemovable ? Cache.NoSlidingExpiration : UrlMetadataSlidingExpiration; try { using (dependency) { dataAdd = new CachedPathData(configPath, virtualPath, physicalPath, exists); try { } finally { data = (CachedPathData)cacheInternal.Add(key, dataAdd, new CacheInsertOptions() { Dependencies = dependency, SlidingExpiration = slidingExpiration, Priority = priority, OnRemovedCallback = s_callback }); if (data == null) { isDataCreator = true; } } } // If another thread added it first, return the data if (!isDataCreator) { data.WaitForInit(); return(data); } // This thread is the creator of the CachedPathData, initialize it lock (dataAdd) { try { dataAdd.Init(parentData); initCompleted = true; } finally { // free waiters dataAdd._flags[FInited] = true; // Wake up waiters. Monitor.PulseAll(dataAdd); if (dataAdd._flags[FCloseNeeded]) { // If we have received a call back to close, then lets // make sure that our config object is cleaned up dataAdd.Close(); } } } } finally { // All the work in this finally block is for the case where we're the // creator of the CachedPathData. if (isDataCreator) { // if (!dataAdd._flags[FInited]) { lock (dataAdd) { // free waiters dataAdd._flags[FInited] = true; // Wake up waiters. Monitor.PulseAll(dataAdd); if (dataAdd._flags[FCloseNeeded]) { // If we have received a call back to close, then lets // make sure that our config object is cleaned up dataAdd.Close(); } } } // // Even though there is a try/catch handler surrounding the call to Init, // a ThreadAbortException can still cause the handler to be bypassed. // // If there is an error, either a thread abort or an error in the config // file itself, we do want to leave the item cached for a short period // so that we do not revisit the error and potentially reparse the config file // on every request. // // The reason we simply do not leave the item in the cache forever is that the // problem that caused the configuration exception may be fixed without touching // the config file in a way that causes a file change notification (for example, an // acl change in a parent directory, or a change of path mapping in the metabase). // // NOTE: It is important to reinsert the item into the cache AFTER dropping // the lock on dataAdd, in order to prevent the possibility of deadlock. // Debug.Assert(dataAdd._flags[FInited], "_flags[FInited]"); if (!initCompleted || (dataAdd.ConfigRecord != null && dataAdd.ConfigRecord.HasInitErrors)) { // // Create a new dependency object as the old one cannot be reused. // Do not include a file dependency if initialization could not be completed, // as invoking the file system could lead to further errors during a thread abort. // if (dependency != null) { if (!initCompleted) { dependency = new CacheDependency(0, null, cacheItemDependencies); } else { dependency = new CacheDependency(0, fileDependencies, cacheItemDependencies); } } using (dependency) { cacheInternal.Insert(key, dataAdd, new CacheInsertOptions() { Dependencies = dependency, AbsoluteExpiration = DateTime.UtcNow.AddSeconds(5), OnRemovedCallback = s_callback }); } } } } return(dataAdd); }