2 // System.Web.Compilation.AspGenerator
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (C) 2002 Ximian, Inc (http://www.ximian.com)
10 using System.Collections;
11 using System.ComponentModel;
13 using System.Diagnostics;
15 using System.Reflection;
17 using System.Text.RegularExpressions;
19 using System.Web.UI.HtmlControls;
20 using System.Web.UI.WebControls;
21 using System.Web.Util;
23 namespace System.Web.Compilation
28 private Stack controls;
29 private ControlStackData top;
30 private bool space_between_tags;
31 private bool sbt_valid;
33 class ControlStackData
35 public Type controlType;
36 public string controlID;
38 public ChildrenKind childKind;
39 public string defaultPropertyName;
40 public int childrenNumber;
41 public Type container;
42 public StringBuilder dataBindFunction;
43 public StringBuilder codeRenderFunction;
44 public bool useCodeRender;
45 public int codeRenderIndex;
47 public ControlStackData (Type controlType,
50 ChildrenKind childKind,
51 string defaultPropertyName,
54 this.controlType = controlType;
55 this.controlID = controlID;
57 this.childKind = childKind;
58 this.defaultPropertyName = defaultPropertyName;
59 this.container = container;
63 public override string ToString ()
65 return controlType + " " + controlID + " " + tagID + " " + childKind + " " + childrenNumber;
69 public ControlStack ()
71 controls = new Stack ();
74 private Type GetContainerType (Type type)
76 if (type != typeof (System.Web.UI.Control) &&
77 !type.IsSubclassOf (typeof (System.Web.UI.Control)))
81 if (type == typeof (System.Web.UI.WebControls.DataList))
82 container_type = typeof (System.Web.UI.WebControls.DataListItem);
83 else if (type == typeof (System.Web.UI.WebControls.DataGrid))
84 container_type = typeof (System.Web.UI.WebControls.DataGridItem);
85 else if (type == typeof (System.Web.UI.WebControls.Repeater))
86 container_type = typeof (System.Web.UI.WebControls.RepeaterItem);
87 else if (type == typeof (ListControl) || type.IsSubclassOf (typeof (ListControl)))
88 container_type = type;
90 container_type = Container;
92 return container_type;
95 public void Push (object o)
97 if (!(o is ControlStackData))
101 top = (ControlStackData) o;
105 public void Push (Type controlType,
108 ChildrenKind childKind,
109 string defaultPropertyName)
111 Type container_type = null;
112 if (controlType != null){
114 container_type = GetContainerType (controlType);
115 if (container_type == null)
116 container_type = this.Container;
119 top = new ControlStackData (controlType,
131 object item = controls.Pop ();
132 if (controls.Count != 0)
133 top = (ControlStackData) controls.Peek ();
138 public Type PeekType ()
140 return top.controlType;
143 public string PeekControlID ()
145 return top.controlID;
148 public string PeekTagID ()
153 public ChildrenKind PeekChildKind ()
155 return top.childKind;
158 public string PeekDefaultPropertyName ()
160 return top.defaultPropertyName;
163 public void AddChild ()
166 top.childrenNumber++;
169 public bool HasDataBindFunction ()
171 if (top.dataBindFunction == null || top.dataBindFunction.Length == 0)
176 public bool UseCodeRender
179 if (top.codeRenderFunction == null || top.codeRenderFunction.Length == 0)
181 return top.useCodeRender;
184 set { top.useCodeRender= value; }
187 public bool SpaceBetweenTags
192 Type type = top.controlType;
193 if (type.Namespace == "System.Web.UI.WebControls")
194 space_between_tags = true;
195 else if (type.IsSubclassOf (typeof (System.Web.UI.WebControls.WebControl)))
196 space_between_tags = true;
197 else if (type == typeof (System.Web.UI.HtmlControls.HtmlSelect))
198 space_between_tags = true;
199 else if (type == typeof (System.Web.UI.HtmlControls.HtmlTable))
200 space_between_tags = true;
201 else if (type == typeof (System.Web.UI.HtmlControls.HtmlTableRow))
202 space_between_tags = true;
203 else if (type == typeof (System.Web.UI.HtmlControls.HtmlTableCell))
204 space_between_tags = true;
206 space_between_tags = false;
208 return space_between_tags;
212 public Type Container {
217 return top.container;
221 public StringBuilder DataBindFunction
224 if (top.dataBindFunction == null)
225 top.dataBindFunction = new StringBuilder ();
226 return top.dataBindFunction;
230 public int CodeRenderIndex {
232 return top.codeRenderIndex++;
236 public StringBuilder CodeRenderFunction
239 if (top.codeRenderFunction == null)
240 top.codeRenderFunction = new StringBuilder ();
241 return top.codeRenderFunction;
245 public int ChildIndex
247 get { return top.childrenNumber - 1; }
252 get { return controls.Count; }
255 public override string ToString ()
257 return top.ToString () + " " + top.useCodeRender;
262 class ArrayListWrapper
264 private ArrayList list;
267 public ArrayListWrapper (ArrayList list)
273 private void CheckIndex ()
275 if (index == -1 || index == list.Count)
276 throw new InvalidOperationException ();
279 public object Current
288 list [index] = value;
292 public bool MoveNext ()
294 if (index < list.Count)
297 return index < list.Count;
303 private object [] parts;
304 private ArrayListWrapper elements;
305 private StringBuilder prolog;
306 private StringBuilder declarations;
307 private StringBuilder script;
308 private StringBuilder constructor;
309 private StringBuilder init_funcs;
310 private StringBuilder epilog;
311 private StringBuilder current_function;
312 private Stack functions;
313 private ControlStack controls;
314 private bool parse_ok;
315 private bool has_form_tag;
316 private AspComponentFoundry aspFoundry;
318 private string classDecl;
319 private string className;
320 private string interfaces;
321 private string basetype;
322 private string parent;
323 private Type parentType;
324 private string fullPath;
327 string privateBinPath;
328 string main_directive;
329 static string app_file_wrong = "The content in the application file is not valid.";
337 SessionState sessionState = SessionState.Enabled;
339 static Type styleType = typeof (System.Web.UI.WebControls.Style);
340 static Type fontinfoType = typeof (System.Web.UI.WebControls.FontInfo);
342 enum UserControlResult
346 CompilationFailed = 2
356 public AspGenerator (string pathToFile, ArrayList elements)
358 if (elements == null)
359 throw new ArgumentNullException ();
361 this.elements = new ArrayListWrapper (elements);
362 string filename = Path.GetFileName (pathToFile);
363 this.className = filename.Replace ('.', '_'); // Overridden by @ Page classname
364 this.className = className.Replace ('-', '_');
365 this.className = className.Replace (' ', '_');
366 Options ["ClassName"] = this.className;
367 this.fullPath = Path.GetFullPath (pathToFile);
369 this.has_form_tag = false;
370 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
371 privateBinPath = setup.PrivateBinPath;
372 // This is a hack until we can run stuff in different domains
373 if (privateBinPath == null || privateBinPath.Length == 0)
374 privateBinPath = "bin";
376 if (!Path.IsPathRooted (privateBinPath))
377 privateBinPath = Path.Combine (setup.ApplicationBase, privateBinPath);
382 public string BaseType {
383 get { return basetype; }
390 isUserControl = (basetype == "System.Web.UI.UserControl");
391 isPage = (basetype == "System.Web.UI.Page");
392 isApplication = (basetype == "System.Web.HttpApplication");
396 public bool IsUserControl {
397 get { return isUserControl; }
401 get { return isPage; }
404 public bool IsApplication {
405 get { return isApplication; }
408 public string Interfaces {
409 get { return interfaces; }
412 public Hashtable Options {
415 options = new Hashtable ();
421 internal HttpContext Context {
422 get { return context; }
423 set { context = value; }
426 bool AddUsing (string nspace)
428 string _using = "using " + nspace + ";";
429 if (prolog.ToString ().IndexOf (_using) == -1) {
430 prolog.AppendFormat ("\t{0}\n", _using);
437 void AddInterface (Type type)
439 AddInterface (type.ToString ());
442 public void AddInterface (string iface)
444 if (interfaces == null) {
445 interfaces = ", " + iface;
447 string s = ", " + iface;
448 if (interfaces.IndexOf (s) == -1)
453 private AspComponentFoundry Foundry
456 if (aspFoundry == null)
457 aspFoundry = new AspComponentFoundry ();
465 controls = new ControlStack ();
466 controls.Push (typeof (System.Web.UI.Control), "Root", null, ChildrenKind.CONTROLS, null);
467 prolog = new StringBuilder ();
468 declarations = new StringBuilder ();
469 script = new StringBuilder ();
470 constructor = new StringBuilder ();
471 init_funcs = new StringBuilder ();
472 epilog = new StringBuilder ();
474 current_function = new StringBuilder ();
475 functions = new Stack ();
476 functions.Push (current_function);
478 parts = new Object [6];
480 parts [1] = declarations;
482 parts [3] = constructor;
483 parts [4] = init_funcs;
486 prolog.Append ("namespace ASP {\n" +
487 "\tusing System;\n" +
488 "\tusing System.Collections;\n" +
489 "\tusing System.Collections.Specialized;\n" +
490 "\tusing System.Configuration;\n" +
491 "\tusing System.IO;\n" +
492 "\tusing System.Text;\n" +
493 "\tusing System.Text.RegularExpressions;\n" +
494 "\tusing System.Web;\n" +
495 "\tusing System.Web.Caching;\n" +
496 "\tusing System.Web.Security;\n" +
497 "\tusing System.Web.SessionState;\n" +
498 "\tusing System.Web.UI;\n" +
499 "\tusing System.Web.UI.WebControls;\n" +
500 "\tusing System.Web.UI.HtmlControls;\n");
502 declarations.Append ("\t\tprivate static int __autoHandlers;\n");
504 current_function.Append ("\t\tprivate void __BuildControlTree (System.Web.UI.Control __ctrl)\n\t\t{\n");
506 current_function.Append ("\t\t\tSystem.Web.UI.IParserAccessor __parser = " +
507 "(System.Web.UI.IParserAccessor) __ctrl;\n\n");
509 controls.UseCodeRender = true;
512 public StringReader GetCode ()
515 throw new ApplicationException ("You gotta call ProcessElements () first!");
517 StringBuilder code = new StringBuilder ();
518 for (int i = 0; i < parts.Length; i++)
519 code.Append ((StringBuilder) parts [i]);
521 return new StringReader (code.ToString ());
527 Console.WriteLine ("//Warning!!!: Elements not correctly parsed.");
530 Console.Write (GetCode ().ReadToEnd ());
533 // Regex.Escape () make some illegal escape sequences for a C# source.
534 private string Escape (string input)
539 string output = input.Replace ("\\", "\\\\");
540 output = output.Replace ("\"", "\\\"");
541 output = output.Replace ("\t", "\\t");
542 output = output.Replace ("\r", "\\r");
543 output = output.Replace ("\n", "\\n");
544 output = output.Replace ("\n", "\\n");
548 bool AddProtectedField (Type type, string fieldName)
550 if (parentType == null) {
551 declarations.AppendFormat ("\t\tprotected {0} {1};\n", type.ToString (), fieldName);
555 FieldInfo field = parentType.GetField (fieldName, BindingFlags.Public |
556 BindingFlags.NonPublic |
557 BindingFlags.Instance |
558 BindingFlags.Static);
560 if (field == null || (!field.IsPublic && !field.IsFamily)) {
561 declarations.AppendFormat ("\t\tprotected {0} {1};\n", type.ToString (), fieldName);
565 if (!field.FieldType.IsAssignableFrom (type)) {
566 string message = String.Format ("The base class includes the field '{0}', but its " +
567 "type '{1}' is not compatible with {2}",
568 fieldName, field.FieldType, type);
570 throw new ApplicationException (message);
576 private Type LoadParentType (string typeName)
578 // First try loaded assemblies, then try assemblies in Bin directory.
579 // By now i do this 'by hand' but may be this is a runtime/gac task.
581 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
582 foreach (Assembly ass in assemblies) {
583 type = ass.GetType (typeName);
589 string [] binDlls = Directory.GetFiles (privateBinPath, "*.dll");
590 foreach (string dll in binDlls) {
591 string dllPath = Path.Combine (privateBinPath, dll);
594 assembly = Assembly.LoadFrom (dllPath);
595 type = assembly.GetType (typeName);
596 } catch (Exception e) {
597 if (assembly != null) {
598 Console.WriteLine ("ASP.NET Warning: assembly {0} loaded", dllPath);
599 Console.WriteLine ("ASP.NET Warning: but type {0} not found", typeName);
601 Console.WriteLine ("ASP.NET Warning: unable to load type {0} from {1}",
604 Console.WriteLine ("ASP.NET Warning: error was: {0}", e.Message);
614 private void PageDirective (TagAttributes att)
616 if (att ["ClassName"] != null){
617 this.className = (string) att ["ClassName"];
618 Options ["ClassName"] = className;
621 if (att ["EnableSessionState"] != null){
623 throw new ApplicationException ("EnableSessionState not allowed here.");
625 string est = (string) att ["EnableSessionState"];
626 if (0 == String.Compare (est, "false", true))
627 sessionState = SessionState.Disabled;
628 else if (0 == String.Compare (est, "true", true))
629 sessionState = SessionState.Enabled;
630 else if (0 == String.Compare (est, "readonly", true))
631 sessionState = SessionState.ReadOnly;
633 throw new ApplicationException ("EnableSessionState in Page directive not set to " +
634 "a correct value: " + est);
637 if (att ["Inherits"] != null) {
638 parent = (string) att ["Inherits"];
639 parentType = LoadParentType (parent);
640 if (parentType == null)
641 throw new ApplicationException ("The class " + parent + " cannot be found.");
644 if (att ["CompilerOptions"] != null)
645 Options ["CompilerOptions"] = (string) att ["CompilerOptions"];
647 if (att ["AutoEventWireup"] != null) {
648 if (options ["AutoEventWireup"] != null)
649 throw new ApplicationException ("Already have an AutoEventWireup attribute");
651 bool autoevent = true;
652 string v = att ["AutoEventWireup"] as string;
654 autoevent = Convert.ToBoolean (v);
655 } catch (Exception) {
656 throw new ApplicationException ("'" + v + "' is not a valid value for AutoEventWireup");
658 options ["AutoEventWireup"] = autoevent;
661 //FIXME: add support for more attributes.
664 void AddReference (string dll)
666 string references = Options ["References"] as string;
667 if (references == null)
670 references = references + " " + dll;
672 Options ["References"] = references;
675 private void RegisterDirective (TagAttributes att)
677 string tag_prefix = (string) (att ["tagprefix"] == null ? "" : att ["tagprefix"]);
678 string name_space = (string) (att ["namespace"] == null ? "" : att ["namespace"]);
679 string assembly_name = (string) (att ["assembly"] == null ? "" : att ["assembly"]);
680 string tag_name = (string) (att ["tagname"] == null ? "" : att ["tagname"]);
681 string src = (string) (att ["src"] == null ? "" : att ["src"]);
683 if (tag_prefix != "" && name_space != "" && assembly_name != ""){
684 if (tag_name != "" || src != "")
685 throw new ApplicationException ("Invalid attributes for @ Register: " +
688 AddUsing (name_space);
689 string dll = privateBinPath + Path.DirectorySeparatorChar + assembly_name + ".dll";
690 // Hack: it should use assembly.load semantics...
691 // may be when we don't run mcs as a external program...
692 if (!File.Exists (dll))
695 Foundry.RegisterFoundry (tag_prefix, dll, name_space);
700 if (tag_prefix != "" && tag_name != "" && src != ""){
701 if (name_space != "" && assembly_name != "")
702 throw new ApplicationException ("Invalid attributes for @ Register: " +
705 if (!src.EndsWith (".ascx"))
706 throw new ApplicationException ("Source file extension for controls " +
709 UserControlData data = GenerateUserControl (src, Context);
710 switch (data.result) {
711 case UserControlResult.OK:
713 Foundry.RegisterFoundry (tag_prefix, tag_name, data.assemblyName, "ASP", data.className);
714 AddReference (data.assemblyName);
716 case UserControlResult.FileNotFound:
717 throw new ApplicationException ("File '" + src + "' not found.");
718 case UserControlResult.CompilationFailed:
719 //TODO: should say where the generated .cs file is for the server to
720 //show the source and the compiler error
721 throw new NotImplementedException ();
726 throw new ApplicationException ("Invalid combination of attributes in " +
727 "@ Register: " + att.ToString ());
730 private void ProcessDirective ()
732 Directive directive = (Directive) elements.Current;
733 TagAttributes att = directive.Attributes;
738 string id = directive.TagID.ToUpper ();
741 if (main_directive != null)
742 throw new ApplicationException (id + " not allowed after " + main_directive);
745 throw new ApplicationException ("@Application not allowed.");
747 string inherits = att ["inherits"] as string;
748 if (inherits != null)
749 Options ["Inherits"] = inherits;
751 main_directive = directive.TagID;
755 if (main_directive != null)
756 throw new ApplicationException (id + " not allowed after " + main_directive);
758 if (IsUserControl && id != "CONTROL")
759 throw new ApplicationException ("@Page not allowed for user controls.");
760 else if (IsPage && id != "PAGE")
761 throw new ApplicationException ("@Control not allowed here. This is a page!");
764 main_directive = directive.TagID;
767 value = att ["namespace"] as string;
768 if (value == null || att.Count > 1)
769 throw new ApplicationException ("Wrong syntax in Import directive.");
771 string _using = "using " + value + ";";
772 if (AddUsing (value) == true) {
773 string imports = Options ["Import"] as string;
774 if (imports == null) {
777 imports += "," + value;
780 Options ["Import"] = imports;
785 throw new ApplicationException ("@ Implements not allowed in an application file.");
787 string iface = (string) att ["interface"];
788 AddInterface (iface);
792 throw new ApplicationException ("@ Register not allowed in an application file.");
794 RegisterDirective (att);
798 throw new ApplicationException ("Wrong syntax in Assembly directive.");
800 string name = att ["name"] as string;
801 string src = att ["src"] as string;
803 if (name == null && src == null)
804 throw new ApplicationException ("Wrong syntax in Assembly directive.");
806 if (IsApplication && src != null)
807 throw new ApplicationException ("'name' attribute expected.");
809 value = (name == null) ? src : name;
810 string assemblies = Options ["Assembly"] as string;
811 if (assemblies == null) {
814 assemblies += "," + value;
817 Options ["Assembly"] = assemblies;
822 private void ProcessPlainText ()
824 PlainText asis = (PlainText) elements.Current;
825 string trimmed = asis.Text.Trim ();
826 if (trimmed == String.Empty && controls.SpaceBetweenTags == true)
830 if (trimmed != String.Empty)
831 throw new ApplicationException (app_file_wrong);
835 if (trimmed != String.Empty && controls.PeekChildKind () != ChildrenKind.CONTROLS){
836 string tag_id = controls.PeekTagID ();
837 throw new ApplicationException ("Literal content not allowed for " + tag_id);
840 string escaped_text = Escape (asis.Text);
841 current_function.AppendFormat ("\t\t\t__parser.AddParsedSubObject (" +
842 "new System.Web.UI.LiteralControl (\"{0}\"));\n",
844 StringBuilder codeRenderFunction = controls.CodeRenderFunction;
845 codeRenderFunction.AppendFormat ("\t\t\t__output.Write (\"{0}\");\n", escaped_text);
848 private string EnumValueNameToString (Type enum_type, string value_name)
850 if (value_name.EndsWith ("*"))
851 throw new ApplicationException ("Invalid property value: '" + value_name +
852 ". It must be a valid " + enum_type.ToString () + " value.");
854 MemberInfo [] nested_types = enum_type.FindMembers (MemberTypes.Field,
855 BindingFlags.Public | BindingFlags.Static,
856 Type.FilterNameIgnoreCase,
859 if (nested_types.Length == 0)
860 throw new ApplicationException ("Value " + value_name + " not found in enumeration " +
861 enum_type.ToString ());
862 if (nested_types.Length > 1)
863 throw new ApplicationException ("Value " + value_name + " found " +
864 nested_types.Length + " in enumeration " +
865 enum_type.ToString ());
867 return enum_type.ToString () + "." + nested_types [0].Name;
870 private void NewControlFunction (string tag_id,
873 ChildrenKind children_kind,
874 string defaultPropertyName)
876 ChildrenKind prev_children_kind = controls.PeekChildKind ();
877 if (prev_children_kind == ChildrenKind.NONE ||
878 prev_children_kind == ChildrenKind.PROPERTIES){
879 string prev_tag_id = controls.PeekTagID ();
880 throw new ApplicationException ("Child controls not allowed for " + prev_tag_id);
883 if (prev_children_kind == ChildrenKind.DBCOLUMNS &&
884 control_type != typeof (System.Web.UI.WebControls.DataGridColumn) &&
885 !control_type.IsSubclassOf (typeof (System.Web.UI.WebControls.DataGridColumn)))
886 throw new ApplicationException ("Inside " + controls.PeekTagID () + " only " +
887 "System.Web.UI.WebControls.DataGridColum " +
888 "objects are allowed");
889 else if (prev_children_kind == ChildrenKind.LISTITEM &&
890 control_type != typeof (System.Web.UI.WebControls.ListItem))
891 throw new ApplicationException ("Inside " + controls.PeekTagID () + " only " +
892 "System.Web.UI.WebControls.ListItem " +
893 "objects are allowed");
894 else if (prev_children_kind == ChildrenKind.HTMLROW &&
895 control_type != typeof (System.Web.UI.HtmlControls.HtmlTableRow))
896 throw new ApplicationException ("Inside " + controls.PeekTagID () + " only " +
897 "System.Web.UI.HtmlControls.HtmlTableRow " +
898 "objects are allowed");
899 else if (prev_children_kind == ChildrenKind.HTMLCELL &&
900 control_type != typeof (System.Web.UI.HtmlControls.HtmlTableCell))
901 throw new ApplicationException ("Inside " + controls.PeekTagID () + " only " +
902 "System.Web.UI.HtmlControls.HtmlTableCell " +
903 "objects are allowed");
906 StringBuilder func_code = new StringBuilder ();
907 current_function = func_code;
908 if (0 == String.Compare (tag_id, "form", true)){
910 throw new ApplicationException ("Only one form server tag allowed.");
914 controls.Push (control_type, control_id, tag_id, children_kind, defaultPropertyName);
915 bool is_generic = control_type == typeof (System.Web.UI.HtmlControls.HtmlGenericControl);
916 functions.Push (current_function);
917 if (control_type != typeof (System.Web.UI.WebControls.ListItem) &&
918 prev_children_kind != ChildrenKind.DBCOLUMNS) {
919 current_function.AppendFormat ("\t\tprivate System.Web.UI.Control __BuildControl_" +
920 "{0} ()\n\t\t{{\n\t\t\t{1} __ctrl;\n\n\t\t\t__ctrl" +
921 " = new {1} ({2});\n\t\t\tthis.{0} = __ctrl;\n",
922 control_id, control_type,
923 (is_generic? "\"" + tag_id + "\"" : ""));
925 current_function.AppendFormat ("\t\tprivate void __BuildControl_{0} ()\n\t\t{{" +
926 "\n\t\t\t{1} __ctrl;\n\t\t\t__ctrl = new {1} ();" +
927 "\n\t\t\tthis.{0} = __ctrl;\n",
928 control_id, control_type);
931 if (children_kind == ChildrenKind.CONTROLS || children_kind == ChildrenKind.OPTION)
932 current_function.Append ("\t\t\tSystem.Web.UI.IParserAccessor __parser = " +
933 "(System.Web.UI.IParserAccessor) __ctrl;\n");
936 private void DataBoundProperty (Type target, string varName, string value)
939 throw new ApplicationException ("Empty data binding tag.");
941 string control_id = controls.PeekControlID ();
942 string control_type_string = controls.PeekType ().ToString ();
943 StringBuilder db_function = controls.DataBindFunction;
945 if (controls.Container == null || !typeof (INamingContainer).IsAssignableFrom (controls.Container))
946 container = "System.Web.UI.Control";
948 container = controls.Container.ToString ();
951 if (db_function.Length == 0)
952 db_function.AppendFormat ("\t\tpublic void __DataBind_{0} (object sender, " +
953 "System.EventArgs e) {{\n" +
954 "\t\t\t{1} Container;\n" +
955 "\t\t\t{2} target;\n" +
956 "\t\t\ttarget = ({2}) sender;\n" +
957 "\t\t\tContainer = ({1}) target.BindingContainer;\n",
958 control_id, container, control_type_string);
960 /* Removes '<%#' and '%>' */
961 string real_value = value.Remove (0,3);
962 real_value = real_value.Remove (real_value.Length - 2, 2);
963 real_value = real_value.Trim ();
965 if (target == typeof (string))
966 db_function.AppendFormat ("\t\t\ttarget.{0} = System.Convert.ToString ({1});\n",
967 varName, real_value);
969 db_function.AppendFormat ("\t\t\ttarget.{0} = ({1}) ({2});\n",
970 varName, target, real_value);
974 * Returns true if it generates some code for the specified property
976 private void AddCodeForPropertyOrField (Type type, string var_name, string att, bool isDataBound)
978 /* FIXME: should i check for this or let the compiler fail?
979 * if (!prop.CanWrite)
983 DataBoundProperty (type, var_name, att);
985 else if (type == typeof (string)){
987 throw new ApplicationException ("null value for attribute " + var_name );
989 current_function.AppendFormat ("\t\t\t__ctrl.{0} = \"{1}\";\n", var_name,
990 Escape (att)); // FIXME: really Escape this?
992 else if (type.IsEnum){
994 throw new ApplicationException ("null value for attribute " + var_name );
996 string enum_value = EnumValueNameToString (type, att);
998 current_function.AppendFormat ("\t\t\t__ctrl.{0} = {1};\n", var_name, enum_value);
1000 else if (type == typeof (bool)){
1003 value = "true"; //FIXME: is this ok for non Style properties?
1004 else if (0 == String.Compare (att, "true", true))
1006 else if (0 == String.Compare (att, "false", true))
1009 throw new ApplicationException ("Value '" + att + "' is not a valid boolean.");
1011 current_function.AppendFormat ("\t\t\t__ctrl.{0} = {1};\n", var_name, value);
1013 else if (type == typeof (System.Web.UI.WebControls.Unit)){
1014 //FIXME: should use the culture specified in Page
1016 Unit value = Unit.Parse (att, System.Globalization.CultureInfo.InvariantCulture);
1017 } catch (Exception) {
1018 throw new ApplicationException ("'" + att + "' cannot be parsed as a unit.");
1020 current_function.AppendFormat ("\t\t\t__ctrl.{0} = " +
1021 "System.Web.UI.WebControls.Unit.Parse (\"{1}\", " +
1022 "System.Globalization.CultureInfo.InvariantCulture);\n",
1025 else if (type == typeof (System.Web.UI.WebControls.FontUnit)){
1026 //FIXME: should use the culture specified in Page
1028 FontUnit value = FontUnit.Parse (att, System.Globalization.CultureInfo.InvariantCulture);
1029 } catch (Exception) {
1030 throw new ApplicationException ("'" + att + "' cannot be parsed as a unit.");
1032 current_function.AppendFormat ("\t\t\t__ctrl.{0} = " +
1033 "System.Web.UI.WebControls.FontUnit.Parse (\"{1}\", " +
1034 "System.Globalization.CultureInfo.InvariantCulture);\n",
1037 else if (type == typeof (Int16) || type == typeof (Int32) || type == typeof (Int64)) {
1040 value = Int64.Parse (att); //FIXME: should use the culture specified in Page
1041 } catch (Exception){
1042 throw new ApplicationException (att + " is not a valid signed number " +
1043 "or is out of range.");
1046 current_function.AppendFormat ("\t\t\t__ctrl.{0} = {1};\n", var_name, value);
1048 else if (type == typeof (UInt16) || type == typeof (UInt32) || type == typeof (UInt64)) {
1051 value = UInt64.Parse (att); //FIXME: should use the culture specified in Page
1052 } catch (Exception){
1053 throw new ApplicationException (att + " is not a valid unsigned number " +
1054 "or is out of range.");
1057 current_function.AppendFormat ("\t\t\t__ctrl.{0} = {1};\n", var_name, value);
1059 else if (type == typeof (float)) {
1062 value = Single.Parse (att);
1063 } catch (Exception){
1064 throw new ApplicationException (att + " is not avalid float number or " +
1065 "is out of range.");
1068 current_function.AppendFormat ("\t\t\t__ctrl.{0} = {1};\n", var_name, value);
1070 else if (type == typeof (double)){
1073 value = Double.Parse (att);
1074 } catch (Exception){
1075 throw new ApplicationException (att + " is not avalid double number or " +
1076 "is out of range.");
1079 current_function.AppendFormat ("\t\t\t__ctrl.{0} = {1};\n", var_name, value);
1081 else if (type == typeof (System.Drawing.Color)){
1084 c = (Color) TypeDescriptor.GetConverter (typeof (Color)).ConvertFromString (att);
1085 } catch (Exception e){
1086 throw new ApplicationException ("Color " + att + " is not a valid color.", e);
1089 // Should i also test for IsSystemColor?
1090 // Are KnownColor members in System.Drawing.Color?
1091 if (c.IsKnownColor){
1092 current_function.AppendFormat ("\t\t\t__ctrl.{0} = System.Drawing.Color." +
1093 "{1};\n", var_name, c.Name);
1096 current_function.AppendFormat ("\t\t\t__ctrl.{0} = System.Drawing.Color." +
1097 "FromArgb ({1}, {2}, {3}, {4});\n",
1098 var_name, c.A, c.R, c.G, c.B);
1101 else if (type == typeof (string [])) {
1102 string [] subStrings = att.Split (',');
1103 current_function.AppendFormat ("\t\t\t__ctrl.{0} = new String [] {{\n", var_name);
1104 int end = subStrings.Length;
1105 for (int i = 0; i < end; i++) {
1106 string s = subStrings [i].Trim ();
1107 current_function.AppendFormat ("\t\t\t\t\"{0}\"", s);
1109 current_function.Append ("\t\t\t\t};\n");
1111 current_function.Append (",\n");
1114 throw new ApplicationException ("Unsupported type in property: " +
1119 private bool ProcessPropertiesAndFields (MemberInfo member, string id, TagAttributes att)
1121 int hyphen = id.IndexOf ('-');
1123 bool isPropertyInfo = (member is PropertyInfo);
1125 bool is_processed = false;
1126 bool isDataBound = att.IsDataBound ((string) att [id]);
1128 if (isPropertyInfo) {
1129 type = ((PropertyInfo) member).PropertyType;
1130 if (hyphen == -1 && ((PropertyInfo) member).CanWrite == false)
1133 type = ((FieldInfo) member).FieldType;
1136 if (0 == String.Compare (member.Name, id, true)){
1137 AddCodeForPropertyOrField (type, member.Name, (string) att [id], isDataBound);
1138 is_processed = true;
1139 } else if (hyphen != -1 && (type == fontinfoType || type == styleType || type.IsSubclassOf (styleType))){
1140 string prop_field = id.Replace ("-", ".");
1141 string [] parts = prop_field.Split (new char [] {'.'});
1142 if (parts.Length != 2 || 0 != String.Compare (member.Name, parts [0], true))
1145 PropertyInfo [] subprops = type.GetProperties ();
1146 foreach (PropertyInfo subprop in subprops){
1147 if (0 != String.Compare (subprop.Name, parts [1], true))
1150 if (subprop.CanWrite == false)
1153 bool is_bool = subprop.PropertyType == typeof (bool);
1154 if (!is_bool && att [id] == null){
1155 att [id] = ""; // Font-Size -> Font-Size="" as html
1160 if (att [id] == null && is_bool)
1161 value = "true"; // Font-Bold <=> Font-Bold="true"
1163 value = (string) att [id];
1165 AddCodeForPropertyOrField (subprop.PropertyType,
1166 member.Name + "." + subprop.Name,
1167 value, isDataBound);
1168 is_processed = true;
1172 return is_processed;
1175 private void AddCodeForAttributes (Type type, TagAttributes att)
1177 EventInfo [] ev_info = type.GetEvents ();
1178 PropertyInfo [] prop_info = type.GetProperties ();
1179 FieldInfo [] field_info = type.GetFields ();
1180 bool is_processed = false;
1181 ArrayList processed = new ArrayList ();
1183 foreach (string id in att.Keys){
1184 if (0 == String.Compare (id, "runat", true) || 0 == String.Compare (id, "id", true))
1187 if (id.Length > 2 && id.Substring (0, 2).ToUpper () == "ON"){
1188 string id_as_event = id.Substring (2);
1189 foreach (EventInfo ev in ev_info){
1190 if (0 == String.Compare (ev.Name, id_as_event, true)){
1191 current_function.AppendFormat (
1192 "\t\t\t__ctrl.{0} += " +
1193 "new {1} (this.{2});\n",
1194 ev.Name, ev.EventHandlerType, att [id]);
1195 is_processed = true;
1200 is_processed = false;
1205 foreach (PropertyInfo prop in prop_info){
1206 is_processed = ProcessPropertiesAndFields (prop, id, att);
1211 if (!is_processed) {
1212 foreach (FieldInfo field in field_info){
1213 is_processed = ProcessPropertiesAndFields (field, id, att);
1220 is_processed = false;
1224 current_function.AppendFormat ("\t\t\t((System.Web.UI.IAttributeAccessor) __ctrl)." +
1225 "SetAttribute (\"{0}\", \"{1}\");\n",
1226 id, Escape ((string) att [id]));
1230 private void AddCodeRenderControl (StringBuilder function)
1232 AddCodeRenderControl (function, controls.CodeRenderIndex);
1235 private void AddCodeRenderControl (StringBuilder function, int index)
1237 function.AppendFormat ("\t\t\tparameterContainer.Controls [{0}]." +
1238 "RenderControl (__output);\n", index);
1241 private void AddRenderMethodDelegate (StringBuilder function, string control_id)
1243 function.AppendFormat ("\t\t\t__ctrl.SetRenderMethodDelegate (new System.Web." +
1244 "UI.RenderMethod (this.__Render_{0}));\n", control_id);
1247 private void AddCodeRenderFunction (string codeRender, string control_id)
1249 StringBuilder codeRenderFunction = new StringBuilder ();
1250 codeRenderFunction.AppendFormat ("\t\tprivate void __Render_{0} " +
1251 "(System.Web.UI.HtmlTextWriter __output, " +
1252 "System.Web.UI.Control parameterContainer)\n" +
1253 "\t\t{{\n", control_id);
1254 codeRenderFunction.Append (codeRender);
1255 codeRenderFunction.Append ("\t\t}\n\n");
1256 init_funcs.Append (codeRenderFunction);
1259 private void RemoveLiterals (StringBuilder function)
1261 string no_literals = Regex.Replace (function.ToString (),
1262 @"\t\t\t__parser.AddParsedSubObject \(" +
1263 @"new System.Web.UI.LiteralControl \(.+\);\n", "");
1264 function.Length = 0;
1265 function.Append (no_literals);
1268 private bool FinishControlFunction (string tag_id)
1270 if (functions.Count == 0)
1271 throw new ApplicationException ("Unbalanced open/close tags");
1273 if (controls.Count == 0)
1276 string saved_id = controls.PeekTagID ();
1277 if (0 != String.Compare (saved_id, tag_id, true))
1280 StringBuilder old_function = (StringBuilder) functions.Pop ();
1281 current_function = (StringBuilder) functions.Peek ();
1283 string control_id = controls.PeekControlID ();
1284 Type control_type = controls.PeekType ();
1285 ChildrenKind child_kind = controls.PeekChildKind ();
1287 bool hasDataBindFunction = controls.HasDataBindFunction ();
1288 if (hasDataBindFunction)
1289 old_function.AppendFormat ("\t\t\t__ctrl.DataBinding += new System.EventHandler " +
1290 "(this.__DataBind_{0});\n", control_id);
1292 bool useCodeRender = controls.UseCodeRender;
1294 AddRenderMethodDelegate (old_function, control_id);
1296 if (control_type == typeof (System.Web.UI.ITemplate)){
1297 old_function.Append ("\n\t\t}\n\n");
1298 current_function.AppendFormat ("\t\t\t__ctrl.{0} = new System.Web.UI." +
1299 "CompiledTemplateBuilder (new System.Web.UI." +
1300 "BuildTemplateMethod (this.__BuildControl_{1}));\n",
1301 saved_id, control_id);
1303 else if (control_type == typeof (System.Web.UI.WebControls.DataGridColumnCollection)){
1304 old_function.Append ("\n\t\t}\n\n");
1305 current_function.AppendFormat ("\t\t\tthis.__BuildControl_{0} (__ctrl.{1});\n",
1306 control_id, saved_id);
1308 else if (control_type == typeof (System.Web.UI.WebControls.DataGridColumn) ||
1309 control_type.IsSubclassOf (typeof (System.Web.UI.WebControls.DataGridColumn)) ||
1310 control_type == typeof (System.Web.UI.WebControls.ListItem)){
1311 old_function.Append ("\n\t\t}\n\n");
1313 string ctrl_name = "ctrl";
1314 Type cont = controls.Container;
1315 if (cont == null || cont == typeof (System.Web.UI.HtmlControls.HtmlSelect)){
1316 parsed = "ParsedSubObject";
1317 ctrl_name = "parser";
1320 current_function.AppendFormat ("\t\t\tthis.__BuildControl_{0} ();\n" +
1321 "\t\t\t__{1}.Add{2} (this.{0});\n\n",
1322 control_id, ctrl_name, parsed);
1324 else if (child_kind == ChildrenKind.LISTITEM){
1325 old_function.Append ("\n\t\t}\n\n");
1326 init_funcs.Append (old_function); // Closes the BuildList function
1327 old_function = (StringBuilder) functions.Pop ();
1328 current_function = (StringBuilder) functions.Peek ();
1329 old_function.AppendFormat ("\n\t\t\tthis.__BuildControl_{0} (__ctrl.{1});\n\t\t\t" +
1330 "return __ctrl;\n\t\t}}\n\n",
1331 control_id, controls.PeekDefaultPropertyName ());
1334 control_id = controls.PeekControlID ();
1335 current_function.AppendFormat ("\t\t\tthis.__BuildControl_{0} ();\n\t\t\t__parser." +
1336 "AddParsedSubObject (this.{0});\n\n", control_id);
1337 } else if (control_type == typeof (HtmlTableCell)) {
1338 old_function.Append ("\n\t\t\treturn __ctrl;\n\t\t}\n\n");
1339 object top = controls.Pop ();
1340 Type t = controls.PeekType ();
1341 controls.Push (top);
1343 string ctrl_name = "ctrl";
1344 if (t != typeof (HtmlTableRow)) {
1345 parsed = "ParsedSubObject";
1346 ctrl_name = "parser";
1349 current_function.AppendFormat ("\t\t\tthis.__BuildControl_{0} ();\n" +
1350 "\t\t\t__{1}.Add{2} (this.{0});\n\n",
1351 control_id, ctrl_name, parsed);
1352 } else if (child_kind == ChildrenKind.HTMLROW || child_kind == ChildrenKind.HTMLCELL) {
1353 old_function.Append ("\n\t\t}\n\n");
1354 init_funcs.Append (old_function);
1355 old_function = (StringBuilder) functions.Pop ();
1356 current_function = (StringBuilder) functions.Peek ();
1357 old_function.AppendFormat ("\n\t\t\tthis.__BuildControl_{0} (__ctrl.{1});\n\t\t\t" +
1358 "return __ctrl;\n\t\t}}\n\n",
1359 control_id, controls.PeekDefaultPropertyName ());
1362 control_id = controls.PeekControlID ();
1363 current_function.AppendFormat ("\t\t\tthis.__BuildControl_{0} ();\n", control_id);
1364 if (child_kind == ChildrenKind.HTMLROW) {
1365 current_function.AppendFormat ("\t\t\t__parser.AddParsedSubObject ({0});\n",
1368 current_function.AppendFormat ("\t\t\t__ctrl.Add (this.{0});\n", control_id);
1371 old_function.Append ("\n\t\t\treturn __ctrl;\n\t\t}\n\n");
1372 current_function.AppendFormat ("\t\t\tthis.__BuildControl_{0} ();\n\t\t\t__parser." +
1373 "AddParsedSubObject (this.{0});\n\n", control_id);
1377 RemoveLiterals (old_function);
1379 init_funcs.Append (old_function);
1381 AddCodeRenderFunction (controls.CodeRenderFunction.ToString (), control_id);
1383 if (hasDataBindFunction){
1384 StringBuilder db_function = controls.DataBindFunction;
1385 db_function.Append ("\t\t}\n\n");
1386 init_funcs.Append (db_function);
1389 // Avoid getting empty stacks for unbalanced open/close tags
1390 if (controls.Count > 1){
1392 AddCodeRenderControl (controls.CodeRenderFunction, controls.ChildIndex);
1398 private void NewTableElementFunction (HtmlControlTag ctrl)
1400 string control_id = Tag.GetDefaultID ();
1401 ChildrenKind child_kind;
1404 if (ctrl.ControlType == typeof (HtmlTable)) {
1405 t = typeof (HtmlTableRowCollection);
1406 child_kind = ChildrenKind.HTMLROW;
1408 t = typeof (HtmlTableCellCollection);
1409 child_kind = ChildrenKind.HTMLCELL;
1412 controls.Push (ctrl.ControlType,
1416 ctrl.ParseChildren);
1419 current_function = new StringBuilder ();
1420 functions.Push (current_function);
1421 current_function.AppendFormat ("\t\tprivate void __BuildControl_{0} ({1} __ctrl)\n" +
1422 "\t\t{{\n", control_id, t);
1425 private void ProcessHtmlControlTag ()
1427 HtmlControlTag html_ctrl = (HtmlControlTag) elements.Current;
1428 if (html_ctrl.TagID.ToUpper () == "SCRIPT"){
1429 //FIXME: if the is script is to be read from disk, do it!
1430 if (html_ctrl.SelfClosing)
1431 throw new ApplicationException ("Read script from file not supported yet.");
1433 if (elements.MoveNext () == false)
1434 throw new ApplicationException ("Error after " + html_ctrl.ToString ());
1436 if (elements.Current is PlainText){
1437 script.Append (((PlainText) elements.Current).Text);
1438 if (!elements.MoveNext ())
1439 throw new ApplicationException ("Error after " +
1440 elements.Current.ToString ());
1443 if (elements.Current is CloseTag)
1444 elements.MoveNext ();
1446 } else if (IsApplication) {
1447 throw new ApplicationException (app_file_wrong);
1450 Type controlType = html_ctrl.ControlType;
1451 AddProtectedField (controlType, html_ctrl.ControlID);
1453 ChildrenKind children_kind;
1454 if (0 == String.Compare (html_ctrl.TagID, "table", true))
1455 children_kind = ChildrenKind.HTMLROW;
1456 else if (0 == String.Compare (html_ctrl.TagID, "tr", true))
1457 children_kind = ChildrenKind.HTMLCELL;
1458 else if (0 != String.Compare (html_ctrl.TagID, "select", true))
1459 children_kind = html_ctrl.IsContainer ? ChildrenKind.CONTROLS :
1462 children_kind = ChildrenKind.OPTION;
1464 NewControlFunction (html_ctrl.TagID, html_ctrl.ControlID, controlType, children_kind, html_ctrl.ParseChildren);
1466 current_function.AppendFormat ("\t\t\t__ctrl.ID = \"{0}\";\n", html_ctrl.ControlID);
1467 AddCodeForAttributes (html_ctrl.ControlType, html_ctrl.Attributes);
1469 if (children_kind == ChildrenKind.HTMLROW || children_kind == ChildrenKind.HTMLCELL)
1470 NewTableElementFunction (html_ctrl);
1472 if (!html_ctrl.SelfClosing)
1475 FinishControlFunction (html_ctrl.TagID);
1478 // Closing is performed in FinishControlFunction ()
1479 private void NewBuildListFunction (AspComponent component)
1481 string control_id = Tag.GetDefaultID ();
1483 controls.Push (component.ComponentType,
1486 ChildrenKind.LISTITEM,
1487 component.DefaultPropertyName);
1489 current_function = new StringBuilder ();
1490 functions.Push (current_function);
1491 current_function.AppendFormat ("\t\tprivate void __BuildControl_{0} " +
1492 "(System.Web.UI.WebControls.ListItemCollection __ctrl)\n" +
1493 "\t\t{{\n", control_id);
1496 private void ProcessComponent ()
1498 AspComponent component = (AspComponent) elements.Current;
1499 Type component_type = component.ComponentType;
1500 AddProtectedField (component_type, component.ControlID);
1502 NewControlFunction (component.TagID, component.ControlID, component_type,
1503 component.ChildrenKind, component.DefaultPropertyName);
1505 if (component_type == typeof (UserControl) ||
1506 component_type.IsSubclassOf (typeof (System.Web.UI.UserControl)))
1507 current_function.Append ("\t\t\t__ctrl.InitializeAsUserControl (Page);\n");
1509 if (component_type == typeof (Control) ||
1510 component_type.IsSubclassOf (typeof (System.Web.UI.Control)))
1511 current_function.AppendFormat ("\t\t\t__ctrl.ID = \"{0}\";\n", component.ControlID);
1513 AddCodeForAttributes (component.ComponentType, component.Attributes);
1514 if (component.ChildrenKind == ChildrenKind.LISTITEM)
1515 NewBuildListFunction (component);
1517 if (!component.SelfClosing)
1520 FinishControlFunction (component.TagID);
1523 private void ProcessServerObjectTag ()
1525 ServerObjectTag obj = (ServerObjectTag) elements.Current;
1526 declarations.AppendFormat ("\t\tprivate {0} cached{1};\n", obj.ObjectClass, obj.ObjectID);
1527 constructor.AppendFormat ("\n\t\tprivate {0} {1}\n\t\t{{\n\t\t\tget {{\n\t\t\t\t" +
1528 "if (this.cached{1} == null)\n\t\t\t\t\tthis.cached{1} = " +
1529 "new {0} ();\n\t\t\t\treturn cached{1};\n\t\t\t}}\n\t\t}}\n\n",
1530 obj.ObjectClass, obj.ObjectID);
1533 // Creates a new function that sets the values of subproperties.
1534 private void NewStyleFunction (PropertyTag tag)
1536 current_function = new StringBuilder ();
1538 string prop_id = tag.PropertyID;
1539 Type prop_type = tag.PropertyType;
1541 current_function.AppendFormat ("\t\tprivate void __BuildControl_{0} ({1} __ctrl)\n" +
1542 "\t\t{{\n", prop_id, prop_type);
1544 // Add property initialization code
1545 PropertyInfo [] subprop_info = prop_type.GetProperties ();
1546 TagAttributes att = tag.Attributes;
1548 string subprop_name = null;
1549 foreach (string id in att.Keys){
1550 if (0 == String.Compare (id, "runat", true) || 0 == String.Compare (id, "id", true))
1553 bool is_processed = false;
1554 foreach (PropertyInfo subprop in subprop_info){
1555 is_processed = ProcessPropertiesAndFields (subprop, id, att);
1557 subprop_name = subprop.Name;
1562 if (subprop_name == null)
1563 throw new ApplicationException ("Property " + tag.TagID + " does not have " +
1564 "a " + id + " subproperty.");
1568 current_function.Append ("\n\t\t}\n\n");
1569 init_funcs.Append (current_function);
1570 current_function = (StringBuilder) functions.Peek ();
1571 current_function.AppendFormat ("\t\t\tthis.__BuildControl_{0} (__ctrl.{1});\n",
1572 prop_id, tag.PropertyName);
1574 if (!tag.SelfClosing){
1575 // Next tag should be the closing tag
1576 controls.Push (null, null, null, ChildrenKind.NONE, null);
1577 bool closing_tag_found = false;
1579 while (!closing_tag_found && elements.MoveNext ()){
1580 elem = (Element) elements.Current;
1581 if (elem is PlainText)
1582 ProcessPlainText ();
1583 else if (!(elem is CloseTag))
1584 throw new ApplicationException ("Tag " + tag.TagID +
1585 " not properly closed.");
1587 closing_tag_found = true;
1590 if (!closing_tag_found)
1591 throw new ApplicationException ("Tag " + tag.TagID + " not properly closed.");
1597 // This one just opens the function. Closing is performed in FinishControlFunction ()
1598 private void NewTemplateFunction (PropertyTag tag)
1602 * This function does almost the same as NewControlFunction.
1605 string prop_id = tag.PropertyID;
1606 Type prop_type = tag.PropertyType;
1607 string tag_id = tag.PropertyName; // Real property name used in FinishControlFunction
1609 controls.Push (prop_type, prop_id, tag_id, ChildrenKind.CONTROLS, null);
1610 current_function = new StringBuilder ();
1611 functions.Push (current_function);
1612 current_function.AppendFormat ("\t\tprivate void __BuildControl_{0} " +
1613 "(System.Web.UI.Control __ctrl)\n" +
1615 "\t\t\tSystem.Web.UI.IParserAccessor __parser " +
1616 "= (System.Web.UI.IParserAccessor) __ctrl;\n" , prop_id);
1619 // Closing is performed in FinishControlFunction ()
1620 private void NewDBColumnFunction (PropertyTag tag)
1624 * This function also does almost the same as NewControlFunction.
1627 string prop_id = tag.PropertyID;
1628 Type prop_type = tag.PropertyType;
1629 string tag_id = tag.PropertyName; // Real property name used in FinishControlFunction
1631 controls.Push (prop_type, prop_id, tag_id, ChildrenKind.DBCOLUMNS, null);
1632 current_function = new StringBuilder ();
1633 functions.Push (current_function);
1634 current_function.AppendFormat ("\t\tprivate void __BuildControl_{0} " +
1635 "(System.Web.UI.WebControls.DataGridColumnCollection __ctrl)\n" +
1636 "\t\t{{\n", prop_id);
1639 private void NewPropertyFunction (PropertyTag tag)
1641 if (tag.PropertyType == typeof (System.Web.UI.WebControls.Style) ||
1642 tag.PropertyType.IsSubclassOf (typeof (System.Web.UI.WebControls.Style)))
1643 NewStyleFunction (tag);
1644 else if (tag.PropertyType == typeof (System.Web.UI.ITemplate))
1645 NewTemplateFunction (tag);
1646 else if (tag.PropertyType == typeof (System.Web.UI.WebControls.DataGridColumnCollection))
1647 NewDBColumnFunction (tag);
1649 throw new ApplicationException ("Other than Style and ITemplate not supported yet. " +
1653 private void ProcessHtmlTag ()
1655 Tag tag = (Tag) elements.Current;
1656 ChildrenKind child_kind = controls.PeekChildKind ();
1657 if (child_kind == ChildrenKind.NONE){
1658 string tag_id = controls.PeekTagID ();
1659 throw new ApplicationException (tag + " not allowed inside " + tag_id);
1662 if (child_kind == ChildrenKind.OPTION){
1663 if (0 != String.Compare (tag.TagID, "option", true))
1664 throw new ApplicationException ("Only <option> tags allowed inside <select>.");
1666 string default_id = Tag.GetDefaultID ();
1667 Type type = typeof (System.Web.UI.WebControls.ListItem);
1668 AddProtectedField (type, default_id);
1669 NewControlFunction (tag.TagID, default_id, type, ChildrenKind.CONTROLS, null);
1673 if (child_kind == ChildrenKind.CONTROLS) {
1674 ArrayList tag_elements = tag.GetElements ();
1675 foreach (Element e in tag_elements) {
1676 if (e is PlainText) {
1677 elements.Current = e;
1678 ProcessPlainText ();
1679 } else if (e is CodeRenderTag) {
1680 elements.Current = e;
1681 ProcessCodeRenderTag ();
1682 } else if (e is DataBindingTag) {
1683 elements.Current = e;
1684 ProcessDataBindingLiteral ();
1686 throw new ApplicationException (fullPath + ": unexpected tag type " + e.GetType ());
1692 if (child_kind == ChildrenKind.HTMLROW) {
1693 if (0 == String.Compare (tag.TagID, "tr", true)) {
1694 elements.Current = new HtmlControlTag (tag);
1695 ProcessHtmlControlTag ();
1700 if (child_kind == ChildrenKind.HTMLCELL) {
1701 if (0 == String.Compare (tag.TagID, "td", true)) {
1702 elements.Current = new HtmlControlTag (tag);
1703 ProcessHtmlControlTag ();
1708 // Now child_kind should be PROPERTIES, so only allow tag_id == property
1709 Type control_type = controls.PeekType ();
1710 PropertyInfo [] prop_info = control_type.GetProperties ();
1711 bool is_processed = false;
1712 foreach (PropertyInfo prop in prop_info){
1713 if (0 == String.Compare (prop.Name, tag.TagID, true)){
1714 PropertyTag prop_tag = new PropertyTag (tag, prop.PropertyType, prop.Name);
1715 NewPropertyFunction (prop_tag);
1716 is_processed = true;
1722 string tag_id = controls.PeekTagID ();
1723 throw new ApplicationException (tag.TagID + " is not a property of " + control_type);
1727 private Tag Map (Tag tag)
1729 int pos = tag.TagID.IndexOf (":");
1731 ChildrenKind child_kind = controls.PeekChildKind ();
1732 if (child_kind == ChildrenKind.HTMLROW && 0 == String.Compare (tag.TagID, "tr", true)) {
1733 tag.Attributes.Add ("runat", "server");
1734 return new HtmlControlTag (tag);
1735 } else if (child_kind == ChildrenKind.HTMLROW && 0 == String.Compare (tag.TagID, "tr", true)) {
1736 tag.Attributes.Add ("runat", "server");
1737 return new HtmlControlTag (tag);
1741 if (tag is CloseTag ||
1742 ((tag.Attributes == null ||
1743 !tag.Attributes.IsRunAtServer ()) && pos == -1))
1747 if (0 == String.Compare (tag.TagID, "object", true))
1748 return new ServerObjectTag (tag);
1750 return new HtmlControlTag (tag);
1753 string foundry_name = tag.TagID.Substring (0, pos);
1754 string component_name = tag.TagID.Substring (pos + 1);
1756 if (Foundry.LookupFoundry (foundry_name) == false)
1757 throw new ApplicationException ("Cannot find foundry for alias'" + foundry_name + "'");
1759 AspComponent component = Foundry.MakeAspComponent (foundry_name, component_name, tag);
1760 if (component == null)
1761 throw new ApplicationException ("Cannot find component '" + component_name +
1762 "' for alias '" + foundry_name + "'");
1767 private void ProcessCloseTag ()
1769 CloseTag close_tag = (CloseTag) elements.Current;
1770 if (FinishControlFunction (close_tag.TagID))
1773 elements.Current = new PlainText (close_tag.PlainHtml);
1774 ProcessPlainText ();
1777 private void ProcessDataBindingLiteral ()
1779 DataBindingTag dataBinding = (DataBindingTag) elements.Current;
1780 string actual_value = dataBinding.Data;
1781 if (actual_value == "")
1782 throw new ApplicationException ("Empty data binding tag.");
1784 if (controls.PeekChildKind () != ChildrenKind.CONTROLS)
1785 throw new ApplicationException ("Data bound content not allowed for " +
1786 controls.PeekTagID ());
1788 StringBuilder db_function = new StringBuilder ();
1789 string control_id = Tag.GetDefaultID ();
1790 string control_type_string = "System.Web.UI.DataBoundLiteralControl";
1791 AddProtectedField (typeof (System.Web.UI.DataBoundLiteralControl), control_id);
1792 // Build the control
1793 db_function.AppendFormat ("\t\tprivate System.Web.UI.Control __BuildControl_{0} ()\n" +
1794 "\t\t{{\n\t\t\t{1} __ctrl;\n\n" +
1795 "\t\t\t__ctrl = new {1} (0, 1);\n" +
1796 "\t\t\tthis.{0} = __ctrl;\n" +
1797 "\t\t\t__ctrl.DataBinding += new System.EventHandler " +
1798 "(this.__DataBind_{0});\n" +
1799 "\t\t\treturn __ctrl;\n"+
1801 control_id, control_type_string);
1802 // DataBinding handler
1803 db_function.AppendFormat ("\t\tpublic void __DataBind_{0} (object sender, " +
1804 "System.EventArgs e) {{\n" +
1805 "\t\t\t{1} Container;\n" +
1806 "\t\t\t{2} target;\n" +
1807 "\t\t\ttarget = ({2}) sender;\n" +
1808 "\t\t\tContainer = ({1}) target.BindingContainer;\n" +
1809 "\t\t\ttarget.SetDataBoundString (0, System.Convert." +
1810 "ToString ({3}));\n" +
1812 control_id, controls.Container, control_type_string,
1815 init_funcs.Append (db_function);
1816 current_function.AppendFormat ("\t\t\tthis.__BuildControl_{0} ();\n\t\t\t__parser." +
1817 "AddParsedSubObject (this.{0});\n\n", control_id);
1819 AddCodeRenderControl (controls.CodeRenderFunction);
1822 private void ProcessCodeRenderTag ()
1824 CodeRenderTag code_tag = (CodeRenderTag) elements.Current;
1826 controls.UseCodeRender = true;
1827 if (code_tag.IsVarName)
1828 controls.CodeRenderFunction.AppendFormat ("\t\t\t__output.Write ({0});\n",
1831 controls.CodeRenderFunction.AppendFormat ("\t\t\t{0}\n", code_tag.Code);
1834 public void ProcessElements ()
1841 private void JustDoIt ()
1845 while (elements.MoveNext ()){
1846 element = (Element) elements.Current;
1847 if (element is Directive){
1848 ProcessDirective ();
1849 } else if (element is PlainText){
1850 ProcessPlainText ();
1851 } else if (element is DataBindingTag){
1853 throw new ApplicationException (app_file_wrong);
1854 ProcessDataBindingLiteral ();
1855 } else if (element is CodeRenderTag){
1857 throw new ApplicationException (app_file_wrong);
1858 ProcessCodeRenderTag ();
1860 elements.Current = Map ((Tag) element);
1861 if (elements.Current is ServerObjectTag) {
1862 ProcessServerObjectTag ();
1866 if (elements.Current is HtmlControlTag) {
1867 ProcessHtmlControlTag ();
1872 throw new ApplicationException (app_file_wrong);
1874 else if (elements.Current is AspComponent)
1875 ProcessComponent ();
1876 else if (elements.Current is CloseTag)
1878 else if (elements.Current is Tag)
1881 throw new ApplicationException ("This place should not be reached.");
1886 private string GetTemplateDirectory ()
1888 string templatePath = Path.GetDirectoryName (fullPath);
1889 string appPath = Path.GetDirectoryName (HttpRuntime.AppDomainAppPath);
1891 if (templatePath == appPath)
1894 templatePath = templatePath.Substring (appPath.Length);
1895 if (Path.DirectorySeparatorChar != '/')
1896 templatePath = templatePath.Replace (Path.DirectorySeparatorChar, '/');
1898 return templatePath;
1904 if (sessionState == SessionState.Enabled || sessionState == SessionState.ReadOnly)
1905 AddInterface (typeof (System.Web.SessionState.IRequiresSessionState));
1907 if (sessionState == SessionState.ReadOnly)
1908 AddInterface (typeof (System.Web.SessionState.IReadOnlySessionState));
1911 classDecl = "\tpublic class " + className + " : " + parent + interfaces + " {\n";
1912 prolog.Append ("\n" + classDecl);
1913 declarations.Append ("\t\tprivate static bool __intialized = false;\n\n");
1915 declarations.Append ("\t\tprivate static ArrayList __fileDependencies;\n\n");
1917 // adds the constructor
1918 constructor.AppendFormat ("\t\tpublic {0} ()\n\t\t{{\n", className);
1920 constructor.Append ("\t\t\tSystem.Collections.ArrayList dependencies;\n\n");
1922 constructor.AppendFormat ("\t\t\tif (ASP.{0}.__intialized == false){{\n", className);
1925 constructor.AppendFormat ("\t\t\t\tdependencies = new System.Collections.ArrayList ();\n" +
1926 "\t\t\t\tdependencies.Add (@\"{1}\");\n" +
1927 "\t\t\t\tASP.{0}.__fileDependencies = dependencies;\n",
1928 className, fullPath);
1931 constructor.AppendFormat ("\t\t\t\tASP.{0}.__intialized = true;\n\t\t\t}}\n\t\t}}\n\n",
1934 if (!IsApplication) {
1935 //FIXME: add AutoHandlers: don't know what for...yet!
1936 constructor.AppendFormat (
1937 "\t\tprotected override int AutoHandlers\n\t\t{{\n" +
1938 "\t\t\tget {{ return ASP.{0}.__autoHandlers; }}\n" +
1939 "\t\t\tset {{ ASP.{0}.__autoHandlers = value; }}\n" +
1940 "\t\t}}\n\n", className);
1942 constructor.Append (
1943 "\t\tprotected System.Web.HttpApplication ApplicationInstance\n\t\t{\n" +
1944 "\t\t\tget { return (System.Web.HttpApplication) this.Context.ApplicationInstance; }\n" +
1947 constructor.AppendFormat (
1948 "\t\tpublic override string TemplateSourceDirectory\n\t\t{{\n" +
1949 "\t\t\tget {{ return \"{0}\"; }}\n" +
1950 "\t\t}}\n\n", GetTemplateDirectory ());
1952 epilog.Append ("\n\t\tprotected override void FrameworkInitialize ()\n\t\t{\n" +
1953 "\t\t\tthis.__BuildControlTree (this);\n");
1956 epilog.AppendFormat ("\t\t\tthis.FileDependencies = ASP.{0}.__fileDependencies;\n" +
1957 "\t\t\tthis.EnableViewStateMac = true;\n", className);
1960 epilog.Append ("\t\t}\n\n");
1964 Random rnd = new Random ();
1965 epilog.AppendFormat ("\t\tpublic override int GetTypeHashCode ()\n\t\t{{\n" +
1966 "\t\t\treturn {0};\n" +
1967 "\t\t}}\n", rnd.Next ());
1970 epilog.Append ("\t}\n}\n");
1972 // Closes the currently opened tags
1973 StringBuilder old_function = current_function;
1975 while (functions.Count > 1){
1976 old_function.Append ("\n\t\t\treturn __ctrl;\n\t\t}\n\n");
1977 init_funcs.Append (old_function);
1978 control_id = controls.PeekControlID ();
1979 FinishControlFunction (control_id);
1980 controls.AddChild ();
1981 old_function = (StringBuilder) functions.Pop ();
1982 current_function = (StringBuilder) functions.Peek ();
1986 bool useCodeRender = controls.UseCodeRender;
1988 RemoveLiterals (current_function);
1989 AddRenderMethodDelegate (current_function, controls.PeekControlID ());
1992 current_function.Append ("\t\t}\n\n");
1993 init_funcs.Append (current_function);
1995 AddCodeRenderFunction (controls.CodeRenderFunction.ToString (), controls.PeekControlID ());
2001 // Functions related to compilation of user controls
2004 private static char dirSeparator = Path.DirectorySeparatorChar;
2005 struct UserControlData
2007 public UserControlResult result;
2008 public string className;
2009 public string assemblyName;
2012 private static UserControlData GenerateUserControl (string src, HttpContext context)
2014 UserControlData data = new UserControlData ();
2015 data.result = UserControlResult.OK;
2017 UserControlCompiler compiler = new UserControlCompiler (new UserControlParser (src, context));
2018 Type t = compiler.GetCompiledType ();
2020 data.result = UserControlResult.CompilationFailed;
2024 data.className = t.Name;
2025 data.assemblyName = compiler.TargetFile;