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
;
63 string oc_header
, oc_custom
, oc_param
, oc_controls
;
65 OutputCacheLocation oc_location
;
67 int appAssemblyIndex
= -1;
69 internal TemplateParser ()
71 imports
= new ArrayList ();
72 imports
.Add ("System");
73 imports
.Add ("System.Collections");
74 imports
.Add ("System.Collections.Specialized");
75 imports
.Add ("System.Configuration");
76 imports
.Add ("System.Text");
77 imports
.Add ("System.Text.RegularExpressions");
78 imports
.Add ("System.Web");
79 imports
.Add ("System.Web.Caching");
80 imports
.Add ("System.Web.Security");
81 imports
.Add ("System.Web.SessionState");
82 imports
.Add ("System.Web.UI");
83 imports
.Add ("System.Web.UI.WebControls");
84 imports
.Add ("System.Web.UI.HtmlControls");
86 assemblies
= new ArrayList ();
87 assemblies
.AddRange (CompilationConfig
.Assemblies
);
88 if (CompilationConfig
.AssembliesInBin
)
89 AddAssembliesInBin ();
91 language
= CompilationConfig
.DefaultLanguage
;
94 internal void AddApplicationAssembly ()
96 string location
= Context
.ApplicationInstance
.AssemblyLocation
;
97 if (location
!= typeof (TemplateParser
).Assembly
.Location
) {
98 appAssemblyIndex
= assemblies
.Add (location
);
102 protected abstract Type
CompileIntoType ();
104 internal virtual void HandleOptions (object obj
)
108 internal static string GetOneKey (Hashtable tbl
)
110 foreach (object key
in tbl
.Keys
)
111 return key
.ToString ();
116 internal virtual void AddDirective (string directive
, Hashtable atts
)
118 if (String
.Compare (directive
, DefaultDirectiveName
, true) == 0) {
119 if (mainAttributes
!= null)
120 ThrowParseException ("Only 1 " + DefaultDirectiveName
+ " is allowed");
122 mainAttributes
= atts
;
123 ProcessMainAttributes (mainAttributes
);
127 int cmp
= String
.Compare ("Assembly", directive
, true);
129 string name
= GetString (atts
, "Name", null);
130 string src
= GetString (atts
, "Src", null);
133 ThrowParseException ("Attribute " + GetOneKey (atts
) + " unknown.");
135 if (name
== null && src
== null)
136 ThrowParseException ("You gotta specify Src or Name");
138 if (name
!= null && src
!= null)
139 ThrowParseException ("Src and Name cannot be used together");
142 AddAssemblyByName (name
);
144 GetAssemblyFromSource (src
);
150 cmp
= String
.Compare ("Import", directive
, true);
152 string namesp
= GetString (atts
, "Namespace", null);
154 ThrowParseException ("Attribute " + GetOneKey (atts
) + " unknown.");
156 if (namesp
!= null && namesp
!= "")
161 cmp
= String
.Compare ("Implements", directive
, true);
163 string ifacename
= GetString (atts
, "Interface", "");
166 ThrowParseException ("Attribute " + GetOneKey (atts
) + " unknown.");
168 Type iface
= LoadType (ifacename
);
170 ThrowParseException ("Cannot find type " + ifacename
);
172 if (!iface
.IsInterface
)
173 ThrowParseException (iface
+ " is not an interface");
175 AddInterface (iface
.FullName
);
179 cmp
= String
.Compare ("OutputCache", directive
, true);
183 if (atts
["Duration"] == null)
184 ThrowParseException ("The directive is missing a 'duration' attribute.");
185 if (atts
["VaryByParam"] == null)
186 ThrowParseException ("This directive is missing a 'VaryByParam' " +
187 "attribute, which should be set to \"none\", \"*\", " +
188 "or a list of name/value pairs.");
190 foreach (DictionaryEntry entry
in atts
) {
191 string key
= (string) entry
.Key
;
192 switch (key
.ToLower ()) {
194 oc_duration
= Int32
.Parse ((string) entry
.Value
);
196 ThrowParseException ("The 'duration' attribute must be set " +
197 "to a positive integer value");
200 oc_param
= (string) entry
.Value
;
201 if (String
.Compare (oc_param
, "none") == 0)
205 oc_header
= (string) entry
.Value
;
208 oc_custom
= (string) entry
.Value
;
211 if (!(this is PageParser
))
215 oc_location
= (OutputCacheLocation
) Enum
.Parse (
216 typeof (OutputCacheLocation
), (string) entry
.Value
, true);
218 ThrowParseException ("The 'location' attribute is case sensitive and " +
219 "must be one of the following values: Any, Client, " +
220 "Downstream, Server, None, ServerAndClient.");
223 case "varybycontrol":
224 if (this is PageParser
)
227 oc_controls
= (string) entry
.Value
;
230 if (this is PageParser
)
234 oc_shared
= Boolean
.Parse ((string) entry
.Value
);
236 ThrowParseException ("The 'shared' attribute is case sensitive" +
237 " and must be set to 'true' or 'false'.");
241 ThrowParseException ("The '" + key
+ "' attribute is not " +
242 "supported by the 'Outputcache' directive.");
251 ThrowParseException ("Unknown directive: " + directive
);
254 internal Type
LoadType (string typeName
)
256 // First try loaded assemblies, then try assemblies in Bin directory.
258 bool seenBin
= false;
259 Assembly
[] assemblies
= AppDomain
.CurrentDomain
.GetAssemblies ();
260 foreach (Assembly ass
in assemblies
) {
261 type
= ass
.GetType (typeName
);
265 if (Path
.GetDirectoryName (ass
.Location
) != PrivateBinPath
) {
266 AddAssembly (ass
, false);
271 AddDependency (ass
.Location
);
279 if (!Directory
.Exists (PrivateBinPath
))
282 string [] binDlls
= Directory
.GetFiles (PrivateBinPath
, "*.dll");
283 foreach (string s
in binDlls
) {
284 Assembly binA
= Assembly
.LoadFrom (s
);
285 type
= binA
.GetType (typeName
);
289 AddDependency (binA
.Location
);
296 void AddAssembliesInBin ()
298 if (!Directory
.Exists (PrivateBinPath
))
301 string [] binDlls
= Directory
.GetFiles (PrivateBinPath
, "*.dll");
302 foreach (string s
in binDlls
) {
307 internal virtual void AddInterface (string iface
)
309 if (interfaces
== null)
310 interfaces
= new ArrayList ();
312 if (!interfaces
.Contains (iface
))
313 interfaces
.Add (iface
);
316 internal virtual void AddImport (string namesp
)
319 imports
= new ArrayList ();
321 if (!imports
.Contains (namesp
))
322 imports
.Add (namesp
);
325 internal virtual void AddDependency (string filename
)
327 if (dependencies
== null)
328 dependencies
= new ArrayList ();
330 if (!dependencies
.Contains (filename
))
331 dependencies
.Add (filename
);
334 internal virtual void AddAssembly (Assembly assembly
, bool fullPath
)
337 anames
= new Hashtable ();
339 string name
= assembly
.GetName ().Name
;
340 string loc
= assembly
.Location
;
342 if (!assemblies
.Contains (loc
)) {
343 assemblies
.Add (loc
);
347 anames
[loc
] = assembly
;
349 if (!assemblies
.Contains (name
)) {
350 assemblies
.Add (name
);
353 anames
[name
] = assembly
;
357 internal virtual Assembly
AddAssemblyByName (string name
)
360 anames
= new Hashtable ();
362 if (anames
.Contains (name
)) {
363 object o
= anames
[name
];
370 bool fullpath
= false;
371 Assembly assembly
= null;
373 assembly
= Assembly
.LoadWithPartialName (name
);
374 string loc
= assembly
.Location
;
375 fullpath
= (Path
.GetDirectoryName (loc
) == PrivateBinPath
);
376 } catch (Exception e
) {
377 ThrowParseException ("Assembly " + name
+ " not found", e
);
380 AddAssembly (assembly
, fullpath
);
384 internal virtual void ProcessMainAttributes (Hashtable atts
)
386 atts
.Remove ("Description"); // ignored
387 atts
.Remove ("CodeBehind"); // ignored
388 atts
.Remove ("AspCompat"); // ignored
390 debug
= GetBool (atts
, "Debug", true);
391 compilerOptions
= GetString (atts
, "CompilerOptions", "");
392 language
= GetString (atts
, "Language", CompilationConfig
.DefaultLanguage
);
393 string src
= GetString (atts
, "Src", null);
395 srcAssembly
= GetAssemblyFromSource (src
);
397 string inherits
= GetString (atts
, "Inherits", null);
398 if (inherits
!= null)
399 SetBaseType (inherits
);
401 className
= GetString (atts
, "ClassName", null);
402 if (className
!= null && !CodeGenerator
.IsValidLanguageIndependentIdentifier (className
))
403 ThrowParseException (String
.Format ("'{0}' is not valid for 'className'", className
));
406 ThrowParseException ("Unknown attribute: " + GetOneKey (atts
));
409 internal void SetBaseType (string type
)
411 if (type
== DefaultBaseTypeName
)
415 if (srcAssembly
!= null)
416 parent
= srcAssembly
.GetType (type
);
419 parent
= LoadType (type
);
422 ThrowParseException ("Cannot find type " + type
);
424 if (!DefaultBaseType
.IsAssignableFrom (parent
))
425 ThrowParseException ("The parent type does not derive from " + DefaultBaseType
);
430 Assembly
GetAssemblyFromSource (string vpath
)
432 vpath
= UrlUtils
.Combine (BaseVirtualDir
, vpath
);
433 string realPath
= MapPath (vpath
, false);
434 if (!File
.Exists (realPath
))
435 ThrowParseException ("File " + vpath
+ " not found");
437 AddDependency (realPath
);
439 CompilerResults result
= CachingCompiler
.Compile (language
, realPath
, realPath
, assemblies
);
440 if (result
.NativeCompilerReturnValue
!= 0) {
441 StreamReader reader
= new StreamReader (realPath
);
442 throw new CompilationException (realPath
, result
.Errors
, reader
.ReadToEnd ());
445 AddAssembly (result
.CompiledAssembly
, true);
446 return result
.CompiledAssembly
;
449 internal abstract Type DefaultBaseType { get; }
450 internal abstract string DefaultBaseTypeName { get; }
451 internal abstract string DefaultDirectiveName { get; }
453 internal string InputFile
455 get { return inputFile; }
456 set { inputFile = value; }
462 set { text = value; }
465 internal Type BaseType
468 if (baseType
== null)
469 baseType
= DefaultBaseType
;
475 internal string ClassName
{
477 if (className
!= null)
480 className
= Path
.GetFileName (inputFile
).Replace ('.', '_');
481 className
= className
.Replace ('-', '_');
482 className
= className
.Replace (' ', '_');
484 if (Char
.IsDigit(className
[0])) {
485 className
= "_" + className
;
492 internal string PrivateBinPath
{
494 if (privateBinPath
!= null)
495 return privateBinPath
;
497 AppDomainSetup setup
= AppDomain
.CurrentDomain
.SetupInformation
;
498 privateBinPath
= Path
.Combine (setup
.ApplicationBase
, setup
.PrivateBinPath
);
500 return privateBinPath
;
504 internal ArrayList Scripts
{
507 scripts
= new ArrayList ();
513 internal ArrayList Imports
{
514 get { return imports; }
517 internal ArrayList Assemblies
{
519 if (appAssemblyIndex
!= -1) {
520 object o
= assemblies
[appAssemblyIndex
];
521 assemblies
.RemoveAt (appAssemblyIndex
);
523 appAssemblyIndex
= -1;
530 internal ArrayList Interfaces
{
531 get { return interfaces; }
534 internal RootBuilder RootBuilder
{
535 get { return rootBuilder; }
536 set { rootBuilder = value; }
539 internal ArrayList Dependencies
{
540 get { return dependencies; }
543 internal string CompilerOptions
{
544 get { return compilerOptions; }
547 internal string Language
{
548 get { return language; }
551 internal bool Debug
{
552 get { return debug; }
555 internal bool OutputCache
{
556 get { return output_cache; }
559 internal int OutputCacheDuration
{
560 get { return oc_duration; }
563 internal string OutputCacheVaryByHeader
{
564 get { return oc_header; }
567 internal string OutputCacheVaryByCustom
{
568 get { return oc_custom; }
571 internal string OutputCacheVaryByControls
{
572 get { return oc_controls; }
575 internal bool OutputCacheShared
{
576 get { return oc_shared; }
579 internal OutputCacheLocation OutputCacheLocation
{
580 get { return oc_location; }
583 internal string OutputCacheVaryByParam
{
584 get { return oc_param; }
587 internal PagesConfiguration PagesConfig
{
588 get { return PagesConfiguration.GetInstance (Context); }