New tests.
[mono.git] / mcs / class / System.Web / System.Web.Compilation / TemplateControlCompiler.cs
index b264543bbfa74e833b4804b84467b7ac469e93d8..4b01ccd67853f2ae263f23f390a1cc351188cde5 100644 (file)
@@ -3,9 +3,10 @@
 //
 // Authors:
 //     Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//     Marek Habersack (mhabersack@novell.com)
 //
 // (C) 2003 Ximian, Inc (http://www.ximian.com)
-//
+// (C) 2004-2008 Novell, Inc (http://novell.com)
 
 //
 // Permission is hereby granted, free of charge, to any person obtaining
@@ -31,22 +32,21 @@ using System;
 using System.CodeDom;
 using System.Collections;
 using System.ComponentModel;
+using System.Configuration;
+using System.Collections.Specialized;
+using System.Collections.Generic;
 using System.Drawing;
 using System.Globalization;
 using System.Reflection;
+using System.Resources;
 using System.Text;
 using System.Web;
+using System.Web.Configuration;
 using System.Web.UI;
 using System.Web.UI.WebControls;
 using System.Web.Util;
 using System.ComponentModel.Design.Serialization;
-#if NET_2_0
-using System.Configuration;
-using System.Collections.Specialized;
-using System.Collections.Generic;
 using System.Text.RegularExpressions;
