File: TemplateFactory.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (153 lines) | stat: -rw-r--r-- 5,981 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Web.Compilation;
using System.Web.Hosting;
using System.Web.Resources;

namespace System.Web.DynamicData {
    internal class TemplateFactory {
        // Use Hashtable instead of Dictionary<,> because it is more thread safe
        private Hashtable _fieldTemplateVirtualPathCache = new Hashtable();

        private string _defaultLocation;
        private string _templateFolderVirtualPath;

        internal MetaModel Model { get; set; }

        private bool _needToResolveVirtualPath;
        private bool _trackFolderChanges;
        private bool _registeredForChangeNotifications;

        private VirtualPathProvider _vpp;
        private bool _usingCustomVpp;

        internal TemplateFactory(string defaultLocation)
            : this(defaultLocation, true) {
        }

        internal TemplateFactory(string defaultLocation, bool trackFolderChanges) {
            Debug.Assert(!String.IsNullOrEmpty(defaultLocation));
            _defaultLocation = defaultLocation;
            _trackFolderChanges = trackFolderChanges;
        }

        internal string TemplateFolderVirtualPath {
            get {
                if (_templateFolderVirtualPath == null) {
                    // If not set, set its default location
                    TemplateFolderVirtualPath = _defaultLocation;
                }

                if (_needToResolveVirtualPath) {
                    // Make sure it ends with a slash
                    _templateFolderVirtualPath = VirtualPathUtility.AppendTrailingSlash(_templateFolderVirtualPath);

                    // If it's relative, make it relative to the Model's path
                    // Note can be null under Unit Testing
                    if (Model != null) {
                        _templateFolderVirtualPath = VirtualPathUtility.Combine(Model.DynamicDataFolderVirtualPath, _templateFolderVirtualPath);
                    }

                    _needToResolveVirtualPath = false;
                }

                return _templateFolderVirtualPath;
            }
            set {
                _templateFolderVirtualPath = value;

                // Make sure we register for change notifications, since we just got a new path
                _registeredForChangeNotifications = false;

                // It may be relative and need resolution, but let's not do it until we need it
                _needToResolveVirtualPath = true;
            }
        }

        internal VirtualPathProvider VirtualPathProvider {
            get {
                if (_vpp == null) {
                    _vpp = HostingEnvironment.VirtualPathProvider;
                }
                return _vpp;
            }
            set {
                _vpp = value;
                _usingCustomVpp = value != null;
            }
        }

        internal string GetTemplatePath(long cacheKey, Func<string> templatePathFactoryFunction) {
            // Check if we already have it cached
            string virtualPath = this[cacheKey];

            // null is a valid value, so we also need to check whether the key exists
            if (virtualPath == null && !ContainsKey(cacheKey)) {
                // It's not cached, so compute it and cache it.  Make sure multiple writers are serialized
                virtualPath = templatePathFactoryFunction();
                this[cacheKey] = virtualPath;
            }

            return virtualPath;
        }

        private string this[long cacheKey] {
            get {
                EnsureRegisteredForChangeNotifications();
                return (string)_fieldTemplateVirtualPathCache[cacheKey];
            }
            set {
                EnsureRegisteredForChangeNotifications();
                lock (_fieldTemplateVirtualPathCache) {
                    _fieldTemplateVirtualPathCache[cacheKey] = value;
                }
            }
        }

        private bool ContainsKey(long cacheKey) {
            EnsureRegisteredForChangeNotifications();
            return _fieldTemplateVirtualPathCache.ContainsKey(cacheKey);
        }

        private void EnsureRegisteredForChangeNotifications() {
            if (!_trackFolderChanges) {
                return;
            }

            if (!_registeredForChangeNotifications) {
                lock (this) {
                    if (!_registeredForChangeNotifications) {
                        // Make sure the folder exists
                        if (!VirtualPathProvider.DirectoryExists(TemplateFolderVirtualPath)) {
                            throw new InvalidOperationException(String.Format(
                                CultureInfo.CurrentCulture,
                                DynamicDataResources.FieldTemplateFactory_FolderNotFound,
                                TemplateFolderVirtualPath));
                        }

                        // Register for notifications if anything in that folder changes
                        FileChangeNotifier.Register(TemplateFolderVirtualPath, delegate(string path) {
                            // Something has changed, so clear our cache
                            lock (_fieldTemplateVirtualPathCache) {
                                _fieldTemplateVirtualPathCache.Clear();
                            }
                        });

                        _registeredForChangeNotifications = true;
                    }
                }
            }
        }

        internal bool FileExists(string virtualPath) {
            if (_usingCustomVpp) {
                // for unit testing
                return VirtualPathProvider.FileExists(virtualPath);
            } else {
                // Use GetObjectFactory instead of GetCompiledType because it will not throw, which improves the debugging experience
                return BuildManager.GetObjectFactory(virtualPath, /* throwIfNotFound */ false) != null;
            }
        }
    }
}