private void RemoveConfigImpl(string configPath, BaseConfigurationRecord configRecord)
        {
            BaseConfigurationRecord record;

            if (!ConfigPathUtility.IsValid(configPath))
            {
                throw ExceptionUtil.ParameterInvalid("configPath");
            }
            string[] parts = ConfigPathUtility.GetParts(configPath);
            try
            {
                int num;
                this.AcquireHierarchyLockForWrite();
                this.hlFindConfigRecord(parts, out num, out record);
                if ((num != parts.Length) || ((configRecord != null) && !object.ReferenceEquals(configRecord, record)))
                {
                    return;
                }
                record.Parent.hlRemoveChild(parts[parts.Length - 1]);
            }
            finally
            {
                this.ReleaseHierarchyLockForWrite();
            }
            this.OnConfigRemoved(new InternalConfigEventArgs(configPath));
            record.CloseRecursive();
        }
        public IInternalConfigRecord GetConfigRecord(string configPath)
        {
            IInternalConfigRecord record4;

            if (!ConfigPathUtility.IsValid(configPath))
            {
                throw ExceptionUtil.ParameterInvalid("configPath");
            }
            string[] parts = ConfigPathUtility.GetParts(configPath);
            try
            {
                int num;
                BaseConfigurationRecord record;
                this.AcquireHierarchyLockForRead();
                this.hlFindConfigRecord(parts, out num, out record);
                if ((num == parts.Length) || !record.hlNeedsChildFor(parts[num]))
                {
                    return(record);
                }
            }
            finally
            {
                this.ReleaseHierarchyLockForRead();
            }
            try
            {
                int num2;
                BaseConfigurationRecord record2;
                this.AcquireHierarchyLockForWrite();
                this.hlFindConfigRecord(parts, out num2, out record2);
                if (num2 == parts.Length)
                {
                    return(record2);
                }
                string parentConfigPath = string.Join("/", parts, 0, num2);
                while ((num2 < parts.Length) && record2.hlNeedsChildFor(parts[num2]))
                {
                    BaseConfigurationRecord record3;
                    string childConfigPath = parts[num2];
                    parentConfigPath = ConfigPathUtility.Combine(parentConfigPath, childConfigPath);
                    if (this._isDesignTime)
                    {
                        record3 = MgmtConfigurationRecord.Create(this, record2, parentConfigPath, null);
                    }
                    else
                    {
                        record3 = (BaseConfigurationRecord)RuntimeConfigurationRecord.Create(this, record2, parentConfigPath);
                    }
                    record2.hlAddChild(childConfigPath, record3);
                    num2++;
                    record2 = record3;
                }
                record4 = record2;
            }
            finally
            {
                this.ReleaseHierarchyLockForWrite();
            }
            return(record4);
        }
 public void ClearResult(BaseConfigurationRecord configRecord, string configKey, bool forceEvaluation)
 {
     string[] parts = ConfigPathUtility.GetParts(configRecord.ConfigPath);
     try
     {
         int num;
         BaseConfigurationRecord record;
         this.AcquireHierarchyLockForRead();
         this.hlFindConfigRecord(parts, out num, out record);
         if ((num == parts.Length) && object.ReferenceEquals(configRecord, record))
         {
             record.hlClearResultRecursive(configKey, forceEvaluation);
         }
     }
     finally
     {
         this.ReleaseHierarchyLockForRead();
     }
 }
示例#4
0
        // 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);
        }
示例#5
0
        // 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);
            }
        }
示例#6
0
        //
        // Clear the result of a configSection evaluation at a particular point
        // in the hierarchy.
        //
        public void ClearResult(BaseConfigurationRecord configRecord, string configKey, bool forceEvaluation)
        {
            string[] parts = ConfigPathUtility.GetParts(configRecord.ConfigPath);

            try {
                int index;
                BaseConfigurationRecord currentRecord;

                AcquireHierarchyLockForRead();

                hlFindConfigRecord(parts, out index, out currentRecord);

                // clear result only if configRecord it is still in the hierarchy
                if (index == parts.Length && Object.ReferenceEquals(configRecord, currentRecord))
                {
                    currentRecord.hlClearResultRecursive(configKey, forceEvaluation);
                }
            }
            finally {
                ReleaseHierarchyLockForRead();
            }
        }