-using System.Web.Configuration;
-#endif
 
 namespace System.Web.Compilation
 {
@@ -54,19 +54,31 @@ namespace System.Web.Compilation
        {
                static BindingFlags noCaseFlags = BindingFlags.Public | BindingFlags.NonPublic |
                                                  BindingFlags.Instance | BindingFlags.IgnoreCase;
-
+               static Type monoTypeType = Type.GetType ("System.MonoType");
+               
                TemplateControlParser parser;
                int dataBoundAtts;
-               ILocation currentLocation;
+               internal ILocation currentLocation;
 
                static TypeConverter colorConverter;
 
                internal static CodeVariableReferenceExpression ctrlVar = new CodeVariableReferenceExpression ("__ctrl");
                
-#if NET_2_0
-               static Regex bindRegex = new Regex (@"Bind\s*\(""(.*?)""\)\s*%>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
-               static Regex bindRegexInValue = new Regex (@"Bind\s*\(""(.*?)""\)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
-#endif
+               List <string> masterPageContentPlaceHolders;
+               static Regex startsWithBindRegex = new Regex (@"^Bind\s*\(", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+               // When modifying those, make sure to look at the SanitizeBindCall to make sure it
+               // picks up correct groups.
+               static Regex bindRegex = new Regex (@"Bind\s*\(\s*[""']+(.*?)[""']+((\s*,\s*[""']+(.*?)[""']+)?)\s*\)\s*%>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+               static Regex bindRegexInValue = new Regex (@"Bind\s*\(\s*[""']+(.*?)[""']+((\s*,\s*[""']+(.*?)[""']+)?)\s*\)\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+               static Regex evalRegexInValue = new Regex (@"(.*)Eval\s*\(\s*[""']+(.*?)[""']+((\s*,\s*[""']+(.*?)[""']+)?)\s*\)(.*)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+
+               List <string> MasterPageContentPlaceHolders {
+                       get {
+                               if (masterPageContentPlaceHolders == null)
+                                       masterPageContentPlaceHolders = new List <string> ();
+                               return masterPageContentPlaceHolders;
+                       }
+               }
 
                public TemplateControlCompiler (TemplateControlParser parser)
                        : base (parser)
@@ -81,30 +93,27 @@ namespace System.Web.Compilation
                }
 
                void CreateField (ControlBuilder builder, bool check)
-               {                       
+               {
                        if (builder == null || builder.ID == null || builder.ControlType == null)
                                return;
-#if NET_2_0
+
                        if (partialNameOverride [builder.ID] != null)
                                return;
-#endif
 
                        MemberAttributes ma = MemberAttributes.Family;
-                       currentLocation = builder.location;
+                       currentLocation = builder.Location;
                        if (check && CheckBaseFieldOrProperty (builder.ID, builder.ControlType, ref ma))
                                return; // The field or property already exists in a base class and is accesible.
 
                        CodeMemberField field;
                        field = new CodeMemberField (builder.ControlType.FullName, builder.ID);
                        field.Attributes = ma;
-#if NET_2_0
                        field.Type.Options |= CodeTypeReferenceOptions.GlobalReference;
 
                        if (partialClass != null)
-                               partialClass.Members.Add (field);
+                               partialClass.Members.Add (AddLinePragma (field, builder));
                        else
-#endif
-                               mainClass.Members.Add (field);
+                               mainClass.Members.Add (AddLinePragma (field, builder));
                }
 
                bool CheckBaseFieldOrProperty (string id, Type type, ref MemberAttributes ma)
@@ -127,43 +136,38 @@ namespace System.Web.Compilation
                                return false;
 
                        if (!other.IsAssignableFrom (type)) {
-#if NET_2_0
                                ma |= MemberAttributes.New;
                                return false;
-#else
-                               string msg = String.Format ("The base class includes the field '{0}', but its " +
-                                                           "type '{1}' is not compatible with {2}",
-                                                           id, other, type);
-                               throw new ParseException (currentLocation, msg);
-#endif
                        }
 
                        return true;
                }
-
+               
                void AddParsedSubObjectStmt (ControlBuilder builder, CodeExpression expr) 
                {
-                       if (!builder.haveParserVariable) {
+                       if (!builder.HaveParserVariable) {
                                CodeVariableDeclarationStatement p = new CodeVariableDeclarationStatement();
                                p.Name = "__parser";
                                p.Type = new CodeTypeReference (typeof (IParserAccessor));
                                p.InitExpression = new CodeCastExpression (typeof (IParserAccessor), ctrlVar);
-                               builder.methodStatements.Add (p);
-                               builder.haveParserVariable = true;
+                               builder.MethodStatements.Add (p);
+                               builder.HaveParserVariable = true;
                        }
 
                        CodeVariableReferenceExpression var = new CodeVariableReferenceExpression ("__parser");
                        CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (var, "AddParsedSubObject");
                        invoke.Parameters.Add (expr);
-                       builder.methodStatements.Add (invoke);
+                       builder.MethodStatements.Add (AddLinePragma (invoke, builder));
                }
-
+               
                void InitMethod (ControlBuilder builder, bool isTemplate, bool childrenAsProperties)
                {
+                       currentLocation = builder.Location;
+                       
                        string tailname = ((builder is RootBuilder) ? "Tree" : ("_" + builder.ID));
                        CodeMemberMethod method = new CodeMemberMethod ();
-                       builder.method = method;
-                       builder.methodStatements = method.Statements;
+                       builder.Method = method;
+                       builder.MethodStatements = method.Statements;
 
                        method.Name = "__BuildControl" + tailname;
                        method.Attributes = MemberAttributes.Private | MemberAttributes.Final;
@@ -173,15 +177,13 @@ namespace System.Web.Compilation
                         * method, allow subclasses to insert control
                         * specific code. */
                        if (builder is RootBuilder) {
-#if NET_2_0
                                SetCustomAttributes (method);
-#endif
                                AddStatementsToInitMethod (method);
                        }
                        
                        if (builder.HasAspCode) {
                                CodeMemberMethod renderMethod = new CodeMemberMethod ();
-                               builder.renderMethod = renderMethod;
+                               builder.RenderMethod = renderMethod;
                                renderMethod.Name = "__Render" + tailname;
                                renderMethod.Attributes = MemberAttributes.Private | MemberAttributes.Final;
                                CodeParameterDeclarationExpression arg1 = new CodeParameterDeclarationExpression ();
@@ -200,11 +202,12 @@ namespace System.Web.Compilation
                                if (builder is RootBuilder)
                                        typeString = parser.ClassName;
                                else {
-                                       if (builder.ControlType != null && builder.isProperty &&
+                                       if (builder.ControlType != null && builder.IsProperty &&
                                            !typeof (ITemplate).IsAssignableFrom (builder.ControlType))
                                                typeString = builder.ControlType.FullName;
                                        else 
                                                typeString = "System.Web.UI.Control";
+                                       ProcessTemplateChildren (builder);
                                }
 
                                method.Parameters.Add (new CodeParameterDeclarationExpression (typeString, "__ctrl"));
@@ -231,8 +234,8 @@ namespace System.Web.Compilation
                                CodeAssignStatement assign = new CodeAssignStatement ();
                                assign.Left = ctrlVar;
                                assign.Right = newExpr;
-                               method.Statements.Add (assign);
-                               
+                               method.Statements.Add (AddLinePragma (assign, builder));
+                                                               
                                // this.$builderID = _ctrl;
                                //
                                CodeFieldReferenceExpression builderID = new CodeFieldReferenceExpression ();
@@ -241,7 +244,8 @@ namespace System.Web.Compilation
                                assign = new CodeAssignStatement ();
                                assign.Left = builderID;
                                assign.Right = ctrlVar;
-                               method.Statements.Add (assign);
+                               method.Statements.Add (AddLinePragma (assign, builder));
+
                                if (typeof (UserControl).IsAssignableFrom (type)) {
                                        CodeMethodReferenceExpression mref = new CodeMethodReferenceExpression ();
                                        mref.TargetObject = builderID;
@@ -251,7 +255,6 @@ namespace System.Web.Compilation
                                        method.Statements.Add (initAsControl);
                                }
 
-#if NET_2_0
                                if (builder.ParentTemplateBuilder is System.Web.UI.WebControls.ContentBuilderInternal) {
                                        PropertyInfo pi;
 
@@ -280,11 +283,10 @@ namespace System.Web.Compilation
                                // CreateAssignStatementsFromAttributes
                                // below.
                                // 
-                               if (builder.attribs != null) {
-                                       string skinid = builder.attribs ["skinid"] as string;
-                                       if (skinid != null)
-                                               CreateAssignStatementFromAttribute (builder, "skinid");
-                               }
+                               string skinid = builder.GetAttribute ("skinid");
+                               if (!String.IsNullOrEmpty (skinid))
+                                       CreateAssignStatementFromAttribute (builder, "skinid");
+
                                if (typeof (WebControl).IsAssignableFrom (type)) {
                                        CodeMethodInvokeExpression applyStyleSheetSkin = new CodeMethodInvokeExpression (ctrlVar, "ApplyStyleSheetSkin");
                                        if (typeof (Page).IsAssignableFrom (parser.BaseType))
@@ -293,35 +295,38 @@ namespace System.Web.Compilation
                                                applyStyleSheetSkin.Parameters.Add (new CodePropertyReferenceExpression (thisRef, "Page"));
                                        method.Statements.Add (applyStyleSheetSkin);
                                }
-#endif
+
+                               // Process template children before anything else
+                               ProcessTemplateChildren (builder);
 
                                // process ID here. It should be set before any other attributes are
                                // assigned, since the control code may rely on ID being set. We
                                // skip ID in CreateAssignStatementsFromAttributes
-                               if (builder.attribs != null) {
-                                       string ctl_id = builder.attribs ["id"] as string;
-                                       if (ctl_id != null && ctl_id != String.Empty)
-                                               CreateAssignStatementFromAttribute (builder, "id");
-                               }
-#if NET_2_0
+                               string ctl_id = builder.GetAttribute ("id");
+                               if (ctl_id != null && ctl_id.Length != 0)
+                                       CreateAssignStatementFromAttribute (builder, "id");
+                               
                                if (typeof (ContentPlaceHolder).IsAssignableFrom (type)) {
-                                       CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (thisRef, "ContentPlaceHolders");
-                                       CodeMethodInvokeExpression addPlaceholder = new CodeMethodInvokeExpression (prop, "Add");
-                                       addPlaceholder.Parameters.Add (ctrlVar);
-                                       method.Statements.Add (addPlaceholder);
-
+                                       List <string> placeHolderIds = MasterPageContentPlaceHolders;
+                                       string cphID = builder.ID;
+                                       
+                                       if (!placeHolderIds.Contains (cphID))
+                                               placeHolderIds.Add (cphID);
 
                                        CodeConditionStatement condStatement;
 
                                        // Add the __Template_* field
-                                       CodeMemberField fld = new CodeMemberField (typeof (ITemplate), "__Template_" + builder.ID);
+                                       string templateField = "__Template_" + cphID;
+                                       CodeMemberField fld = new CodeMemberField (typeof (ITemplate), templateField);
                                        fld.Attributes = MemberAttributes.Private;
                                        mainClass.Members.Add (fld);
 
                                        CodeFieldReferenceExpression templateID = new CodeFieldReferenceExpression ();
                                        templateID.TargetObject = thisRef;
-                                       templateID.FieldName = "__Template_" + builder.ID;
+                                       templateID.FieldName = templateField;
 
+                                       CreateContentPlaceHolderTemplateProperty (templateField, "Template_" + cphID);
+                                       
                                        // if ((this.ContentTemplates != null)) {
                                        //      this.__Template_$builder.ID = ((System.Web.UI.ITemplate)(this.ContentTemplates["$builder.ID"]));
                                        // }
@@ -332,7 +337,7 @@ namespace System.Web.Compilation
 
                                        CodeIndexerExpression indexer = new CodeIndexerExpression ();
                                        indexer.TargetObject = new CodePropertyReferenceExpression (thisRef, "ContentTemplates");
-                                       indexer.Indices.Add (new CodePrimitiveExpression (builder.ID));
+                                       indexer.Indices.Add (new CodePrimitiveExpression (cphID));
 
                                        assign = new CodeAssignStatement ();
                                        assign.Left = templateID;
@@ -367,15 +372,28 @@ namespace System.Web.Compilation
                                        method.Statements.Add (condStatement);
 
                                        // this is the bit that causes the following stuff to end up in the else { }
-                                       builder.methodStatements = condStatement.FalseStatements;
+                                       builder.MethodStatements = condStatement.FalseStatements;
                                }
-#endif
                        }
                        
                        mainClass.Members.Add (method);
                }
 
-#if NET_2_0
+               void ProcessTemplateChildren (ControlBuilder builder)
+               {
+                       ArrayList templates = builder.TemplateChildren;
+                       if (templates != null && templates.Count > 0) {
+                               foreach (TemplateBuilder tb in templates) {
+                                       CreateControlTree (tb, true, false);
+                                       if (tb.BindingDirection == BindingDirection.TwoWay) {
+                                               string extractMethod = CreateExtractValuesMethod (tb);
+                                               AddBindableTemplateInvocation (builder, tb.TagName, tb.Method.Name, extractMethod);
+                                       } else
+                                               AddTemplateInvocation (builder, tb.TagName, tb.Method.Name);
+                               }
+                       }
+               }
+               
                void SetCustomAttribute (CodeMemberMethod method, UnknownAttributeDescriptor uad)
                {
                        CodeAssignStatement assign = new CodeAssignStatement ();
@@ -400,7 +418,6 @@ namespace System.Web.Compilation
                        foreach (UnknownAttributeDescriptor uad in attrs)
                                SetCustomAttribute (method, uad);
                }
-#endif
                
                protected virtual void AddStatementsToInitMethod (CodeMemberMethod method)
                {
@@ -419,35 +436,77 @@ namespace System.Web.Compilation
 
                                CodeMethodInvokeExpression expr;
                                expr = new CodeMethodInvokeExpression (methodRef, new CodePrimitiveExpression (str));
-                               builder.renderMethod.Statements.Add (expr);
+                               builder.RenderMethod.Statements.Add (expr);
                        }
                }
 
-               string TrimDB (string value)
+               string TrimDB (string value, bool trimTail)
                {
                        string str = value.Trim ();
-                       str = str.Substring (3);
-                       return str.Substring (0, str.Length - 2);
+                       int len = str.Length;
+                       int idx = str.IndexOf ('#', 2) + 1;
+                       if (idx >= len)
+                               return String.Empty;
+                       if (trimTail)
+                               len -= 2;
+                       
+                       return str.Substring (idx, len - idx).Trim ();
+               }
+
+               CodeExpression CreateEvalInvokeExpression (Regex regex, string value, bool isBind)
+               {
+                       Match match = regex.Match (value);
+                       if (!match.Success) {
+                               if (isBind)
+                                       throw new HttpParseException ("Bind invocation wasn't formatted properly.");
+                               return null;
+                       }
+                       
+                       string sanitizedSnippet;
+                       if (isBind)
+                               sanitizedSnippet = SanitizeBindCall (match);
+                       else
+                               sanitizedSnippet = value;
+                       
+                       return new CodeSnippetExpression (sanitizedSnippet);
                }
 
+               string SanitizeBindCall (Match match)
+               {
+                       GroupCollection groups = match.Groups;
+                       StringBuilder sb = new StringBuilder ("Eval(\"" + groups [1] + "\"");
+                       Group second = groups [4];
+                       if (second != null) {
+                               string v = second.Value;
+                               if (v != null && v.Length > 0)
+                                       sb.Append (",\"" + second + "\"");
+                       }
+                       
+                       sb.Append (")");
+                       return sb.ToString ();
+               }
+               
                string DataBoundProperty (ControlBuilder builder, Type type, string varName, string value)
                {
-                       value = TrimDB (value);
+                       value = TrimDB (value, true);
                        CodeMemberMethod method;
-                       string dbMethodName = builder.method.Name + "_DB_" + dataBoundAtts++;
-#if NET_2_0
-                       bool need_if = false;
+                       string dbMethodName = builder.Method.Name + "_DB_" + dataBoundAtts++;
+                       CodeExpression valueExpression = null;
                        value = value.Trim ();
-                       if (StrUtils.StartsWith (value, "Bind", true)) {
-                               Match match = bindRegexInValue.Match (value);
-                               if (match.Success) {
-                                       value = "Eval" + value.Substring (4);
+                       
+                       bool need_if = false;
+                       if (startsWithBindRegex.Match (value).Success) {
+                               valueExpression = CreateEvalInvokeExpression (bindRegexInValue, value, true);
+                               if (valueExpression != null)
                                        need_if = true;
-                               }
-                       }
-#endif
-                       method = CreateDBMethod (dbMethodName, GetContainerType (builder), builder.ControlType);
+                       } else
+                               if (StrUtils.StartsWith (value, "Eval", true))
+                                       valueExpression = CreateEvalInvokeExpression (evalRegexInValue, value, false);
+                       
+                       if (valueExpression == null)
+                               valueExpression = new CodeSnippetExpression (value);
                        
+                       method = CreateDBMethod (builder, dbMethodName, GetContainerType (builder), builder.ControlType);
                        CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
 
                        // This should be a CodePropertyReferenceExpression for properties... but it works anyway
@@ -458,24 +517,19 @@ namespace System.Web.Compilation
                                CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
                                CodeTypeReferenceExpression conv = new CodeTypeReferenceExpression (typeof (Convert));
                                tostring.Method = new CodeMethodReferenceExpression (conv, "ToString");
-                               tostring.Parameters.Add (new CodeSnippetExpression (value));
+                               tostring.Parameters.Add (valueExpression);
                                expr = tostring;
-                       } else {
-                               CodeSnippetExpression snippet = new CodeSnippetExpression (value);
-                               expr = new CodeCastExpression (type, snippet);
-                       }
+                       } else
+                               expr = new CodeCastExpression (type, valueExpression);
 
                        CodeAssignStatement assign = new CodeAssignStatement (field, expr);
-#if NET_2_0
                        if (need_if) {
                                CodeExpression page = new CodePropertyReferenceExpression (thisRef, "Page");
                                CodeExpression left = new CodeMethodInvokeExpression (page, "GetDataItem");
                                CodeBinaryOperatorExpression ce = new CodeBinaryOperatorExpression (left, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
                                CodeConditionStatement ccs = new CodeConditionStatement (ce, assign);
                                method.Statements.Add (ccs);
-                       }
-                       else
-#endif
+                       } else
                                method.Statements.Add (assign);
 
                        mainClass.Members.Add (method);
@@ -483,80 +537,97 @@ namespace System.Web.Compilation
                }
 
                void AddCodeForPropertyOrField (ControlBuilder builder, Type type, string var_name, string att, MemberInfo member, bool isDataBound, bool isExpression)
-               {                       
-                       CodeMemberMethod method = builder.method;
+               {
+                       CodeMemberMethod method = builder.Method;
                        bool isWritable = IsWritablePropertyOrField (member);
+                       
                        if (isDataBound && isWritable) {
                                string dbMethodName = DataBoundProperty (builder, type, var_name, att);
-                               AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
+                               AddEventAssign (method, builder, "DataBinding", typeof (EventHandler), dbMethodName);
                                return;
-                       }
-#if NET_2_0
-                       else if (isExpression && isWritable) {
-                               AddExpressionAssign (method, member, type, var_name, att);
+                       } else if (isExpression && isWritable) {
+                               AddExpressionAssign (method, builder, member, type, var_name, att);
                                return;
                        }
-#endif
-                       
+
                        CodeAssignStatement assign = new CodeAssignStatement ();
                        assign.Left = new CodePropertyReferenceExpression (ctrlVar, var_name);
-                       currentLocation = builder.location;
+                       currentLocation = builder.Location;
                        assign.Right = GetExpressionFromString (type, att, member);
 
-                       method.Statements.Add (assign);
+                       method.Statements.Add (AddLinePragma (assign, builder));
                }
 
-               bool IsDataBound (string value)
+               bool IsDirective (string value, char directiveChar)
                {
-                       if (value == null || value == "")
+                       if (value == null || value == String.Empty)
+                               return false;
+                       
+                       value = value.Trim ();
+                       if (!StrUtils.StartsWith (value, "<%") || !StrUtils.EndsWith (value, "%>"))
                                return false;
 
-                       string str = value.Trim ();
-                       return (StrUtils.StartsWith (str, "<%#") && StrUtils.EndsWith (str, "%>"));
+                       int dcIndex = value.IndexOf (directiveChar, 2);
+                       if (dcIndex == -1)
+                               return false;
+
+                       if (dcIndex == 2)
+                               return true;
+                       dcIndex--;
+                       
+                       while (dcIndex >= 2) {
+                               if (!Char.IsWhiteSpace (value [dcIndex]))
+                                       return false;
+                               dcIndex--;
+                       }
+
+                       return true;
+               }
+               
+               bool IsDataBound (string value)
+               {
+                       return IsDirective (value, '#');
                }
 
-#if NET_2_0
                bool IsExpression (string value)
                {
-                       if (value == null || value == "")
-                               return false;
-                       string str = value.Trim ();
-                       return (StrUtils.StartsWith (str, "<%$") && StrUtils.EndsWith (str, "%>"));
+                       return IsDirective (value, '$');
                }               
 
                void RegisterBindingInfo (ControlBuilder builder, string propName, ref string value)
                {
-                       string str = value.Trim ();
-                       str = str.Substring (3).Trim ();        // eats "<%#"
+                       string str = TrimDB (value, false);
                        if (StrUtils.StartsWith (str, "Bind", true)) {
                                Match match = bindRegex.Match (str);
                                if (match.Success) {
                                        string bindingName = match.Groups [1].Value;
-                                       
                                        TemplateBuilder templateBuilder = builder.ParentTemplateBuilder;
-                                       if (templateBuilder == null || templateBuilder.BindingDirection == BindingDirection.OneWay)
+                                       
+                                       if (templateBuilder == null)
                                                throw new HttpException ("Bind expression not allowed in this context.");
-                                               
-                                       string id = builder.attribs ["ID"] as string;
-                                       if (id == null)
+
+                                       if (templateBuilder.BindingDirection == BindingDirection.OneWay)
+                                               return;
+                                       
+                                       string id = builder.GetAttribute ("ID");
+                                       if (String.IsNullOrEmpty (id))
                                                throw new HttpException ("Control of type '" + builder.ControlType + "' using two-way binding on property '" + propName + "' must have an ID.");
                                        
                                        templateBuilder.RegisterBoundProperty (builder.ControlType, propName, id, bindingName);
                                }
                        }
                }
-#endif
 
                /*
                static bool InvariantCompare (string a, string b)
                {
-                       return (0 == String.Compare (a, b, false, CultureInfo.InvariantCulture));
+                       return (0 == String.Compare (a, b, false, Helpers.InvariantCulture));
                }
                */
 
                static bool InvariantCompareNoCase (string a, string b)
                {
-                       return (0 == String.Compare (a, b, true, CultureInfo.InvariantCulture));
+                       return (0 == String.Compare (a, b, true, Helpers.InvariantCulture));
                }
 
                static MemberInfo GetFieldOrProperty (Type type, string name)
@@ -580,7 +651,7 @@ namespace System.Web.Compilation
                {
                        PropertyInfo pi = member as PropertyInfo;
                        if (pi != null)
-                               return pi.CanWrite;
+                               return pi.GetSetMethod (false) != null;
                        FieldInfo fi = member as FieldInfo;
                        if (fi != null)
                                return !fi.IsInitOnly;
@@ -593,11 +664,7 @@ namespace System.Web.Compilation
                        int hyphen = id.IndexOf ('-');
                        bool isPropertyInfo = (member is PropertyInfo);
                        bool isDataBound = IsDataBound (attValue);
-#if NET_2_0
                        bool isExpression = !isDataBound && IsExpression (attValue);
-#else
-                       bool isExpression = false;
-#endif
                        Type type;
                        if (isPropertyInfo) {
                                type = ((PropertyInfo) member).PropertyType;
@@ -606,14 +673,12 @@ namespace System.Web.Compilation
                        }
 
                        if (InvariantCompareNoCase (member.Name, id)) {
-#if NET_2_0
                                if (isDataBound)
-                                       RegisterBindingInfo (builder, member.Name, ref attValue);
-                               
-#endif
+                                       RegisterBindingInfo (builder, member.Name, ref attValue);                               
+
                                if (!IsWritablePropertyOrField (member))
                                        return false;
-
+                               
                                AddCodeForPropertyOrField (builder, type, member.Name, attValue, member, isDataBound, isExpression);
                                return true;
                        }
@@ -621,7 +686,7 @@ namespace System.Web.Compilation
                        if (hyphen == -1)
                                return false;
 
-                       string prop_field = id.Replace ("-", ".");
+                       string prop_field = id.Replace ('-', '.');
                        string [] parts = prop_field.Split (new char [] {'.'});
                        int length = parts.Length;
                        
@@ -653,9 +718,10 @@ namespace System.Web.Compilation
                        string val = attValue;
                        if (attValue == null && is_bool)
                                val = "true"; // Font-Bold <=> Font-Bold="true"
-#if NET_2_0
-                       if (isDataBound) RegisterBindingInfo (builder, prefix + member.Name + "." + subprop.Name, ref attValue);
-#endif
+
+                       if (isDataBound)
+                               RegisterBindingInfo (builder, prefix + member.Name + "." + subprop.Name, ref attValue);
+
                        AddCodeForPropertyOrField (builder, subprop.PropertyType,
                                                   prefix + member.Name + "." + subprop.Name,
                                                   val, subprop, isDataBound, isExpression);
@@ -663,46 +729,38 @@ namespace System.Web.Compilation
                        return true;
                }
 
-#if NET_2_0
-               void AddExpressionAssign (CodeMemberMethod method, MemberInfo member, Type type, string name, string value)
+               CodeExpression CompileExpression (MemberInfo member, Type type, string value, bool useSetAttribute)
                {
-                       CodeAssignStatement assign = new CodeAssignStatement ();
-                       assign.Left = new CodePropertyReferenceExpression (ctrlVar, name);
-
                        // First let's find the correct expression builder
-                       string expr = value.Substring (3, value.Length - 5).Trim ();
-                       int colon = expr.IndexOf (':');
+                       value = value.Substring (3, value.Length - 5).Trim ();
+                       int colon = value.IndexOf (':');
                        if (colon == -1)
-                               return;
-                       string prefix = expr.Substring (0, colon).Trim ();
+                               return null;
+                       string prefix = value.Substring (0, colon).Trim ();
+                       string expr = value.Substring (colon + 1).Trim ();
                        
-                       System.Configuration.Configuration config = WebConfigurationManager.OpenWebConfiguration ("");
-                       if (config == null)
-                               return;
-                       CompilationSection cs = (CompilationSection)config.GetSection ("system.web/compilation");
+                       CompilationSection cs = (CompilationSection)WebConfigurationManager.GetWebApplicationSection ("system.web/compilation");
                        if (cs == null)
-                               return;
+                               return null;
+                       
                        if (cs.ExpressionBuilders == null || cs.ExpressionBuilders.Count == 0)
-                               return;
+                               return null;
 
                        System.Web.Configuration.ExpressionBuilder ceb = cs.ExpressionBuilders[prefix];
                        if (ceb == null)
-                               return;
+                               return null;
+                       
                        string builderType = ceb.Type;
-
                        Type t;
+                       
                        try {
-                               t = System.Type.GetType (builderType, true);
+                               t = HttpApplication.LoadType (builderType, true);
                        } catch (Exception e) {
-                               throw new HttpException (
-                                       String.Format ("Failed to load expression builder type `{0}'", builderType), e);
+                               throw new HttpException (String.Format ("Failed to load expression builder type `{0}'", builderType), e);
                        }
 
                        if (!typeof (System.Web.Compilation.ExpressionBuilder).IsAssignableFrom (t))
-                               throw new HttpException (
-                                       String.Format (
-                                               "Type {0} is not descendant from System.Web.Compilation.ExpressionBuilder",
-                                               builderType));
+                               throw new HttpException (String.Format ("Type {0} is not descendant from System.Web.Compilation.ExpressionBuilder", builderType));
 
                        System.Web.Compilation.ExpressionBuilder eb = null;
                        object parsedData;
@@ -711,35 +769,76 @@ namespace System.Web.Compilation
                        try {
                                eb = Activator.CreateInstance (t) as System.Web.Compilation.ExpressionBuilder;
                                ctx = new ExpressionBuilderContext (HttpContext.Current.Request.FilePath);
-                               parsedData = eb.ParseExpression (expr.Substring (colon + 1).Trim (), type, ctx);
+                               parsedData = eb.ParseExpression (expr, type, ctx);
                        } catch (Exception e) {
-                               throw new HttpException (
-                                       String.Format ("Failed to create an instance of type `{0}'", builderType), e);
+                               throw new HttpException (String.Format ("Failed to create an instance of type `{0}'", builderType), e);
                        }
                        
-                       BoundPropertyEntry bpe = CreateBoundPropertyEntry (member as PropertyInfo, prefix, expr);
-                       assign.Right = eb.GetCodeExpression (bpe, parsedData, ctx);
+                       BoundPropertyEntry bpe = CreateBoundPropertyEntry (member as PropertyInfo, prefix, expr, useSetAttribute);
+                       return eb.GetCodeExpression (bpe, parsedData, ctx);
+               }
+               
+               void AddExpressionAssign (CodeMemberMethod method, ControlBuilder builder, MemberInfo member, Type type, string name, string value)
+               {
+                       CodeExpression expr = CompileExpression (member, type, value, false);
+
+                       if (expr == null)
+                               return;
+                       
+                       CodeAssignStatement assign = new CodeAssignStatement ();
+                       assign.Left = new CodePropertyReferenceExpression (ctrlVar, name);
+                       assign.Right = expr;
                        
-                       method.Statements.Add (assign);
+                       builder.Method.Statements.Add (AddLinePragma (assign, builder));
                }
 
-               BoundPropertyEntry CreateBoundPropertyEntry (PropertyInfo pi, string prefix, string expr)
+               BoundPropertyEntry CreateBoundPropertyEntry (PropertyInfo pi, string prefix, string expr, bool useSetAttribute)
                {
-                       if (pi == null)
-                               return null;
-
                        BoundPropertyEntry ret = new BoundPropertyEntry ();
                        ret.Expression = expr;
                        ret.ExpressionPrefix = prefix;
                        ret.Generated = false;
-                       ret.Name = pi.Name;
-                       ret.PropertyInfo = pi;
-                       ret.Type = pi.PropertyType;
-
+                       if (pi != null) {
+                               ret.Name = pi.Name;
+                               ret.PropertyInfo = pi;
+                               ret.Type = pi.PropertyType;
+                       }
+                       ret.UseSetAttribute = useSetAttribute;
+                       
                        return ret;
                }
+
+               bool ResourceProviderHasObject (string key)
+               {
+                       IResourceProvider rp = HttpContext.GetResourceProvider (InputVirtualPath.Absolute, true);
+                       if (rp == null)
+                               return false;
+
+                       IResourceReader rr = rp.ResourceReader;
+                       if (rr == null)
+                               return false;
+
+                       try {
+                               IDictionaryEnumerator ide = rr.GetEnumerator ();
+                               if (ide == null)
+                                       return false;
+                       
+                               string dictKey;
+                               while (ide.MoveNext ()) {
+                                       dictKey = ide.Key as string;
+                                       if (String.IsNullOrEmpty (dictKey))
+                                               continue;
+                                       if (String.Compare (key, dictKey, StringComparison.Ordinal) == 0)
+                                               return true;
+                               }
+                       } finally {
+                               rr.Close ();
+                       }
+                       
+                       return false;
+               }
                
-               void AssignPropertyFromResources (CodeMemberMethod method, MemberInfo mi, string attvalue)
+               void AssignPropertyFromResources (ControlBuilder builder, MemberInfo mi, string attvalue)
                {
                        bool isProperty = mi.MemberType == MemberTypes.Property;
                        bool isField = !isProperty && (mi.MemberType == MemberTypes.Field);
@@ -747,9 +846,16 @@ namespace System.Web.Compilation
                        if (!isProperty && !isField || !IsWritablePropertyOrField (mi))
                                return;                 
 
+                       object[] attrs = mi.GetCustomAttributes (typeof (LocalizableAttribute), true);
+                       if (attrs != null && attrs.Length > 0 && !((LocalizableAttribute)attrs [0]).IsLocalizable)
+                               return;
+                       
                        string memberName = mi.Name;
-                       string resname = String.Format ("{0}.{1}", attvalue, memberName);
+                       string resname = String.Concat (attvalue, ".", memberName);
 
+                       if (!ResourceProviderHasObject (resname))
+                               return;
+                       
                        // __ctrl.Text = System.Convert.ToString(HttpContext.GetLocalResourceObject("ButtonResource1.Text"));
                        string inputFile = parser.InputFile;
                        string physPath = HttpContext.Current.Request.PhysicalApplicationPath;
@@ -770,16 +876,15 @@ namespace System.Web.Compilation
                        if (!isProperty && !isField)
                                return; // an "impossible" case
                        
-                       Type declaringType = mi.DeclaringType;
                        CodeAssignStatement assign = new CodeAssignStatement ();
                        
                        assign.Left = new CodePropertyReferenceExpression (ctrlVar, memberName);
                        assign.Right = ResourceExpressionBuilder.CreateGetLocalResourceObject (mi, resname);
                        
-                       method.Statements.Add (assign);
+                       builder.Method.Statements.Add (AddLinePragma (assign, builder));
                }
 
-               void AssignPropertiesFromResources (CodeMemberMethod method, Type controlType, string attvalue)
+               void AssignPropertiesFromResources (ControlBuilder builder, Type controlType, string attvalue)
                {
                        // Process all public fields and properties of the control. We don't use GetMembers to make the code
                        // faster
@@ -791,9 +896,9 @@ namespace System.Web.Compilation
                                BindingFlags.Public | BindingFlags.FlattenHierarchy);
 
                        foreach (FieldInfo fi in fields)
-                               AssignPropertyFromResources (method, fi, attvalue);
+                               AssignPropertyFromResources (builder, fi, attvalue);
                        foreach (PropertyInfo pi in properties)
-                               AssignPropertyFromResources (method, pi, attvalue);
+                               AssignPropertyFromResources (builder, pi, attvalue);
                }
                
                void AssignPropertiesFromResources (ControlBuilder builder, string attvalue)
@@ -805,11 +910,10 @@ namespace System.Web.Compilation
                        if (controlType == null)
                                return;
 
-                       AssignPropertiesFromResources (builder.method, controlType, attvalue);
+                       AssignPropertiesFromResources (builder, controlType, attvalue);
                }
-#endif
                
-               void AddEventAssign (CodeMemberMethod method, string name, Type type, string value)
+               void AddEventAssign (CodeMemberMethod method, ControlBuilder builder, string name, Type type, string value)
                {
                        //"__ctrl.{0} += new {1} (this.{2});"
                        CodeEventReferenceExpression evtID = new CodeEventReferenceExpression (ctrlVar, name);
@@ -826,15 +930,16 @@ namespace System.Web.Compilation
                        EventInfo [] ev_info = null;
                        Type type = builder.ControlType;
                        
-                       string attvalue = builder.attribs [id] as string;
-                       if (id.Length > 2 && id.Substring (0, 2).ToUpper () == "ON"){
+                       string attvalue = builder.GetAttribute (id);
+                       if (id.Length > 2 && String.Compare (id.Substring (0, 2), "ON", true, Helpers.InvariantCulture) == 0){
                                if (ev_info == null)
                                        ev_info = type.GetEvents ();
 
                                string id_as_event = id.Substring (2);
                                foreach (EventInfo ev in ev_info){
                                        if (InvariantCompareNoCase (ev.Name, id_as_event)){
-                                               AddEventAssign (builder.method,
+                                               AddEventAssign (builder.Method,
+                                                               builder,
                                                                ev.Name,
                                                                ev.EventHandlerType,
                                                                attvalue);
@@ -845,12 +950,10 @@ namespace System.Web.Compilation
 
                        }
 
-#if NET_2_0
-                       if (id.ToLower () == "meta:resourcekey") {
+                       if (String.Compare (id, "meta:resourcekey", StringComparison.OrdinalIgnoreCase) == 0) {
                                AssignPropertiesFromResources (builder, attvalue);
                                return;
                        }
-#endif
                        
                        int hyphen = id.IndexOf ('-');
                        string alt_id = id;
@@ -864,16 +967,25 @@ namespace System.Web.Compilation
                        }
 
                        if (!typeof (IAttributeAccessor).IsAssignableFrom (type))
-                               throw new ParseException (builder.location, "Unrecognized attribute: " + id);
+                               throw new ParseException (builder.Location, "Unrecognized attribute: " + id);
 
-                       string val;
-                       CodeMemberMethod method = builder.method;
-                       bool databound = IsDataBound (attvalue);
+                       CodeMemberMethod method = builder.Method;
+                       bool isDatabound = IsDataBound (attvalue);
+                       bool isExpression = !isDatabound && IsExpression (attvalue);
 
-                       if (databound) {
-                               val = attvalue.Substring (3);
-                               val = val.Substring (0, val.Length - 2);
-                               CreateDBAttributeMethod (builder, id, val);
+                       if (isDatabound) {
+                               string value = attvalue.Substring (3, attvalue.Length - 5).Trim ();
+                               CodeExpression valueExpression = null;
+                               if (startsWithBindRegex.Match (value).Success)
+                                       valueExpression = CreateEvalInvokeExpression (bindRegexInValue, value, true);
+                               else
+                                       if (StrUtils.StartsWith (value, "Eval", true))
+                                               valueExpression = CreateEvalInvokeExpression (evalRegexInValue, value, false);
+                               
+                               if (valueExpression == null && value != null && value.Trim () != String.Empty)
+                                       valueExpression = new CodeSnippetExpression (value);
+                               
+                               CreateDBAttributeMethod (builder, id, valueExpression);
                        } else {
                                CodeCastExpression cast;
                                CodeMethodReferenceExpression methodExpr;
@@ -883,19 +995,23 @@ namespace System.Web.Compilation
                                methodExpr = new CodeMethodReferenceExpression (cast, "SetAttribute");
                                expr = new CodeMethodInvokeExpression (methodExpr);
                                expr.Parameters.Add (new CodePrimitiveExpression (id));
-                               expr.Parameters.Add (new CodePrimitiveExpression (attvalue));
-                               method.Statements.Add (expr);
-                       }
 
+                               CodeExpression valueExpr = null;
+                               if (isExpression)
+                                       valueExpr = CompileExpression (null, typeof (string), attvalue, true);
+
+                               if (valueExpr == null)
+                                       valueExpr = new CodePrimitiveExpression (attvalue);
+                               
+                               expr.Parameters.Add (valueExpr);
+                               method.Statements.Add (AddLinePragma (expr, builder));
+                       }
                }
 
                protected void CreateAssignStatementsFromAttributes (ControlBuilder builder)
                {
-#if NET_2_0
-                       bool haveMetaKey = false;
-#endif
                        this.dataBoundAtts = 0;
-                       IDictionary atts = builder.attribs;
+                       IDictionary atts = builder.Attributes;
                        if (atts == null || atts.Count == 0)
                                return;
                        
@@ -904,37 +1020,31 @@ namespace System.Web.Compilation
                                        continue;
                                // ID is assigned in BuildControltree
                                if (InvariantCompareNoCase (id, "id"))
-                                       continue;
-                               
-#if NET_2_0
+                                       continue;                               
+
                                /* we skip SkinID here as it's assigned in BuildControlTree */
                                if (InvariantCompareNoCase (id, "skinid"))
                                        continue;
-                               if (InvariantCompareNoCase (id, "meta:resourcekey")) {
-                                       haveMetaKey = true;
-                                       continue;
-                               }
-#endif
+                               if (InvariantCompareNoCase (id, "meta:resourcekey"))
+                                       continue; // ignore, this one's processed at the very end of
+                                                 // the method
                                CreateAssignStatementFromAttribute (builder, id);
                        }
-                       
-#if NET_2_0
-                       if (haveMetaKey)
-                               CreateAssignStatementFromAttribute (builder, "meta:resourcekey");
-#endif
                }
 
-               void CreateDBAttributeMethod (ControlBuilder builder, string attr, string code)
+               void CreateDBAttributeMethod (ControlBuilder builder, string attr, CodeExpression code)
                {
-                       if (code == null || code.Trim () == "")
+                       if (code == null)
                                return;
 
                        string id = builder.GetNextID (null);
                        string dbMethodName = "__DataBind_" + id;
-                       CodeMemberMethod method = builder.method;
-                       AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
+                       CodeMemberMethod method = builder.Method;
+                       AddEventAssign (method, builder, "DataBinding", typeof (EventHandler), dbMethodName);
+
+                       method = CreateDBMethod (builder, dbMethodName, GetContainerType (builder), builder.ControlType);
+                       builder.DataBindingMethod = method;
 
-                       method = CreateDBMethod (dbMethodName, GetContainerType (builder), builder.ControlType);
                        CodeCastExpression cast;
                        CodeMethodReferenceExpression methodExpr;
                        CodeMethodInvokeExpression expr;
@@ -948,7 +1058,7 @@ namespace System.Web.Compilation
                        tostring.Method = new CodeMethodReferenceExpression (
                                                        new CodeTypeReferenceExpression (typeof (Convert)),
                                                        "ToString");
-                       tostring.Parameters.Add (new CodeSnippetExpression (code));
+                       tostring.Parameters.Add (code);
                        expr.Parameters.Add (tostring);
                        method.Statements.Add (expr);
                        mainClass.Members.Add (method);
@@ -961,25 +1071,27 @@ namespace System.Web.Compilation
                                                        new CodeArgumentReferenceExpression ("parameterContainer"),
                                                        "Controls");
                                                        
-                       indexer.Indices.Add (new CodePrimitiveExpression (builder.renderIndex));
+                       indexer.Indices.Add (new CodePrimitiveExpression (builder.RenderIndex));
                        
                        CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (indexer, "RenderControl");
                        invoke.Parameters.Add (new CodeArgumentReferenceExpression ("__output"));
-                       builder.renderMethod.Statements.Add (invoke);
-                       builder.renderIndex++;
+                       builder.RenderMethod.Statements.Add (invoke);
+                       builder.IncreaseRenderIndex ();
                }
 
                protected void AddChildCall (ControlBuilder parent, ControlBuilder child)
                {
                        if (parent == null || child == null)
                                return;
-                       CodeMethodReferenceExpression m = new CodeMethodReferenceExpression (thisRef, child.method.Name);
+                       
+                       CodeMethodReferenceExpression m = new CodeMethodReferenceExpression (thisRef, child.Method.Name);
                        CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (m);
 
                        object [] atts = null;
-                       
+
                        if (child.ControlType != null)
-                               child.ControlType.GetCustomAttributes (typeof (PartialCachingAttribute), true);
+                               atts = child.ControlType.GetCustomAttributes (typeof (PartialCachingAttribute), true);
+                       
                        if (atts != null && atts.Length > 0) {
                                PartialCachingAttribute pca = (PartialCachingAttribute) atts [0];
                                CodeTypeReferenceExpression cc = new CodeTypeReferenceExpression("System.Web.UI.StaticPartialCachingControl");
@@ -999,35 +1111,35 @@ namespace System.Web.Compilation
                                build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByCustom));
                                build.Parameters.Add (new CodeDelegateCreateExpression (
                                                              new CodeTypeReference (typeof (System.Web.UI.BuildMethod)),
-                                                             thisRef, child.method.Name));
-                               
-                               parent.methodStatements.Add (build);
+                                                             thisRef, child.Method.Name));
+
+                               parent.MethodStatements.Add (AddLinePragma (build, parent));
                                if (parent.HasAspCode)
                                        AddRenderControl (parent);
                                return;
                        }
                                 
-                       if (child.isProperty || parent.ChildrenAsProperties) {
+                       if (child.IsProperty || parent.ChildrenAsProperties) {
                                expr.Parameters.Add (new CodeFieldReferenceExpression (ctrlVar, child.TagName));
-                               parent.methodStatements.Add (expr);
+                               parent.MethodStatements.Add (AddLinePragma (expr, parent));
                                return;
                        }
 
-                       parent.methodStatements.Add (expr);
+                       parent.MethodStatements.Add (AddLinePragma (expr, parent));
                        CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (thisRef, child.ID);
-                       if (parent.ControlType == null || typeof (IParserAccessor).IsAssignableFrom (parent.ControlType)) {
+                       if (parent.ControlType == null || typeof (IParserAccessor).IsAssignableFrom (parent.ControlType))
                                AddParsedSubObjectStmt (parent, field);
-                       else {
+                       else {
                                CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (ctrlVar, "Add");
                                invoke.Parameters.Add (field);
-                               parent.methodStatements.Add (invoke);
+                               parent.MethodStatements.Add (AddLinePragma (invoke, parent));
                        }
                                
                        if (parent.HasAspCode)
                                AddRenderControl (parent);
                }
 
-               void AddTemplateInvocation (CodeMemberMethod method, string name, string methodName)
+               void AddTemplateInvocation (ControlBuilder builder, string name, string methodName)
                {
                        CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
 
@@ -1038,11 +1150,10 @@ namespace System.Web.Compilation
                        newCompiled.Parameters.Add (newBuild);
 
                        CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
-                       method.Statements.Add (assign);
+                       builder.Method.Statements.Add (AddLinePragma (assign, builder));
                }
 
-#if NET_2_0
-               void AddBindableTemplateInvocation (CodeMemberMethod method, string name, string methodName, string extractMethodName)
+               void AddBindableTemplateInvocation (ControlBuilder builder, string name, string methodName, string extractMethodName)
                {
                        CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
 
@@ -1057,7 +1168,7 @@ namespace System.Web.Compilation
                        newCompiled.Parameters.Add (newExtract);
                        
                        CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
-                       method.Statements.Add (assign);
+                       builder.Method.Statements.Add (AddLinePragma (assign, builder));
                }
                
                string CreateExtractValuesMethod (TemplateBuilder builder)
@@ -1132,9 +1243,8 @@ namespace System.Web.Compilation
                        invoke.Parameters.Add (new CodePrimitiveExpression (cbuilder.ContentPlaceHolderID));
                        invoke.Parameters.Add (newCompiled);
 
-                       method.Statements.Add (invoke);
+                       method.Statements.Add (AddLinePragma (invoke, cbuilder));
                }
-#endif
 
                void AddCodeRender (ControlBuilder parent, CodeRenderBuilder cr)
                {
@@ -1143,7 +1253,7 @@ namespace System.Web.Compilation
 
                        if (!cr.IsAssign) {
                                CodeSnippetStatement code = new CodeSnippetStatement (cr.Code);
-                               parent.renderMethod.Statements.Add (code);
+                               parent.RenderMethod.Statements.Add (AddLinePragma (code, cr));
                                return;
                        }
 
@@ -1152,37 +1262,28 @@ namespace System.Web.Compilation
                                                        new CodeArgumentReferenceExpression ("__output"),
                                                        "Write");
 
-                       expr.Parameters.Add (new CodeSnippetExpression (cr.Code));
-                       parent.renderMethod.Statements.Add (expr);
+                       expr.Parameters.Add (GetWrappedCodeExpression (cr));
+                       parent.RenderMethod.Statements.Add (AddLinePragma (expr, cr));
                }
 
+               CodeExpression GetWrappedCodeExpression (CodeRenderBuilder cr)
+               {
+                       var ret = new CodeSnippetExpression (cr.Code);
+#if NET_4_0
+                       if (cr.HtmlEncode) {
+                               var encodeRef = new CodeMethodReferenceExpression (new CodeTypeReferenceExpression (typeof (HttpUtility)), "HtmlEncode");
+                               return new CodeMethodInvokeExpression (encodeRef, new CodeExpression[] { ret });
+                       } else
+#endif
+                               return ret;
+               }
+               
                static Type GetContainerType (ControlBuilder builder)
                {
-                       TemplateBuilder tb = builder as TemplateBuilder;
-                       if (tb != null && tb.ContainerType != null)
-                               return tb.ContainerType;
-#if NET_2_0
                        return builder.BindingContainerType;
-#else
-                       Type type = builder.BindingContainerType;
-
-                       PropertyInfo prop = type.GetProperty ("Items", noCaseFlags & ~BindingFlags.NonPublic);
-                       if (prop == null)
-                               return type;
-
-                       Type ptype = prop.PropertyType;
-                       if (!typeof (ICollection).IsAssignableFrom (ptype))
-                               return type;
-
-                       prop = ptype.GetProperty ("Item", noCaseFlags & ~BindingFlags.NonPublic);
-                       if (prop == null)
-                               return type;
-
-                       return prop.PropertyType;
-#endif
                }
                
-               CodeMemberMethod CreateDBMethod (string name, Type container, Type target)
+               CodeMemberMethod CreateDBMethod (ControlBuilder builder, string name, Type container, Type target)
                {
                        CodeMemberMethod method = new CodeMemberMethod ();
                        method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
@@ -1197,7 +1298,7 @@ namespace System.Web.Compilation
                        decl.Name = "Container";
                        decl.Type = containerRef;
                        method.Statements.Add (decl);
-
+                       
                        decl = new CodeVariableDeclarationStatement();
                        decl.Name = "target";
                        decl.Type = targetRef;
@@ -1207,13 +1308,13 @@ namespace System.Web.Compilation
                        CodeAssignStatement assign = new CodeAssignStatement ();
                        assign.Left = targetExpr;
                        assign.Right = new CodeCastExpression (targetRef, new CodeArgumentReferenceExpression ("sender"));
-                       method.Statements.Add (assign);
+                       method.Statements.Add (AddLinePragma (assign, builder));
 
                        assign = new CodeAssignStatement ();
                        assign.Left = new CodeVariableReferenceExpression ("Container");
                        assign.Right = new CodeCastExpression (containerRef,
                                                new CodePropertyReferenceExpression (targetExpr, "BindingContainer"));
-                       method.Statements.Add (assign);
+                       method.Statements.Add (AddLinePragma (assign, builder));
 
                        return method;
                }
@@ -1229,12 +1330,13 @@ namespace System.Web.Compilation
                        string dbMethodName = "__DataBind_" + db.ID;
                        // Add the method that builds the DataBoundLiteralControl
                        InitMethod (db, false, false);
-                       CodeMemberMethod method = db.method;
-                       AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
+                       CodeMemberMethod method = db.Method;
+                       AddEventAssign (method, builder, "DataBinding", typeof (EventHandler), dbMethodName);
                        method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
 
                        // Add the DataBind handler
-                       method = CreateDBMethod (dbMethodName, GetContainerType (builder), typeof (DataBoundLiteralControl));
+                       method = CreateDBMethod (builder, dbMethodName, GetContainerType (builder), typeof (DataBoundLiteralControl));
+                       builder.DataBindingMethod = method;
 
                        CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
                        CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
@@ -1247,10 +1349,10 @@ namespace System.Web.Compilation
                                                        "ToString");
                        tostring.Parameters.Add (new CodeSnippetExpression (db.Code));
                        invoke.Parameters.Add (tostring);
-                       method.Statements.Add (invoke);
+                       method.Statements.Add (AddLinePragma (invoke, builder));
                        
                        mainClass.Members.Add (method);
-
+                       
                        AddChildCall (builder, db);
                }
 
@@ -1270,16 +1372,14 @@ namespace System.Web.Compilation
                        if (!isTemplate && !inTemplate) {
                                CreateField (builder, true);
                        } else if (!isTemplate) {
-                               bool doCheck = false;
-                               
-#if NET_2_0
+                               bool doCheck = false;                           
                                bool singleInstance = false;
-                               ControlBuilder pb = builder.parentBuilder;
+                               ControlBuilder pb = builder.ParentBuilder;
                                TemplateBuilder tpb;
                                while (pb != null) {
                                        tpb = pb as TemplateBuilder;
                                        if (tpb == null) {
-                                               pb = pb.parentBuilder;
+                                               pb = pb.ParentBuilder;
                                                continue;
                                        }
                                        
@@ -1289,12 +1389,10 @@ namespace System.Web.Compilation
                                }
                                
                                if (!singleInstance)
-#endif
                                        builder.ID = builder.GetNextID (null);
-#if NET_2_0
                                else
                                        doCheck = true;
-#endif
+
                                CreateField (builder, doCheck);
                        }
 
@@ -1303,8 +1401,6 @@ namespace System.Web.Compilation
                                CreateAssignStatementsFromAttributes (builder);
 
                        if (builder.Children != null && builder.Children.Count > 0) {
-                               ArrayList templates = null;
-
                                StringBuilder sb = new StringBuilder ();
                                foreach (object b in builder.Children) {
                                        if (b is string) {
@@ -1315,110 +1411,103 @@ namespace System.Web.Compilation
                                        FlushText (builder, sb);
                                        if (b is ObjectTagBuilder) {
                                                ProcessObjectTag ((ObjectTagBuilder) b);
-                                               continue;
-                                       }
-
-                                       StringPropertyBuilder pb = b as StringPropertyBuilder;
-                                       if (pb != null){
+                                       } else if (b is StringPropertyBuilder) {
+                                               StringPropertyBuilder pb = b as StringPropertyBuilder;
                                                if (pb.Children != null && pb.Children.Count > 0) {
                                                        StringBuilder asb = new StringBuilder ();
                                                        foreach (string s in pb.Children)
                                                                asb.Append (s);
-                                                       CodeMemberMethod method = builder.method;
+                                                       CodeMemberMethod method = builder.Method;
                                                        CodeAssignStatement assign = new CodeAssignStatement ();
                                                        assign.Left = new CodePropertyReferenceExpression (ctrlVar, pb.PropertyName);
                                                        assign.Right = new CodePrimitiveExpression (asb.ToString ());
-                                                       method.Statements.Add (assign);
+                                                       method.Statements.Add (AddLinePragma (assign, builder));
                                                }
-                                               continue;
-                                       }
-
-#if NET_2_0
-                                       if (b is ContentBuilderInternal) {
+                                       } else if (b is ContentBuilderInternal) {
                                                ContentBuilderInternal cb = (ContentBuilderInternal) b;
                                                CreateControlTree (cb, false, true);
-                                               AddContentTemplateInvocation (cb, builder.method, cb.method.Name);
-                                               continue;
-                                       }
-#endif
-
-                                       if (b is TemplateBuilder) {
-                                               if (templates == null)
-                                                       templates = new ArrayList ();
-
-                                               templates.Add (b);
+                                               AddContentTemplateInvocation (cb, builder.Method, cb.Method.Name);
                                                continue;
                                        }
 
-                                       if (b is CodeRenderBuilder) {
+                                       // Ignore TemplateBuilders - they are processed in InitMethod
+                                       else if (b is TemplateBuilder) {
+                                       } else if (b is CodeRenderBuilder) {
                                                AddCodeRender (builder, (CodeRenderBuilder) b);
-                                               continue;
-                                       }
-
-                                       if (b is DataBindingBuilder) {
+                                       } else if (b is DataBindingBuilder) {
                                                AddDataBindingLiteral (builder, (DataBindingBuilder) b);
-                                               continue;
-                                       }
-                                       
-                                       if (b is ControlBuilder) {
+                                       } else if (b is ControlBuilder) {
                                                ControlBuilder child = (ControlBuilder) b;
                                                CreateControlTree (child, inTemplate, builder.ChildrenAsProperties);
                                                AddChildCall (builder, child);
                                                continue;
-                                       }
+                                       } else
+                                               throw new Exception ("???");
 
-                                       throw new Exception ("???");
+                                       ControlBuilder bldr = b as ControlBuilder;
+                                       bldr.ProcessGeneratedCode (CompileUnit, BaseType, DerivedType, bldr.Method, bldr.DataBindingMethod);
                                }
 
                                FlushText (builder, sb);
-
-                               if (templates != null) {
-                                       foreach (TemplateBuilder b in templates) {
-                                               CreateControlTree (b, true, false);
-#if NET_2_0
-                                               if (b.BindingDirection == BindingDirection.TwoWay) {
-                                                       string extractMethod = CreateExtractValuesMethod (b);
-                                                       AddBindableTemplateInvocation (builder.method, b.TagName, b.method.Name, extractMethod);
-                                               }
-                                               else
-#endif
-                                               AddTemplateInvocation (builder.method, b.TagName, b.method.Name);
-                                       }
-                               }
-
                        }
 
-                       if (builder.defaultPropertyBuilder != null) {
-                               ControlBuilder b = builder.defaultPropertyBuilder;
-                               CreateControlTree (b, false, true);
-                               AddChildCall (builder, b);
+                       ControlBuilder defaultPropertyBuilder = builder.DefaultPropertyBuilder;
+                       if (defaultPropertyBuilder != null) {
+                               CreateControlTree (defaultPropertyBuilder, false, true);
+                               AddChildCall (builder, defaultPropertyBuilder);
                        }
-
+                       
                        if (builder.HasAspCode) {
+                               CodeMemberMethod renderMethod = builder.RenderMethod;
                                CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
                                m.TargetObject = thisRef;
-                               m.MethodName = builder.renderMethod.Name;
+                               m.MethodName = renderMethod.Name;
 
                                CodeDelegateCreateExpression create = new CodeDelegateCreateExpression ();
                                create.DelegateType = new CodeTypeReference (typeof (RenderMethod));
                                create.TargetObject = thisRef;
-                               create.MethodName = builder.renderMethod.Name;
+                               create.MethodName = renderMethod.Name;
 
                                CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
                                invoke.Method = new CodeMethodReferenceExpression (ctrlVar, "SetRenderMethodDelegate");
                                invoke.Parameters.Add (create);
 
-                               builder.methodStatements.Add (invoke);
+                               builder.MethodStatements.Add (invoke);
                        }
-                       
-                       if (!childrenAsProperties && typeof (Control).IsAssignableFrom (builder.ControlType))
-                               builder.method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
 
-#if NET_2_0
                        if (builder is RootBuilder)
                                if (!String.IsNullOrEmpty (parser.MetaResourceKey))
-                                       AssignPropertiesFromResources (builder.method, parser.BaseType, parser.MetaResourceKey);
-#endif
+                                       AssignPropertiesFromResources (builder, parser.BaseType, parser.MetaResourceKey);
+                       
+                       if ((!isTemplate || builder is RootBuilder) && !String.IsNullOrEmpty (builder.GetAttribute ("meta:resourcekey")))
+                               CreateAssignStatementFromAttribute (builder, "meta:resourcekey");
+
+                       if (!childrenAsProperties && typeof (Control).IsAssignableFrom (builder.ControlType))
+                               builder.Method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
+
+                       builder.ProcessGeneratedCode (CompileUnit, BaseType, DerivedType, builder.Method, builder.DataBindingMethod);
+               }
+
+               protected override void AddStatementsToConstructor (CodeConstructor ctor)
+               {
+                       if (masterPageContentPlaceHolders == null || masterPageContentPlaceHolders.Count == 0)
+                               return;
+                       
+                       var ilist = new CodeVariableDeclarationStatement ();
+                       ilist.Name = "__contentPlaceHolders";
+                       ilist.Type = new CodeTypeReference (typeof (IList));
+                       ilist.InitExpression = new CodePropertyReferenceExpression (thisRef, "ContentPlaceHolders");
+                       
+                       var ilistRef = new CodeVariableReferenceExpression ("__contentPlaceHolders");
+                       CodeStatementCollection statements = ctor.Statements;
+                       statements.Add (ilist);
+
+                       CodeMethodInvokeExpression mcall;
+                       foreach (string id in masterPageContentPlaceHolders) {
+                               mcall = new CodeMethodInvokeExpression (ilistRef, "Add");
+                               mcall.Parameters.Add (new CodePrimitiveExpression (id.ToLowerInvariant ()));
+                               statements.Add (mcall);
+                       }
                }
                
                protected internal override void CreateMethods ()
@@ -1430,13 +1519,42 @@ namespace System.Web.Compilation
                        CreateFrameworkInitializeMethod ();
                }
 
+               protected override void InitializeType ()
+               {
+                       List <string> registeredTagNames = parser.RegisteredTagNames;
+                       RootBuilder rb = parser.RootBuilder;
+                       if (rb == null || registeredTagNames == null || registeredTagNames.Count == 0)
+                               return;
+
+                       AspComponent component;
+                       foreach (string tagName in registeredTagNames) {
+                               component = rb.Foundry.GetComponent (tagName);
+                               if (component == null || component.Type == null) // unlikely
+                                       throw new HttpException ("Custom control '" + tagName + "' cannot be found.");
+                               if (!(typeof (UserControl).IsAssignableFrom (component.Type)))
+                                       throw new ParseException (parser.Location, "Type '" + component.Type.ToString () + "' does not derive from 'System.Web.UI.UserControl'.");
+                               AddReferencedAssembly (component.Type.Assembly);
+                       }
+               }
+               
                void CallBaseFrameworkInitialize (CodeMemberMethod method)
                {
                        CodeBaseReferenceExpression baseRef = new CodeBaseReferenceExpression ();
                        CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (baseRef, "FrameworkInitialize");
                        method.Statements.Add (invoke);
                }
-
+               
+               void CallSetStringResourcePointer (CodeMemberMethod method)
+               {
+                       CodeFieldReferenceExpression stringResource = GetMainClassFieldReferenceExpression ("__stringResource");
+                       method.Statements.Add (
+                               new CodeMethodInvokeExpression (
+                                       thisRef,
+                                       "SetStringResourcePointer",
+                                       new CodeExpression[] {stringResource, new CodePrimitiveExpression (0)})
+                       );
+               }
+               
                void CreateFrameworkInitializeMethod ()
                {
                        CodeMemberMethod method = new CodeMemberMethod ();
@@ -1444,6 +1562,7 @@ namespace System.Web.Compilation
                        method.Attributes = MemberAttributes.Family | MemberAttributes.Override;
                        PrependStatementsToFrameworkInitialize (method);
                        CallBaseFrameworkInitialize (method);
+                       CallSetStringResourcePointer (method);
                        AppendStatementsToFrameworkInitialize (method);
                        mainClass.Members.Add (method);
                }
@@ -1479,6 +1598,16 @@ namespace System.Web.Compilation
                        }
                }
 
