1 using System.Collections;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Linq.Expressions;
5 using System.Text;
6 using System.Web.UI;
7 using System.Web.UI.WebControls;
8 using System.Collections.Specialized;
9 using System.Diagnostics;
10 using System.Web.Resources;
11 using System.Globalization;
12 using System.Web.Caching;
13 using System.Web.Hosting;
14 
15 namespace System.Web.DynamicData {
FileChangedCallback(string path)16     delegate void FileChangedCallback(string path);
17 
18     class FileChangeNotifier {
19         private static VirtualPathProvider _vpp;
20 
21         internal static VirtualPathProvider VirtualPathProvider {
22             private get {
23                 if (_vpp == null) {
24                     _vpp = HostingEnvironment.VirtualPathProvider;
25                 }
26                 return _vpp;
27             }
28             // For unit test purpose
29             set {
30                 _vpp = value;
31             }
32         }
33 
34         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults",
35             MessageId = "System.Web.DynamicData.FileChangeNotifier",
36             Justification="The object deals with file change notifications and we don't need to hold on to it")]
Register(string virtualPath, FileChangedCallback onFileChanged)37         internal static void Register(string virtualPath, FileChangedCallback onFileChanged) {
38             new FileChangeNotifier(virtualPath, onFileChanged);
39         }
40 
41         private FileChangedCallback _onFileChanged;
42 
FileChangeNotifier(string virtualPath, FileChangedCallback onFileChanged)43         private FileChangeNotifier(string virtualPath, FileChangedCallback onFileChanged) {
44             _onFileChanged = onFileChanged;
45             RegisterForNextNotification(virtualPath);
46         }
47 
RegisterForNextNotification(string virtualPath)48         private void RegisterForNextNotification(string virtualPath) {
49             // Get a CacheDependency from the BuildProvider, so that we know anytime something changes
50             var virtualPathDependencies = new List<string>();
51             virtualPathDependencies.Add(virtualPath);
52             CacheDependency cacheDependency = VirtualPathProvider.GetCacheDependency(
53                 virtualPath, virtualPathDependencies, DateTime.UtcNow);
54 
55             // Rely on the ASP.NET cache for file change notifications, since FileSystemWatcher
56             // doesn't work in medium trust
57             HttpRuntime.Cache.Insert(virtualPath /*key*/, virtualPath /*value*/, cacheDependency,
58                 Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
59                 CacheItemPriority.NotRemovable, new CacheItemRemovedCallback(OnCacheItemRemoved));
60         }
61 
OnCacheItemRemoved(string key, object value, CacheItemRemovedReason reason)62         private void OnCacheItemRemoved(string key, object value, CacheItemRemovedReason reason) {
63 
64             // We only care about dependency changes
65             if (reason != CacheItemRemovedReason.DependencyChanged)
66                 return;
67 
68             _onFileChanged(key);
69 
70             // We need to register again to get the next notification
71             RegisterForNextNotification(key);
72         }
73     }
74 }
75 
76