示例#7
0
        // Find and remove the config record and all its children for the config path.
        // Optionally ensure the config record matches a desired config record.
        private void RemoveConfigImpl(string configPath, BaseConfigurationRecord configRecord)
        {
            if (!ConfigPathUtility.IsValid(configPath))
            {
                throw ExceptionUtil.ParameterInvalid("configPath");
            }

            string[] parts = ConfigPathUtility.GetParts(configPath);

            BaseConfigurationRecord currentRecord;

            // search under exclusive writer lock
            try
            {
                int index;

                AcquireHierarchyLockForWrite();

                HlFindConfigRecord(parts, out index, out currentRecord);

                // Return if not found, or does not match the one we are trying to remove.
                if ((index != parts.Length) || ((configRecord != null) && !ReferenceEquals(configRecord, currentRecord)))
                {
                    return;
                }

                // Remove it from the hierarchy.
                currentRecord.Parent.HlRemoveChild(parts[parts.Length - 1]);
            }
            finally
            {
                ReleaseHierarchyLockForWrite();
            }

            OnConfigRemoved(new InternalConfigEventArgs(configPath));

            // Close the record. This is safe to do outside the lock.
            currentRecord.CloseRecursive();
        }
 public void GetName(string configPath, string expected)
 {
     Assert.Equal(expected, ConfigPathUtility.GetName(configPath));
 }
 public void GetParts(string configPath, string[] expected)
 {
     Assert.Equal(expected, ConfigPathUtility.GetParts(configPath));
 }
示例#10
0
 public void Combine(string parentConfigPath, string childConfigPath, string expected)
 {
     Assert.Equal(expected, ConfigPathUtility.Combine(parentConfigPath, childConfigPath));
 }
示例#11
0
 public void IsValid(string configPath, bool expected)
 {
     Assert.Equal(expected, ConfigPathUtility.IsValid(configPath));
 }
示例#12
0
        //
        // Get the config record for a path.
        // If the record does not exist, create it if it is needed.
        //
        public IInternalConfigRecord GetConfigRecord(string configPath)
        {
            if (!ConfigPathUtility.IsValid(configPath))
            {
                throw ExceptionUtil.ParameterInvalid("configPath");
            }

            string[] parts = ConfigPathUtility.GetParts(configPath);

            //
            // First search under the reader lock, so that multiple searches
            // can proceed in parallel.
            //
            try {
                int index;
                BaseConfigurationRecord currentRecord;

                AcquireHierarchyLockForRead();

                hlFindConfigRecord(parts, out index, out currentRecord);

                // check if found
                if (index == parts.Length || !currentRecord.hlNeedsChildFor(parts[index]))
                {
                    return(currentRecord);
                }
            }
            finally {
                ReleaseHierarchyLockForRead();
            }

            //
            // Not found, so search again under exclusive writer lock so that
            // we can create the record.
            //
            try {
                int index;
                BaseConfigurationRecord currentRecord;

                AcquireHierarchyLockForWrite();

                hlFindConfigRecord(parts, out index, out currentRecord);

                if (index == parts.Length)
                {
                    return(currentRecord);
                }

                string currentConfigPath = String.Join(BaseConfigurationRecord.ConfigPathSeparatorString, parts, 0, index);

                //
                // create new records
                //

                while (index < parts.Length && currentRecord.hlNeedsChildFor(parts[index]))
                {
                    string configName = parts[index];
                    currentConfigPath = ConfigPathUtility.Combine(currentConfigPath, configName);
                    BaseConfigurationRecord childRecord;

                    Debug.Trace("ConfigurationCreate", "Creating config record for " + currentConfigPath);
                    if (_isDesignTime)
                    {
                        childRecord = MgmtConfigurationRecord.Create(this, currentRecord, currentConfigPath, null);
                    }
                    else
                    {
                        childRecord = (BaseConfigurationRecord)RuntimeConfigurationRecord.Create(this, currentRecord, currentConfigPath);
                    }

                    currentRecord.hlAddChild(configName, childRecord);

                    index++;
                    currentRecord = childRecord;
                }

                return(currentRecord);
            }
            finally {
                ReleaseHierarchyLockForWrite();
            }
        }
示例#13
0
        // 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);
        }