+               protected override void CreateStaticFields ()
+               {
+                       base.CreateStaticFields ();
+
+                       CodeMemberField fld = new CodeMemberField (typeof (object), "__stringResource");
+                       fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
+                       fld.InitExpression = new CodePrimitiveExpression (null);
+                       mainClass.Members.Add (fld);
+               }
+               
                protected void ProcessObjectTag (ObjectTagBuilder tag)
                {
                        string fieldName = CreateFieldForObject (tag.Type, tag.ObjectID);
@@ -1510,14 +1639,41 @@ namespace System.Web.Compilation
 
                        CodeCastExpression cast = new CodeCastExpression (appType.FullName, propRef);
                        prop.GetStatements.Add (new CodeMethodReturnStatement (cast));
-#if NET_2_0
                        if (partialClass != null)
                                partialClass.Members.Add (prop);
                        else
-#endif
-                       mainClass.Members.Add (prop);
+                               mainClass.Members.Add (prop);
                }
 
+               void CreateContentPlaceHolderTemplateProperty (string backingField, string name)
+               {
+                       CodeMemberProperty prop = new CodeMemberProperty ();
+                       prop.Type = new CodeTypeReference (typeof (ITemplate));
+                       prop.Name = name;
+                       prop.Attributes = MemberAttributes.Public;
+
+                       var ret = new CodeMethodReturnStatement ();
+                       var fldRef = new CodeFieldReferenceExpression (thisRef, backingField);
+                       ret.Expression = fldRef;
+                       prop.GetStatements.Add (ret);
+                       prop.SetStatements.Add (new CodeAssignStatement (fldRef, new CodePropertySetValueReferenceExpression ()));
+
+                       prop.CustomAttributes.Add (new CodeAttributeDeclaration ("TemplateContainer", new CodeAttributeArgument [] {
+                                               new CodeAttributeArgument (new CodeTypeOfExpression (new CodeTypeReference (typeof (MasterPage))))
+                                       }
+                               )
+                       );
+
+                       var enumValueRef = new CodeFieldReferenceExpression (new CodeTypeReferenceExpression (typeof (TemplateInstance)), "Single");
+                       prop.CustomAttributes.Add (new CodeAttributeDeclaration ("TemplateInstanceAttribute", new CodeAttributeArgument [] {
+                                               new CodeAttributeArgument (enumValueRef)
+                                       }
+                               )
+                       );
+
+                       mainClass.Members.Add (prop);
+               }
+               
                void CreateAutoHandlers ()
                {
                        // Create AutoHandlers property
@@ -1533,11 +1689,8 @@ namespace System.Web.Compilation
                        prop.GetStatements.Add (ret);
                        prop.SetStatements.Add (new CodeAssignStatement (fldRef, new CodePropertySetValueReferenceExpression ()));
 
-#if NET_2_0
                        CodeAttributeDeclaration attr = new CodeAttributeDeclaration ("System.Obsolete");
-                       prop.CustomAttributes.Add (attr);
-#endif
-                       
+                       prop.CustomAttributes.Add (attr);                       
                        mainClass.Members.Add (prop);
 
                        // Add the __autoHandlers field
@@ -1557,77 +1710,65 @@ namespace System.Web.Compilation
                        mainClass.Members.Add (prop);
                }
 
