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)
11 using System.CodeDom.Compiler;
12 using System.Collections;
14 using System.Reflection;
16 using System.Web.Compilation;
17 using System.Web.Util;
19 namespace System.Web.UI
21 public abstract class TemplateParser : BaseParser
25 string privateBinPath;
26 Hashtable mainAttributes;
27 ArrayList dependencies;
35 RootBuilder rootBuilder;
37 string compilerOptions;
40 public TemplateParser ()
42 imports = new ArrayList ();
43 imports.Add ("System");
44 imports.Add ("System.Collections");
45 imports.Add ("System.Collections.Specialized");
46 imports.Add ("System.Configuration");
47 imports.Add ("System.Text");
48 imports.Add ("System.Text.RegularExpressions");
49 imports.Add ("System.Web");
50 imports.Add ("System.Web.Caching");
51 imports.Add ("System.Web.Security");
52 imports.Add ("System.Web.SessionState");
53 imports.Add ("System.Web.UI");
54 imports.Add ("System.Web.UI.WebControls");
55 imports.Add ("System.Web.UI.HtmlControls");
57 assemblies = new ArrayList ();
58 assemblies.Add ("System.dll");
59 assemblies.Add ("System.Drawing.dll");
60 assemblies.Add ("System.Data.dll");
61 assemblies.Add ("System.Web.dll");
62 assemblies.Add ("System.Xml.dll");
63 AddAssembliesInBin ();
66 protected abstract Type CompileIntoType ();
68 protected virtual void HandleOptions (object obj)
72 internal static string GetOneKey (Hashtable tbl)
74 foreach (object key in tbl.Keys)
75 return key.ToString ();
80 internal virtual void AddDirective (string directive, Hashtable atts)
82 if (String.Compare (directive, DefaultDirectiveName, true) == 0) {
83 if (mainAttributes != null)
84 ThrowParseException ("Only 1 " + DefaultDirectiveName + " is allowed");
86 mainAttributes = atts;
87 ProcessMainAttributes (mainAttributes);
91 int cmp = String.Compare ("Assembly", directive, true);
93 string name = GetString (atts, "Name", null);
94 string src = GetString (atts, "Src", null);
97 ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
99 if (name == null && src == null)
100 ThrowParseException ("You gotta specify Src or Name");
102 if (name != null && src != null)
103 ThrowParseException ("Src and Name cannot be used together");
106 AddAssemblyByName (name);
108 GetAssemblyFromSource (src);
114 cmp = String.Compare ("Import", directive, true);
116 string namesp = GetString (atts, "Namespace", null);
118 ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
120 if (namesp != null && namesp != "")
125 cmp = String.Compare ("Implements", directive, true);
127 string ifacename = GetString (atts, "Interface", "");
130 ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
132 Type iface = LoadType (ifacename);
134 ThrowParseException ("Cannot find type " + ifacename);
136 if (!iface.IsInterface)
137 ThrowParseException (iface + " is not an interface");
139 AddInterface (iface.FullName);
143 ThrowParseException ("Unknown directive: " + directive);
146 internal Type LoadType (string typeName)
148 // First try loaded assemblies, then try assemblies in Bin directory.
149 // By now i do this 'by hand' but may be this is a runtime/gac task.
151 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
152 foreach (Assembly ass in assemblies) {
153 type = ass.GetType (typeName);
155 AddAssembly (ass, false);
156 AddDependency (ass.Location);
164 void AddAssembliesInBin ()
166 if (!Directory.Exists (PrivateBinPath))
169 string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
170 foreach (string dll in binDlls) {
171 Assembly assembly = Assembly.LoadFrom (dll);
172 AddAssembly (assembly, true);
176 Assembly LoadAssemblyFromBin (string name)
179 if (!Directory.Exists (PrivateBinPath))
182 string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
183 foreach (string dll in binDlls) {
184 string fn = Path.GetFileName (dll);
185 fn = Path.ChangeExtension (fn, null);
189 assembly = Assembly.LoadFrom (dll);
196 internal virtual void AddInterface (string iface)
198 if (interfaces == null)
199 interfaces = new ArrayList ();
201 if (!interfaces.Contains (iface))
202 interfaces.Add (iface);
205 internal virtual void AddImport (string namesp)
208 imports = new ArrayList ();
210 if (!imports.Contains (namesp))
211 imports.Add (namesp);
214 internal virtual void AddDependency (string filename)
216 if (dependencies == null)
217 dependencies = new ArrayList ();
219 if (!dependencies.Contains (filename))
220 dependencies.Add (filename);
223 internal virtual void AddAssembly (Assembly assembly, bool fullPath)
226 anames = new Hashtable ();
228 string name = assembly.GetName ().Name;
229 string loc = assembly.Location;
231 if (!assemblies.Contains (loc)) {
232 assemblies.Add (loc);
236 anames [loc] = assembly;
238 if (!assemblies.Contains (name)) {
239 assemblies.Add (name);
242 anames [name] = assembly;
246 internal virtual Assembly AddAssemblyByName (string name)
249 anames = new Hashtable ();
251 if (anames.Contains (name)) {
252 object o = anames [name];
259 bool fullpath = true;
260 Assembly assembly = LoadAssemblyFromBin (name);
261 if (assembly != null) {
262 AddAssembly (assembly, fullpath);
267 assembly = Assembly.Load (name);
268 string loc = assembly.Location;
269 fullpath = (Path.GetDirectoryName (loc) == PrivateBinPath);
270 } catch (Exception e) {
271 ThrowParseException ("Assembly " + name + " not found", e);
274 AddAssembly (assembly, fullpath);
278 internal virtual void ProcessMainAttributes (Hashtable atts)
280 atts.Remove ("Description"); // ignored
281 atts.Remove ("CodeBehind"); // ignored
283 debug = GetBool (atts, "Debug", true);
284 compilerOptions = GetString (atts, "CompilerOptions", null);
285 language = GetString (atts, "Language", "C#");
286 if (String.Compare (language, "c#", true) != 0)
287 ThrowParseException ("Only C# supported.");
289 string src = GetString (atts, "Src", null);
290 Assembly srcAssembly = null;
292 srcAssembly = GetAssemblyFromSource (src);
294 string inherits = GetString (atts, "Inherits", null);
295 if (inherits != null) {
297 if (srcAssembly != null)
298 parent = srcAssembly.GetType (inherits);
300 parent = LoadType (inherits);
303 ThrowParseException ("Cannot find type " + inherits);
305 if (!DefaultBaseType.IsAssignableFrom (parent))
306 ThrowParseException ("The parent type does not derive from " + DefaultBaseType);
311 className = GetString (atts, "ClassName", null);
313 ThrowParseException ("Unknown attribute: " + GetOneKey (atts));
316 Assembly GetAssemblyFromSource (string vpath)
318 vpath = UrlUtils.Combine (BaseVirtualDir, vpath);
319 string realPath = MapPath (vpath, false);
320 if (!File.Exists (realPath))
321 ThrowParseException ("File " + vpath + " not found");
323 AddDependency (realPath);
325 CompilerResults result = CachingCompiler.Compile (realPath, assemblies);
326 if (result.NativeCompilerReturnValue != 0) {
327 StringWriter writer = new StringWriter();
328 StreamReader reader = new StreamReader (realPath);
329 throw new CompilationException (realPath, result.Errors, reader.ReadToEnd ());
332 AddAssembly (result.CompiledAssembly, true);
333 return result.CompiledAssembly;
336 protected abstract Type DefaultBaseType { get; }
338 protected internal abstract string DefaultDirectiveName { get; }
340 internal string InputFile
342 get { return inputFile; }
343 set { inputFile = value; }
349 set { text = value; }
352 internal Type BaseType
355 if (baseType == null)
356 baseType = DefaultBaseType;
362 internal string ClassName {
364 if (className != null)
367 className = Path.GetFileName (inputFile).Replace ('.', '_');
368 className = className.Replace ('-', '_');
369 className = className.Replace (' ', '_');
374 internal string PrivateBinPath {
376 if (privateBinPath != null)
377 return privateBinPath;
379 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
380 privateBinPath = setup.PrivateBinPath;
382 if (!Path.IsPathRooted (privateBinPath)) {
383 string appbase = setup.ApplicationBase;
384 if (appbase.StartsWith ("file://")) {
385 appbase = appbase.Substring (7);
386 if (Path.DirectorySeparatorChar != '/')
387 appbase = appbase.Replace ('/', Path.DirectorySeparatorChar);
389 privateBinPath = Path.Combine (appbase, privateBinPath);
392 return privateBinPath;
396 internal ArrayList Scripts {
399 scripts = new ArrayList ();
405 internal ArrayList Imports {
406 get { return imports; }
409 internal ArrayList Assemblies {
410 get { return assemblies; }
413 internal ArrayList Interfaces {
414 get { return interfaces; }
417 internal RootBuilder RootBuilder {
418 get { return rootBuilder; }
419 set { rootBuilder = value; }
422 internal ArrayList Dependencies {
423 get { return dependencies; }
426 internal string CompilerOptions {
427 get { return compilerOptions; }
430 internal string Language {
431 get { return language; }
434 internal bool Debug {
435 get { return debug; }