2 // System.Web.UI.TemplateParser
5 // Duncan Mak (duncan@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // (C) 2002,2003 Ximian, Inc. (http://www.ximian.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.CodeDom.Compiler;
33 using System.Collections;
35 using System.Reflection;
37 using System.Web.Compilation;
38 using System.Web.Configuration;
39 using System.Web.Util;
41 namespace System.Web.UI
43 public abstract class TemplateParser : BaseParser
47 string privateBinPath;
48 Hashtable mainAttributes;
49 ArrayList dependencies;
57 RootBuilder rootBuilder;
59 string compilerOptions;
61 bool strictOn = false;
62 bool explicitOn = false;
65 string oc_header, oc_custom, oc_param, oc_controls;
67 OutputCacheLocation oc_location;
69 int appAssemblyIndex = -1;
71 internal TemplateParser ()
73 imports = new ArrayList ();
74 imports.Add ("System");
75 imports.Add ("System.Collections");
76 imports.Add ("System.Collections.Specialized");
77 imports.Add ("System.Configuration");
78 imports.Add ("System.Text");
79 imports.Add ("System.Text.RegularExpressions");
80 imports.Add ("System.Web");
81 imports.Add ("System.Web.Caching");
82 imports.Add ("System.Web.Security");
83 imports.Add ("System.Web.SessionState");
84 imports.Add ("System.Web.UI");
85 imports.Add ("System.Web.UI.WebControls");
86 imports.Add ("System.Web.UI.HtmlControls");
88 assemblies = new ArrayList ();
89 foreach (string a in CompilationConfig.Assemblies)
90 AddAssemblyByName (a);
91 if (CompilationConfig.AssembliesInBin)
92 AddAssembliesInBin ();
94 language = CompilationConfig.DefaultLanguage;
97 internal void AddApplicationAssembly ()
99 string location = Context.ApplicationInstance.AssemblyLocation;
100 if (location != typeof (TemplateParser).Assembly.Location) {
101 appAssemblyIndex = assemblies.Add (location);
105 protected abstract Type CompileIntoType ();
107 internal virtual void HandleOptions (object obj)
111 internal static string GetOneKey (Hashtable tbl)
113 foreach (object key in tbl.Keys)
114 return key.ToString ();
119 internal virtual void AddDirective (string directive, Hashtable atts)
121 if (String.Compare (directive, DefaultDirectiveName, true) == 0) {
122 if (mainAttributes != null)
123 ThrowParseException ("Only 1 " + DefaultDirectiveName + " is allowed");
125 mainAttributes = atts;
126 ProcessMainAttributes (mainAttributes);
130 int cmp = String.Compare ("Assembly", directive, true);
132 string name = GetString (atts, "Name", null);
133 string src = GetString (atts, "Src", null);
136 ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
138 if (name == null && src == null)
139 ThrowParseException ("You gotta specify Src or Name");
141 if (name != null && src != null)
142 ThrowParseException ("Src and Name cannot be used together");
145 AddAssemblyByName (name);
147 GetAssemblyFromSource (src);
153 cmp = String.Compare ("Import", directive, true);
155 string namesp = GetString (atts, "Namespace", null);
157 ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
159 if (namesp != null && namesp != "")
164 cmp = String.Compare ("Implements", directive, true);
166 string ifacename = GetString (atts, "Interface", "");
169 ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
171 Type iface = LoadType (ifacename);
173 ThrowParseException ("Cannot find type " + ifacename);
175 if (!iface.IsInterface)
176 ThrowParseException (iface + " is not an interface");
178 AddInterface (iface.FullName);
182 cmp = String.Compare ("OutputCache", directive, true);
186 if (atts ["Duration"] == null)
187 ThrowParseException ("The directive is missing a 'duration' attribute.");
188 if (atts ["VaryByParam"] == null)
189 ThrowParseException ("This directive is missing a 'VaryByParam' " +
190 "attribute, which should be set to \"none\", \"*\", " +
191 "or a list of name/value pairs.");
193 foreach (DictionaryEntry entry in atts) {
194 string key = (string) entry.Key;
195 switch (key.ToLower ()) {
197 oc_duration = Int32.Parse ((string) entry.Value);
199 ThrowParseException ("The 'duration' attribute must be set " +
200 "to a positive integer value");
203 oc_param = (string) entry.Value;
204 if (String.Compare (oc_param, "none") == 0)
208 oc_header = (string) entry.Value;
211 oc_custom = (string) entry.Value;
214 if (!(this is PageParser))
218 oc_location = (OutputCacheLocation) Enum.Parse (
219 typeof (OutputCacheLocation), (string) entry.Value, true);
221 ThrowParseException ("The 'location' attribute is case sensitive and " +
222 "must be one of the following values: Any, Client, " +
223 "Downstream, Server, None, ServerAndClient.");
226 case "varybycontrol":
227 if (this is PageParser)
230 oc_controls = (string) entry.Value;
233 if (this is PageParser)
237 oc_shared = Boolean.Parse ((string) entry.Value);
239 ThrowParseException ("The 'shared' attribute is case sensitive" +
240 " and must be set to 'true' or 'false'.");
244 ThrowParseException ("The '" + key + "' attribute is not " +
245 "supported by the 'Outputcache' directive.");
254 ThrowParseException ("Unknown directive: " + directive);
257 internal Type LoadType (string typeName)
259 // First try loaded assemblies, then try assemblies in Bin directory.
261 bool seenBin = false;
262 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
263 foreach (Assembly ass in assemblies) {
264 type = ass.GetType (typeName);
268 if (Path.GetDirectoryName (ass.Location) != PrivateBinPath) {
269 AddAssembly (ass, true);
274 AddDependency (ass.Location);
282 if (!Directory.Exists (PrivateBinPath))
285 string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
286 foreach (string s in binDlls) {
287 Assembly binA = Assembly.LoadFrom (s);
288 type = binA.GetType (typeName);
292 AddDependency (binA.Location);
299 void AddAssembliesInBin ()
301 if (!Directory.Exists (PrivateBinPath))
304 string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
305 foreach (string s in binDlls) {
310 internal virtual void AddInterface (string iface)
312 if (interfaces == null)
313 interfaces = new ArrayList ();
315 if (!interfaces.Contains (iface))
316 interfaces.Add (iface);
319 internal virtual void AddImport (string namesp)
322 imports = new ArrayList ();
324 if (!imports.Contains (namesp))
325 imports.Add (namesp);
328 internal virtual void AddSourceDependency (string filename)
330 if (dependencies != null && dependencies.Contains (filename)) {
331 ThrowParseException ("Circular file references are not allowed. File: " + filename);
334 AddDependency (filename);
337 internal virtual void AddDependency (string filename)
342 if (dependencies == null)
343 dependencies = new ArrayList ();
345 if (!dependencies.Contains (filename))
346 dependencies.Add (filename);
349 internal virtual void AddAssembly (Assembly assembly, bool fullPath)
351 if (assembly.Location == "")
355 anames = new Hashtable ();
357 string name = assembly.GetName ().Name;
358 string loc = assembly.Location;
360 if (!assemblies.Contains (loc)) {
361 assemblies.Add (loc);
365 anames [loc] = assembly;
367 if (!assemblies.Contains (name)) {
368 assemblies.Add (name);
371 anames [name] = assembly;
375 internal virtual Assembly AddAssemblyByName (string name)
378 anames = new Hashtable ();
380 if (anames.Contains (name)) {
381 object o = anames [name];
388 Assembly assembly = null;
389 Exception error = null;
390 if (name.IndexOf (',') != -1) {
392 assembly = Assembly.Load (name);
393 } catch (Exception e) { error = e; }
396 if (assembly == null) {
398 assembly = Assembly.LoadWithPartialName (name);
399 } catch (Exception e) { error = e; }
402 if (assembly == null)
403 ThrowParseException ("Assembly " + name + " not found", error);
405 AddAssembly (assembly, true);
409 internal virtual void ProcessMainAttributes (Hashtable atts)
411 atts.Remove ("Description"); // ignored
413 atts.Remove ("CodeBehind"); // ignored
415 atts.Remove ("AspCompat"); // ignored
417 debug = GetBool (atts, "Debug", true);
418 compilerOptions = GetString (atts, "CompilerOptions", "");
419 language = GetString (atts, "Language", CompilationConfig.DefaultLanguage);
420 strictOn = GetBool (atts, "Strict", CompilationConfig.Strict);
421 explicitOn = GetBool (atts, "Explicit", CompilationConfig.Explicit);
423 string src = GetString (atts, "CodeFile", null);
425 string src = GetString (atts, "Src", null);
428 srcAssembly = GetAssemblyFromSource (src);
430 string inherits = GetString (atts, "Inherits", null);
432 className = inherits;
434 if (inherits != null)
435 SetBaseType (inherits);
437 className = GetString (atts, "ClassName", null);
438 if (className != null && !CodeGenerator.IsValidLanguageIndependentIdentifier (className))
439 ThrowParseException (String.Format ("'{0}' is not valid for 'className'", className));
443 ThrowParseException ("Unknown attribute: " + GetOneKey (atts));
446 internal void SetBaseType (string type)
448 if (type == DefaultBaseTypeName)
452 if (srcAssembly != null)
453 parent = srcAssembly.GetType (type);
456 parent = LoadType (type);
459 ThrowParseException ("Cannot find type " + type);
461 if (!DefaultBaseType.IsAssignableFrom (parent))
462 ThrowParseException ("The parent type does not derive from " + DefaultBaseType);
467 Assembly GetAssemblyFromSource (string vpath)
469 vpath = UrlUtils.Combine (BaseVirtualDir, vpath);
470 string realPath = MapPath (vpath, false);
471 if (!File.Exists (realPath))
472 ThrowParseException ("File " + vpath + " not found");
474 AddSourceDependency (realPath);
476 CompilerResults result = CachingCompiler.Compile (language, realPath, realPath, assemblies);
477 if (result.NativeCompilerReturnValue != 0) {
478 StreamReader reader = new StreamReader (realPath);
479 throw new CompilationException (realPath, result.Errors, reader.ReadToEnd ());
482 AddAssembly (result.CompiledAssembly, true);
483 return result.CompiledAssembly;
486 internal abstract Type DefaultBaseType { get; }
487 internal abstract string DefaultBaseTypeName { get; }
488 internal abstract string DefaultDirectiveName { get; }
490 internal string InputFile
492 get { return inputFile; }
493 set { inputFile = value; }
499 set { text = value; }
502 internal Type BaseType
505 if (baseType == null)
506 baseType = DefaultBaseType;
512 internal string ClassName {
514 if (className != null)
517 className = Path.GetFileName (inputFile).Replace ('.', '_');
518 className = className.Replace ('-', '_');
519 className = className.Replace (' ', '_');
521 if (Char.IsDigit(className[0])) {
522 className = "_" + className;
529 internal string PrivateBinPath {
531 if (privateBinPath != null)
532 return privateBinPath;
534 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
535 privateBinPath = Path.Combine (setup.ApplicationBase, setup.PrivateBinPath);
537 return privateBinPath;
541 internal ArrayList Scripts {
544 scripts = new ArrayList ();
550 internal ArrayList Imports {
551 get { return imports; }
554 internal ArrayList Assemblies {
556 if (appAssemblyIndex != -1) {
557 object o = assemblies [appAssemblyIndex];
558 assemblies.RemoveAt (appAssemblyIndex);
560 appAssemblyIndex = -1;
567 internal ArrayList Interfaces {
568 get { return interfaces; }
571 internal RootBuilder RootBuilder {
572 get { return rootBuilder; }
573 set { rootBuilder = value; }
576 internal ArrayList Dependencies {
577 get { return dependencies; }
578 set { dependencies = value; }
581 internal string CompilerOptions {
582 get { return compilerOptions; }
585 internal string Language {
586 get { return language; }
589 internal bool StrictOn {
590 get { return strictOn; }
593 internal bool ExplicitOn {
594 get { return explicitOn; }
597 internal bool Debug {
598 get { return debug; }
601 internal bool OutputCache {
602 get { return output_cache; }
605 internal int OutputCacheDuration {
606 get { return oc_duration; }
609 internal string OutputCacheVaryByHeader {
610 get { return oc_header; }
613 internal string OutputCacheVaryByCustom {
614 get { return oc_custom; }
617 internal string OutputCacheVaryByControls {
618 get { return oc_controls; }
621 internal bool OutputCacheShared {
622 get { return oc_shared; }
625 internal OutputCacheLocation OutputCacheLocation {
626 get { return oc_location; }
629 internal string OutputCacheVaryByParam {
630 get { return oc_param; }
633 internal PagesConfiguration PagesConfig {
634 get { return PagesConfiguration.GetInstance (Context); }