File: Hosting\ObjectCacheHost.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
// <copyright file="ObjectCacheHost.cs" company="Microsoft">
//   Copyright (c) 2009 Microsoft Corporation.  All rights reserved.
// </copyright>
 
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Caching;
using System.Runtime.Caching.Hosting;
using System.Web.Util;
 
namespace System.Web.Hosting {
    [SuppressMessage("Microsoft.Usage", "CA2302:FlagServiceProviders", Justification = "Internal class")]
    internal sealed class ObjectCacheHost : IServiceProvider, IApplicationIdentifier, IFileChangeNotificationSystem, IMemoryCacheManager
    {
 
        private Object _lock = new Object();
        private Dictionary<MemoryCache, MemoryCacheInfo> _cacheInfos;
 
        internal sealed class FileChangeEventTarget {
            private OnChangedCallback _onChangedCallback;
            private FileChangeEventHandler _handler;
 
            private void OnChanged(Object sender, FileChangeEvent e) {
                _onChangedCallback(null);
            }
            
            internal FileChangeEventHandler Handler { get { return _handler; } }
 
            internal FileChangeEventTarget(OnChangedCallback onChangedCallback) {
                _onChangedCallback = onChangedCallback;
                _handler = new FileChangeEventHandler(this.OnChanged);
            }
        }
        
        internal sealed class MemoryCacheInfo {
            internal MemoryCache Cache;
            internal long Size;
        }
 
        Object IServiceProvider.GetService(Type service) {
            if (service == typeof(IFileChangeNotificationSystem)) {
                return this as IFileChangeNotificationSystem;
            }
            else if (service == typeof(IMemoryCacheManager)) {
                return this as IMemoryCacheManager;
            }
            else if (service == typeof(IApplicationIdentifier)) {
                return this as IApplicationIdentifier;
            }
            else {
                return null;
            }
        }
 
        String IApplicationIdentifier.GetApplicationId() {
            return HttpRuntime.AppDomainAppId;
        }
 
        void IFileChangeNotificationSystem.StartMonitoring(string filePath, OnChangedCallback onChangedCallback, out Object state, out DateTimeOffset lastWrite, out long fileSize) {
            if (filePath == null) {
                throw new ArgumentNullException("filePath");
            }
            if (onChangedCallback == null) {
                throw new ArgumentNullException("onChangedCallback");
            }
            FileChangeEventTarget target = new FileChangeEventTarget(onChangedCallback);
            FileAttributesData fad;
            HttpRuntime.FileChangesMonitor.StartMonitoringPath(filePath, target.Handler, out fad);
            if (fad == null) {
                fad = FileAttributesData.NonExistantAttributesData;
            }
            state = target;
#if DBG            
            Debug.Assert(fad.UtcLastWriteTime.Kind == DateTimeKind.Utc, "fad.UtcLastWriteTime.Kind == DateTimeKind.Utc");
#endif
            lastWrite = fad.UtcLastWriteTime;
            fileSize = fad.FileSize;
        }
 
        void IFileChangeNotificationSystem.StopMonitoring(string filePath, Object state) {
            if (filePath == null) {
                throw new ArgumentNullException("filePath");
            }
            if (state == null) {
                throw new ArgumentNullException("state");
            }
            HttpRuntime.FileChangesMonitor.StopMonitoringPath(filePath, state);
        }
 
        void IMemoryCacheManager.ReleaseCache(MemoryCache memoryCache) {
            if (memoryCache == null) {
                throw new ArgumentNullException("memoryCache");
            }
            lock (_lock) {
                if (_cacheInfos != null) {
                    MemoryCacheInfo info = null;
                    if (_cacheInfos.TryGetValue(memoryCache, out info)) {
                        _cacheInfos.Remove(memoryCache);
                    }
                }
            }
        }
 
        void IMemoryCacheManager.UpdateCacheSize(long size, MemoryCache memoryCache) {
            if (memoryCache == null) {
                throw new ArgumentNullException("memoryCache");
            }
            lock (_lock) {
                if (_cacheInfos == null) {
                    _cacheInfos = new Dictionary<MemoryCache, MemoryCacheInfo>();
                }
                MemoryCacheInfo info = null;
                if (!_cacheInfos.TryGetValue(memoryCache, out info)) {
                    info = new MemoryCacheInfo();
                    info.Cache = memoryCache;
                    _cacheInfos[memoryCache] = info;
                }
                info.Size = size;
            }
        }
 
        internal long TrimCache(int percent) {
            long trimmedOrExpired = 0;
            MemoryCache[] caches = null;
            lock (_lock) {
                if (_cacheInfos != null && _cacheInfos.Count > 0) {
                    caches = new MemoryCache[_cacheInfos.Keys.Count];
                    _cacheInfos.Keys.CopyTo(caches, 0);
                }
            }
            if (caches != null) {
                foreach (MemoryCache cache in caches) {
                    trimmedOrExpired += cache.Trim(percent);
                }
            }
            return trimmedOrExpired;
        }
    }
}