2 // System.Web.Compilation.TemplateBuildProvider
5 // Marek Habersack (mhabersack@novell.com)
7 // (C) 2007 Novell, Inc
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.CodeDom.Compiler;
34 using System.Collections;
35 using System.Collections.Generic;
37 using System.Reflection;
38 using System.Text.RegularExpressions;
40 using System.Web.Hosting;
42 using System.Web.Util;
44 namespace System.Web.Compilation
46 abstract class TemplateBuildProvider : GenericBuildProvider <TemplateParser>
48 delegate void ExtractDirectiveDependencies (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp);
50 static SortedDictionary <string, ExtractDirectiveDependencies> directiveAttributes;
51 static char[] directiveValueTrimChars = {' ', '\t', '\r', '\n', '"', '\''};
53 SortedDictionary <string, bool> dependencies;
54 string compilationLanguage;
56 internal override string LanguageName {
58 if (String.IsNullOrEmpty (compilationLanguage)) {
59 ExtractDependencies ();
60 if (String.IsNullOrEmpty (compilationLanguage))
61 compilationLanguage = base.LanguageName;
64 return compilationLanguage;
68 static TemplateBuildProvider ()
70 directiveAttributes = new SortedDictionary <string, ExtractDirectiveDependencies> (StringComparer.InvariantCultureIgnoreCase);
71 directiveAttributes.Add ("Control", ExtractControlDependencies);
72 directiveAttributes.Add ("Master", ExtractPageOrMasterDependencies);
73 directiveAttributes.Add ("MasterType", ExtractPreviousPageTypeOrMasterTypeDependencies);
74 directiveAttributes.Add ("Page", ExtractPageOrMasterDependencies);
75 directiveAttributes.Add ("PreviousPageType", ExtractPreviousPageTypeOrMasterTypeDependencies);
76 directiveAttributes.Add ("Reference", ExtractReferenceDependencies);
77 directiveAttributes.Add ("Register", ExtractRegisterDependencies);
78 directiveAttributes.Add ("WebHandler", ExtractLanguage);
79 directiveAttributes.Add ("WebService", ExtractLanguage);
82 static string ExtractDirectiveAttribute (string baseDirectory, string name, CaptureCollection names, CaptureCollection values)
84 return ExtractDirectiveAttribute (baseDirectory, name, names, values, true);
87 static string ExtractDirectiveAttribute (string baseDirectory, string name, CaptureCollection names, CaptureCollection values, bool isPath)
93 int valuesCount = values.Count;
94 foreach (Capture c in names) {
95 if (String.Compare (c.Value, name, StringComparison.OrdinalIgnoreCase) != 0) {
100 if (index > valuesCount)
104 string value = values [index].Value.Trim (directiveValueTrimChars);
105 if (String.IsNullOrEmpty (value))
108 return new VirtualPath (value, baseDirectory).Absolute;
110 return values [index].Value.Trim ();
116 static void ExtractControlDependencies (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp)
118 ExtractLanguage (baseDirectory, names, values, bp);
119 ExtractCodeBehind (baseDirectory, names, values, bp);
122 static void ExtractLanguage (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp)
124 string value = ExtractDirectiveAttribute (baseDirectory, "Language", names, values, false);
125 if (String.IsNullOrEmpty (value))
128 bp.compilationLanguage = value;
130 ExtractCodeBehind (baseDirectory, names, values, bp);
133 static void ExtractPageOrMasterDependencies (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp)
135 ExtractLanguage (baseDirectory, names, values, bp);
136 string value = ExtractDirectiveAttribute (baseDirectory, "MasterPageFile", names, values);
137 if (!String.IsNullOrEmpty (value)) {
138 if (!bp.dependencies.ContainsKey (value))
139 bp.dependencies.Add (value, true);
142 ExtractCodeBehind (baseDirectory, names, values, bp);
145 static void ExtractCodeBehind (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp)
147 string[] varray = new string [2];
149 varray [0] = ExtractDirectiveAttribute (baseDirectory, "CodeFile", names, values);
150 varray [1] = ExtractDirectiveAttribute (baseDirectory, "Src", names, values);
151 foreach (string value in varray) {
152 if (!String.IsNullOrEmpty (value)) {
153 if (!bp.dependencies.ContainsKey (value))
154 bp.dependencies.Add (value, true);
159 static void ExtractRegisterDependencies (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp)
161 string src = ExtractDirectiveAttribute (baseDirectory, "Src", names, values);
162 if (String.IsNullOrEmpty (src))
165 string value = ExtractDirectiveAttribute (baseDirectory, "TagName", names, values);
166 if (String.IsNullOrEmpty (value))
169 value = ExtractDirectiveAttribute (baseDirectory, "TagPrefix", names, values);
170 if (String.IsNullOrEmpty (value))
173 if (bp.dependencies.ContainsKey (src))
176 bp.dependencies.Add (src, true);
179 static void ExtractPreviousPageTypeOrMasterTypeDependencies (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp)
181 string value = ExtractDirectiveAttribute (baseDirectory, "VirtualPath", names, values);
182 if (String.IsNullOrEmpty (value))
185 if (bp.dependencies.ContainsKey (value))
188 bp.dependencies.Add (value, true);
191 static void ExtractReferenceDependencies (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp)
193 string control = ExtractDirectiveAttribute (baseDirectory, "Control", names, values);
194 string virtualPath = ExtractDirectiveAttribute (baseDirectory, "VirtualPath", names, values);
195 string page = ExtractDirectiveAttribute (baseDirectory, "Page", names, values);
196 bool controlEmpty = String.IsNullOrEmpty (control);
197 bool virtualPathEmpty = String.IsNullOrEmpty (virtualPath);
198 bool pageEmpty = String.IsNullOrEmpty (page);
200 if (controlEmpty && virtualPathEmpty && pageEmpty)
203 if ((controlEmpty ? 1 : 0) + (virtualPathEmpty ? 1 : 0) + (pageEmpty ? 1 : 0) != 2)
209 else if (!virtualPathEmpty)
214 if (bp.dependencies.ContainsKey (value))
217 bp.dependencies.Add (value, true);
220 IDictionary <string, bool> AddParsedDependencies (IDictionary <string, bool> dict)
223 ArrayList deps = Parser.Dependencies;
224 if (deps == null || deps.Count > 0)
230 dict = dependencies = new SortedDictionary <string, bool> (StringComparer.InvariantCultureIgnoreCase);
234 foreach (object o in deps) {
236 if (s == null || dict.ContainsKey (s))
242 if (dict == null || dict.Count == 0)
248 internal override IDictionary <string, bool> ExtractDependencies ()
250 if (dependencies != null)
251 return AddParsedDependencies (dependencies);
253 string vpath = VirtualPath;
254 if (String.IsNullOrEmpty (vpath))
255 return AddParsedDependencies (null);
257 VirtualPathProvider vpp = HostingEnvironment.VirtualPathProvider;
258 if (!vpp.FileExists (vpath))
259 return AddParsedDependencies (null);
261 VirtualFile vf = vpp.GetFile (vpath);
263 return AddParsedDependencies (null);
266 using (Stream st = vf.Open ()) {
267 if (st == null || !st.CanRead)
268 return AddParsedDependencies (null);
270 using (StreamReader sr = new StreamReader (st, WebEncoding.FileEncoding)) {
271 input = sr.ReadToEnd ();
275 if (String.IsNullOrEmpty (input))
276 return AddParsedDependencies (null);
278 MatchCollection matches = AspGenerator.DirectiveRegex.Matches (input);
279 if (matches == null || matches.Count == 0)
280 return AddParsedDependencies (null);
282 dependencies = new SortedDictionary <string, bool> (StringComparer.InvariantCultureIgnoreCase);
283 CaptureCollection ccNames;
284 GroupCollection groups;
285 string directiveName;
286 ExtractDirectiveDependencies edd;
287 string baseDirectory = VirtualPathUtility.GetDirectory (vpath);
289 foreach (Match match in matches) {
290 groups = match.Groups;
291 if (groups.Count < 6)
294 ccNames = groups [3].Captures;
295 directiveName = ccNames [0].Value;
296 if (!directiveAttributes.TryGetValue (directiveName, out edd))
298 edd (baseDirectory, ccNames, groups [5].Captures, this);
301 return AddParsedDependencies (dependencies);
304 protected override string GetClassType (BaseCompiler compiler, TemplateParser parser)
306 if (compiler != null)
307 return compiler.MainClassType;
312 protected override ICollection GetParserDependencies (TemplateParser parser)
315 return parser.Dependencies;
320 protected override string GetParserLanguage (TemplateParser parser)
323 return parser.Language;
328 protected override string GetCodeBehindSource (TemplateParser parser)
330 if (parser != null) {
331 string codeBehind = parser.CodeBehindSource;
332 if (String.IsNullOrEmpty (codeBehind))
335 return parser.CodeBehindSource;
341 protected override AspGenerator CreateAspGenerator (TemplateParser parser)
344 return new AspGenerator (parser);
349 protected override List <string> GetReferencedAssemblies (TemplateParser parser)
354 ArrayList al = parser.Assemblies;
355 if (al == null || al.Count == 0)
358 List <string> ret = new List <string> ();
361 foreach (object o in al) {
366 if (ret.Contains (loc))