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)
9 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
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.
31 using System.CodeDom.Compiler;
32 using System.Collections;
34 using System.Reflection;
35 using System.Security.Permissions;
36 using System.Web.Compilation;
37 using System.Web.Configuration;
38 using System.Web.Util;
40 namespace System.Web.UI {
43 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
44 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
45 public abstract class TemplateParser : BaseParser
49 string privateBinPath;
50 Hashtable mainAttributes;
51 ArrayList dependencies;
59 RootBuilder rootBuilder;
61 string compilerOptions;
63 bool strictOn = false;
64 bool explicitOn = false;
67 string oc_header, oc_custom, oc_param, oc_controls;
69 OutputCacheLocation oc_location;
71 int appAssemblyIndex = -1;
73 internal TemplateParser ()
75 imports = new ArrayList ();
76 imports.Add ("System");
77 imports.Add ("System.Collections");
78 imports.Add ("System.Collections.Specialized");
79 imports.Add ("System.Configuration");
80 imports.Add ("System.Text");
81 imports.Add ("System.Text.RegularExpressions");
82 imports.Add ("System.Web");
83 imports.Add ("System.Web.Caching");
84 imports.Add ("System.Web.Security");
85 imports.Add ("System.Web.SessionState");
86 imports.Add ("System.Web.UI");
87 imports.Add ("System.Web.UI.WebControls");
88 imports.Add ("System.Web.UI.HtmlControls");
90 assemblies = new ArrayList ();
91 foreach (string a in CompilationConfig.Assemblies)
92 AddAssemblyByName (a);
93 if (CompilationConfig.AssembliesInBin)
94 AddAssembliesInBin ();
96 language = CompilationConfig.DefaultLanguage;
99 internal void AddApplicationAssembly ()
101 string location = Context.ApplicationInstance.AssemblyLocation;
102 if (location != typeof (TemplateParser).Assembly.Location) {
103 appAssemblyIndex = assemblies.Add (location);
107 protected abstract Type CompileIntoType ();
109 internal virtual void HandleOptions (object obj)
113 internal static string GetOneKey (Hashtable tbl)
115 foreach (object key in tbl.Keys)
116 return key.ToString ();
121 internal virtual void AddDirective (string directive, Hashtable atts)
123 if (String.Compare (directive, DefaultDirectiveName, true) == 0) {
124 if (mainAttributes != null)
125 ThrowParseException ("Only 1 " + DefaultDirectiveName + " is allowed");
127 mainAttributes = atts;
128 ProcessMainAttributes (mainAttributes);
132 int cmp = String.Compare ("Assembly", directive, true);
134 string name = GetString (atts, "Name", null);
135 string src = GetString (atts, "Src", null);
138 ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
140 if (name == null && src == null)
141 ThrowParseException ("You gotta specify Src or Name");
143 if (name != null && src != null)
144 ThrowParseException ("Src and Name cannot be used together");
147 AddAssemblyByName (name);
149 GetAssemblyFromSource (src);
155 cmp = String.Compare ("Import", directive, true);
157 string namesp = GetString (atts, "Namespace", null);
159 ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
161 if (namesp != null && namesp != "")
166 cmp = String.Compare ("Implements", directive, true);
168 string ifacename = GetString (atts, "Interface", "");
171 ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
173 Type iface = LoadType (ifacename);
175 ThrowParseException ("Cannot find type " + ifacename);
177 if (!iface.IsInterface)
178 ThrowParseException (iface + " is not an interface");
180 AddInterface (iface.FullName);
184 cmp = String.Compare ("OutputCache", directive, true);
188 if (atts ["Duration"] == null)
189 ThrowParseException ("The directive is missing a 'duration' attribute.");
190 if (atts ["VaryByParam"] == null)
191 ThrowParseException ("This directive is missing a 'VaryByParam' " +
192 "attribute, which should be set to \"none\", \"*\", " +
193 "or a list of name/value pairs.");
195 foreach (DictionaryEntry entry in atts) {
196 string key = (string) entry.Key;
197 switch (key.ToLower ()) {
199 oc_duration = Int32.Parse ((string) entry.Value);
201 ThrowParseException ("The 'duration' attribute must be set " +
202 "to a positive integer value");
205 oc_param = (string) entry.Value;
206 if (String.Compare (oc_param, "none") == 0)
210 oc_header = (string) entry.Value;
213 oc_custom = (string) entry.Value;
216 if (!(this is PageParser))
220 oc_location = (OutputCacheLocation) Enum.Parse (
221 typeof (OutputCacheLocation), (string) entry.Value, true);
223 ThrowParseException ("The 'location' attribute is case sensitive and " +
224 "must be one of the following values: Any, Client, " +
225 "Downstream, Server, None, ServerAndClient.");
228 case "varybycontrol":
229 if (this is PageParser)
232 oc_controls = (string) entry.Value;
235 if (this is PageParser)
239 oc_shared = Boolean.Parse ((string) entry.Value);
241 ThrowParseException ("The 'shared' attribute is case sensitive" +
242 " and must be set to 'true' or 'false'.");
246 ThrowParseException ("The '" + key + "' attribute is not " +
247 "supported by the 'Outputcache' directive.");
256 ThrowParseException ("Unknown directive: " + directive);
259 internal Type LoadType (string typeName)
261 // First try loaded assemblies, then try assemblies in Bin directory.
263 bool seenBin = false;
264 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
265 foreach (Assembly ass in assemblies) {
266 type = ass.GetType (typeName);
270 if (Path.GetDirectoryName (ass.Location) != PrivateBinPath) {
271 AddAssembly (ass, true);
276 AddDependency (ass.Location);
284 if (!Directory.Exists (PrivateBinPath))
287 string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
288 foreach (string s in binDlls) {
289 Assembly binA = Assembly.LoadFrom (s);
290 type = binA.GetType (typeName);
294 AddDependency (binA.Location);
301 void AddAssembliesInBin ()
303 if (!Directory.Exists (PrivateBinPath))
306 string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
307 foreach (string s in binDlls) {
312 internal virtual void AddInterface (string iface)
314 if (interfaces == null)
315 interfaces = new ArrayList ();
317 if (!interfaces.Contains (iface))
318 interfaces.Add (iface);
321 internal virtual void AddImport (string namesp)
324 imports = new ArrayList ();
326 if (!imports.Contains (namesp))
327 imports.Add (namesp);
330 internal virtual void AddSourceDependency (string filename)
332 if (dependencies != null && dependencies.Contains (filename)) {
333 ThrowParseException ("Circular file references are not allowed. File: " + filename);
336 AddDependency (filename);
339 internal virtual void AddDependency (string filename)
344 if (dependencies == null)
345 dependencies = new ArrayList ();
347 if (!dependencies.Contains (filename))
348 dependencies.Add (filename);
351 internal virtual void AddAssembly (Assembly assembly, bool fullPath)
353 if (assembly.Location == "")
357 anames = new Hashtable ();
359 string name = assembly.GetName ().Name;
360 string loc = assembly.Location;
362 if (!assemblies.Contains (loc)) {
363 assemblies.Add (loc);
367 anames [loc] = assembly;
369 if (!assemblies.Contains (name)) {
370 assemblies.Add (name);
373 anames [name] = assembly;
377 internal virtual Assembly AddAssemblyByName (string name)
380 anames = new Hashtable ();
382 if (anames.Contains (name)) {
383 object o = anames [name];
390 Assembly assembly = null;
391 Exception error = null;
392 if (name.IndexOf (',') != -1) {
394 assembly = Assembly.Load (name);
395 } catch (Exception e) { error = e; }
398 if (assembly == null) {
400 assembly = Assembly.LoadWithPartialName (name);
401 } catch (Exception e) { error = e; }
404 if (assembly == null)
405 ThrowParseException ("Assembly " + name + " not found", error);
407 AddAssembly (assembly, true);
411 internal virtual void ProcessMainAttributes (Hashtable atts)
413 atts.Remove ("Description"); // ignored
415 atts.Remove ("CodeBehind"); // ignored
417 atts.Remove ("AspCompat"); // ignored
419 debug = GetBool (atts, "Debug", true);
420 compilerOptions = GetString (atts, "CompilerOptions", "");
421 language = GetString (atts, "Language", CompilationConfig.DefaultLanguage);
422 strictOn = GetBool (atts, "Strict", CompilationConfig.Strict);
423 explicitOn = GetBool (atts, "Explicit", CompilationConfig.Explicit);
425 string src = GetString (atts, "CodeFile", null);
427 string src = GetString (atts, "Src", null);
430 srcAssembly = GetAssemblyFromSource (src);
432 string inherits = GetString (atts, "Inherits", null);
434 if (srcAssembly == null)
435 className = inherits;
437 SetBaseType (inherits);
439 if (inherits != null)
440 SetBaseType (inherits);
442 className = GetString (atts, "ClassName", null);
443 if (className != null && !CodeGenerator.IsValidLanguageIndependentIdentifier (className))
444 ThrowParseException (String.Format ("'{0}' is not valid for 'className'", className));
448 ThrowParseException ("Unknown attribute: " + GetOneKey (atts));
451 internal void SetBaseType (string type)
453 if (type == DefaultBaseTypeName)
457 if (srcAssembly != null)
458 parent = srcAssembly.GetType (type);
461 parent = LoadType (type);
464 ThrowParseException ("Cannot find type " + type);
466 if (!DefaultBaseType.IsAssignableFrom (parent))
467 ThrowParseException ("The parent type does not derive from " + DefaultBaseType);
472 Assembly GetAssemblyFromSource (string vpath)
474 vpath = UrlUtils.Combine (BaseVirtualDir, vpath);
475 string realPath = MapPath (vpath, false);
476 if (!File.Exists (realPath))
477 ThrowParseException ("File " + vpath + " not found");
479 AddSourceDependency (realPath);
481 CompilerResults result = CachingCompiler.Compile (language, realPath, realPath, assemblies);
482 if (result.NativeCompilerReturnValue != 0) {
483 StreamReader reader = new StreamReader (realPath);
484 throw new CompilationException (realPath, result.Errors, reader.ReadToEnd ());
487 AddAssembly (result.CompiledAssembly, true);
488 return result.CompiledAssembly;
491 internal abstract Type DefaultBaseType { get; }
492 internal abstract string DefaultBaseTypeName { get; }
493 internal abstract string DefaultDirectiveName { get; }
495 internal string InputFile
497 get { return inputFile; }
498 set { inputFile = value; }
504 set { text = value; }
507 internal Type BaseType
510 if (baseType == null)
511 baseType = DefaultBaseType;
517 internal string ClassName {
519 if (className != null)
522 className = Path.GetFileName (inputFile).Replace ('.', '_');
523 className = className.Replace ('-', '_');
524 className = className.Replace (' ', '_');
526 if (Char.IsDigit(className[0])) {
527 className = "_" + className;
534 internal string PrivateBinPath {
536 if (privateBinPath != null)
537 return privateBinPath;
539 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
540 privateBinPath = Path.Combine (setup.ApplicationBase, setup.PrivateBinPath);
542 return privateBinPath;
546 internal ArrayList Scripts {
549 scripts = new ArrayList ();
555 internal ArrayList Imports {
556 get { return imports; }
559 internal ArrayList Assemblies {
561 if (appAssemblyIndex != -1) {
562 object o = assemblies [appAssemblyIndex];
563 assemblies.RemoveAt (appAssemblyIndex);
565 appAssemblyIndex = -1;
572 internal ArrayList Interfaces {
573 get { return interfaces; }
576 internal RootBuilder RootBuilder {
577 get { return rootBuilder; }
578 set { rootBuilder = value; }
581 internal ArrayList Dependencies {
582 get { return dependencies; }
583 set { dependencies = value; }
586 internal string CompilerOptions {
587 get { return compilerOptions; }
590 internal string Language {
591 get { return language; }
594 internal bool StrictOn {
595 get { return strictOn; }
598 internal bool ExplicitOn {
599 get { return explicitOn; }
602 internal bool Debug {
603 get { return debug; }
606 internal bool OutputCache {
607 get { return output_cache; }
610 internal int OutputCacheDuration {
611 get { return oc_duration; }
614 internal string OutputCacheVaryByHeader {
615 get { return oc_header; }
618 internal string OutputCacheVaryByCustom {
619 get { return oc_custom; }
622 internal string OutputCacheVaryByControls {
623 get { return oc_controls; }
626 internal bool OutputCacheShared {
627 get { return oc_shared; }
630 internal OutputCacheLocation OutputCacheLocation {
631 get { return oc_location; }
634 internal string OutputCacheVaryByParam {
635 get { return oc_param; }
638 internal PagesConfiguration PagesConfig {
639 get { return PagesConfiguration.GetInstance (Context); }