-#if NET_2_0
                protected virtual string HandleUrlProperty (string str, MemberInfo member)
                {
                        return str;
                }
-#endif
 
                TypeConverter GetConverterForMember (MemberInfo member)
                {
-                       TypeConverterAttribute tca = null;
-                       object[] attrs;
-                       
-#if NET_2_0
-                       attrs = member.GetCustomAttributes (typeof (TypeConverterAttribute), true);
-                       if (attrs.Length > 0)
-                               tca = attrs [0] as TypeConverterAttribute;
-#else
-                       attrs = member.GetCustomAttributes (true);
-                       
-                       foreach (object attr in attrs) {
-                               tca = attr as TypeConverterAttribute;
-                               
-                               if (tca != null)
-                                       break;
-                       }
-#endif
-
-                       if (tca == null)
+                       TypeDescriptionProvider prov = TypeDescriptor.GetProvider (member.ReflectedType);
+                       if (prov == null)
                                return null;
 
-                       string typeName = tca.ConverterTypeName;
-                       if (typeName == null || typeName.Length == 0)
-                               return null;
+                       ICustomTypeDescriptor desc = prov.GetTypeDescriptor (member.ReflectedType);
+                       PropertyDescriptorCollection coll = desc != null ? desc.GetProperties () : null;
 
-                       Type t = null;
-                       try {
-                               t = Type.GetType (typeName);
-                       } catch (Exception) {
-                               // ignore
-                       }
+                       if (coll == null || coll.Count == 0)
+                               return null;
 
-                       if (t == null)
+                       PropertyDescriptor pd = coll.Find (member.Name, false);
+                       if (pd == null)
                                return null;
 
-                       return (TypeConverter) Activator.CreateInstance (t);
+                       return pd.Converter;
                }
                
                CodeExpression CreateNullableExpression (Type type, CodeExpression inst, bool nullable)
                {
-#if NET_2_0
                        if (!nullable)
                                return inst;
                        
-                       return new CodeObjectCreateExpression (
-                               type,
-                               new CodeExpression[] {inst}
-                       );
-#else
-                       return inst;
-#endif
+                       return new CodeObjectCreateExpression (type, new CodeExpression[] {inst});
+               }
+
+               bool SafeCanConvertFrom (Type type, TypeConverter cvt)
+               {
+                       try {
+                               return cvt.CanConvertFrom (type);
+                       } catch (NotImplementedException) {
+                               return false;
+                       }
+               }
+
+               bool SafeCanConvertTo (Type type, TypeConverter cvt)
+               {
+                       try {
+                               return cvt.CanConvertTo (type);
+                       } catch (NotImplementedException) {
+                               return false;
+                       }
                }
                
                CodeExpression GetExpressionFromString (Type type, string str, MemberInfo member)
                {
                        TypeConverter cvt = GetConverterForMember (member);
-                       if (cvt != null && !cvt.CanConvertFrom (typeof (string)))
+                       if (cvt != null && !SafeCanConvertFrom (typeof (string), cvt))
                                cvt = null;
-
+                       
                        object convertedFromAttr = null;
                        bool preConverted = false;
-                       if (cvt != null) {
+                       if (cvt != null && str != null) {
                                convertedFromAttr = cvt.ConvertFromInvariantString (str);
                                if (convertedFromAttr != null) {
                                        type = convertedFromAttr.GetType ();
@@ -1637,30 +1778,25 @@ namespace System.Web.Compilation
 
                        bool wasNullable = false;
                        Type originalType = type;
-#if NET_2_0
+
                        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {
                                Type[] types = type.GetGenericArguments();
                                originalType = type;
                                type = types[0]; // we're interested only in the first type here
                                wasNullable = true;
                        }
-#endif
-                       
+
                        if (type == typeof (string)) {
-                               if (preConverted)
+                               object[] urlAttr = member.GetCustomAttributes (typeof (UrlPropertyAttribute), true);
+                               if (urlAttr.Length != 0)
+                                       str = HandleUrlProperty ((preConverted && convertedFromAttr is string) ? (string)convertedFromAttr : str, member);
+                               else if (preConverted)
                                        return CreateNullableExpression (originalType,
                                                                         new CodePrimitiveExpression ((string) convertedFromAttr),
                                                                         wasNullable);
-                               
-#if NET_2_0
-                               object[] urlAttr = member.GetCustomAttributes (typeof (UrlPropertyAttribute), true);
-                               if (urlAttr.Length != 0)
-                                       str = HandleUrlProperty (str, member);
-#endif
-                               return CreateNullableExpression (originalType, new CodePrimitiveExpression (str), wasNullable);
-                       }
 
-                       if (type == typeof (bool)) {
+                               return CreateNullableExpression (originalType, new CodePrimitiveExpression (str), wasNullable);
+                       } else if (type == typeof (bool)) {
                                if (preConverted)
                                        return CreateNullableExpression (originalType,
                                                                         new CodePrimitiveExpression ((bool) convertedFromAttr),
@@ -1670,14 +1806,13 @@ namespace System.Web.Compilation
                                        return CreateNullableExpression (originalType, new CodePrimitiveExpression (true), wasNullable);
                                else if (InvariantCompareNoCase (str, "false"))
                                        return CreateNullableExpression (originalType, new CodePrimitiveExpression (false), wasNullable);
-#if NET_2_0
                                else if (wasNullable && InvariantCompareNoCase(str, "null"))
                                        return new CodePrimitiveExpression (null);
-#endif
                                else
                                        throw new ParseException (currentLocation,
                                                        "Value '" + str  + "' is not a valid boolean.");
-                       }
+                       } else if (type == monoTypeType)
+                               type = typeof (System.Type);
                        
                        if (str == null)
                                return new CodePrimitiveExpression (null);
@@ -1686,7 +1821,7 @@ namespace System.Web.Compilation
                                return CreateNullableExpression (originalType,
                                                                 new CodePrimitiveExpression (
                                                                         Convert.ChangeType (preConverted ? convertedFromAttr : str,
-                                                                                            type, CultureInfo.InvariantCulture)),
+                                                                                            type, Helpers.InvariantCulture)),
                                                                 wasNullable);
 
                        if (type == typeof (string [])) {
@@ -1771,20 +1906,48 @@ namespace System.Web.Compilation
                                }
                        }
 
-                       TypeConverter converter = preConverted ? cvt :
-                               wasNullable ? TypeDescriptor.GetConverter (type) :
-                               TypeDescriptor.GetProperties (member.DeclaringType) [member.Name].Converter;
+                       TypeConverter converter = preConverted ? cvt : wasNullable ? TypeDescriptor.GetConverter (type) : null;
+                       if (converter == null) {
+                               PropertyDescriptor pdesc = TypeDescriptor.GetProperties (member.DeclaringType) [member.Name];
+                               if (pdesc != null)
+                                       converter = pdesc.Converter;
+                               else {
+                                       Type memberType;
+                                       switch (member.MemberType) {
+                                               case MemberTypes.Field:
+                                                       memberType = ((FieldInfo)member).FieldType;
+                                                       break;
+
+                                               case MemberTypes.Property:
+                                                       memberType = ((PropertyInfo)member).PropertyType;
+                                                       break;
+
+                                               default:
+                                                       memberType = null;
+                                                       break;
+                                       }
+
+                                       if (memberType == null)
+                                               return null;
 
-                       if (preConverted || (converter != null && converter.CanConvertFrom (typeof (string)))) {
+                                       converter = TypeDescriptor.GetConverter (memberType);
+                               }
+                       }
+                       
+                       if (preConverted || (converter != null && SafeCanConvertFrom (typeof (string), converter))) {
                                object value = preConverted ? convertedFromAttr : converter.ConvertFromInvariantString (str);
 
-                               if (converter.CanConvertTo (typeof (InstanceDescriptor))) {
+                               if (SafeCanConvertTo (typeof (InstanceDescriptor), converter)) {
                                        InstanceDescriptor idesc = (InstanceDescriptor) converter.ConvertTo (value, typeof(InstanceDescriptor));
                                        if (wasNullable)
                                                return CreateNullableExpression (originalType, GenerateInstance (idesc, true),
                                                                                 wasNullable);
-                                       
-                                       return new CodeCastExpression (type, GenerateInstance (idesc, true));
+
+                                       CodeExpression instance = GenerateInstance (idesc, true);
+                                       if (type.IsPublic)
+                                               return new CodeCastExpression (type, instance);
+                                       else
+                                               return instance;
                                }
 
                                CodeExpression exp = GenerateObjectInstance (value, false);
@@ -1803,7 +1966,7 @@ namespace System.Web.Compilation
 
                                if (wasNullable)
                                        return CreateNullableExpression (originalType, invoke, wasNullable);
-                               
+
                                return new CodeCastExpression (type, invoke);
                        }
 
@@ -1887,6 +2050,10 @@ namespace System.Web.Compilation
                {
                        if (value is System.Web.UI.WebControls.Unit) {
                                System.Web.UI.WebControls.Unit s = (System.Web.UI.WebControls.Unit) value;
+                               if (s.IsEmpty) {
+                                       FieldInfo f = typeof (Unit).GetField ("Empty");
+                                       return new InstanceDescriptor (f, null);
+                               }
                                ConstructorInfo c = typeof(System.Web.UI.WebControls.Unit).GetConstructor (
                                        BindingFlags.Instance | BindingFlags.Public,
                                        null,
@@ -1898,6 +2065,10 @@ namespace System.Web.Compilation
                        
                        if (value is System.Web.UI.WebControls.FontUnit) {
                                System.Web.UI.WebControls.FontUnit s = (System.Web.UI.WebControls.FontUnit) value;
+                               if (s.IsEmpty) {
+                                       FieldInfo f = typeof (FontUnit).GetField ("Empty");
+                                       return new InstanceDescriptor (f, null);
+                               }
 
                                Type cParamType = null;
                                object cParam = null;
@@ -1925,6 +2096,21 @@ namespace System.Web.Compilation
                        }
                        return null;
                }
+
+#if DEBUG
+               CodeMethodInvokeExpression CreateConsoleWriteLineCall (string format, params CodeExpression[] parms)
+               {
+                       CodeMethodReferenceExpression cwl = new CodeMethodReferenceExpression (new CodeTypeReferenceExpression (typeof (System.Console)), "WriteLine");
+                       CodeMethodInvokeExpression cwlCall = new CodeMethodInvokeExpression (cwl);
+
+                       cwlCall.Parameters.Add (new CodePrimitiveExpression (format));
+                       if (parms != null && parms.Length > 0)
+                               foreach (CodeExpression expr in parms)
+                                       cwlCall.Parameters.Add (expr);
+
+                       return cwlCall;
+               }
+#endif
        }
 }