New tests.
[mono.git] / mcs / class / System.Web / System.Web.Compilation / TemplateControlCompiler.cs
index 534da95174ff149bb44e4d39bceaadfa8dc3d2fb..4b01ccd67853f2ae263f23f390a1cc351188cde5 100644 (file)
@@ -32,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;
 using System.Text.RegularExpressions;
-#if NET_2_0
-using System.Configuration;
-using System.Collections.Specialized;
-using System.Collections.Generic;
-using System.Web.Configuration;
-#endif
 
 namespace System.Web.Compilation
 {
@@ -65,14 +64,14 @@ namespace System.Web.Compilation
 
                internal static CodeVariableReferenceExpression ctrlVar = new CodeVariableReferenceExpression ("__ctrl");
                
-#if NET_2_0
                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);
-#endif
                static Regex evalRegexInValue = new Regex (@"(.*)Eval\s*\(\s*[""']+(.*?)[""']+((\s*,\s*[""']+(.*?)[""']+)?)\s*\)(.*)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
 
-#if NET_2_0
                List <string> MasterPageContentPlaceHolders {
                        get {
                                if (masterPageContentPlaceHolders == null)
@@ -80,7 +79,7 @@ namespace System.Web.Compilation
                                return masterPageContentPlaceHolders;
                        }
                }
-#endif
+
                public TemplateControlCompiler (TemplateControlParser parser)
                        : base (parser)
                {
@@ -97,26 +96,23 @@ namespace System.Web.Compilation
                {
                        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 (AddLinePragma (field, builder));
                        else
-#endif
                                mainClass.Members.Add (AddLinePragma (field, builder));
                }
 
@@ -140,15 +136,8 @@ 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;
@@ -156,29 +145,29 @@ namespace System.Web.Compilation
                
                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 (AddLinePragma (invoke, builder));
+                       builder.MethodStatements.Add (AddLinePragma (invoke, builder));
                }
                
                void InitMethod (ControlBuilder builder, bool isTemplate, bool childrenAsProperties)
                {
-                       currentLocation = builder.location;
+                       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;
@@ -188,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 ();
@@ -215,7 +202,7 @@ 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 
@@ -268,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;
 
@@ -297,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))
@@ -310,7 +295,6 @@ namespace System.Web.Compilation
                                                applyStyleSheetSkin.Parameters.Add (new CodePropertyReferenceExpression (thisRef, "Page"));
                                        method.Statements.Add (applyStyleSheetSkin);
                                }
-#endif
 
                                // Process template children before anything else
                                ProcessTemplateChildren (builder);
@@ -318,13 +302,10 @@ namespace System.Web.Compilation
                                // 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");
-                               }
+                               string ctl_id = builder.GetAttribute ("id");
+                               if (ctl_id != null && ctl_id.Length != 0)
+                                       CreateAssignStatementFromAttribute (builder, "id");
                                
-#if NET_2_0
                                if (typeof (ContentPlaceHolder).IsAssignableFrom (type)) {
                                        List <string> placeHolderIds = MasterPageContentPlaceHolders;
                                        string cphID = builder.ID;
@@ -391,9 +372,8 @@ 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);
@@ -405,18 +385,15 @@ namespace System.Web.Compilation
                        if (templates != null && templates.Count > 0) {
                                foreach (TemplateBuilder tb in templates) {
                                        CreateControlTree (tb, true, false);
-#if NET_2_0
                                        if (tb.BindingDirection == BindingDirection.TwoWay) {
                                                string extractMethod = CreateExtractValuesMethod (tb);
-                                               AddBindableTemplateInvocation (builder, tb.TagName, tb.method.Name, extractMethod);
+                                               AddBindableTemplateInvocation (builder, tb.TagName, tb.Method.Name, extractMethod);
                                        } else
-#endif
-                                               AddTemplateInvocation (builder, tb.TagName, tb.method.Name);
+                                               AddTemplateInvocation (builder, tb.TagName, tb.Method.Name);
                                }
                        }
                }
                
-#if NET_2_0
                void SetCustomAttribute (CodeMemberMethod method, UnknownAttributeDescriptor uad)
                {
                        CodeAssignStatement assign = new CodeAssignStatement ();
@@ -441,7 +418,6 @@ namespace System.Web.Compilation
                        foreach (UnknownAttributeDescriptor uad in attrs)
                                SetCustomAttribute (method, uad);
                }
-#endif
                
                protected virtual void AddStatementsToInitMethod (CodeMemberMethod method)
                {
@@ -460,7 +436,7 @@ namespace System.Web.Compilation
 
                                CodeMethodInvokeExpression expr;
                                expr = new CodeMethodInvokeExpression (methodRef, new CodePrimitiveExpression (str));
-                               builder.renderMethod.Statements.Add (AddLinePragma (expr, builder));
+                               builder.RenderMethod.Statements.Add (expr);
                        }
                }
 
@@ -481,10 +457,8 @@ namespace System.Web.Compilation
                {
                        Match match = regex.Match (value);
                        if (!match.Success) {
-#if NET_2_0
                                if (isBind)
                                        throw new HttpParseException ("Bind invocation wasn't formatted properly.");
-#endif
                                return null;
                        }
                        
@@ -501,7 +475,7 @@ namespace System.Web.Compilation
                {
                        GroupCollection groups = match.Groups;
                        StringBuilder sb = new StringBuilder ("Eval(\"" + groups [1] + "\"");
-                       Group second = groups [2];
+                       Group second = groups [4];
                        if (second != null) {
                                string v = second.Value;
                                if (v != null && v.Length > 0)
@@ -516,18 +490,16 @@ namespace System.Web.Compilation
                {
                        value = TrimDB (value, true);
                        CodeMemberMethod method;
-                       string dbMethodName = builder.method.Name + "_DB_" + dataBoundAtts++;
+                       string dbMethodName = builder.Method.Name + "_DB_" + dataBoundAtts++;
                        CodeExpression valueExpression = null;
                        value = value.Trim ();
                        
-#if NET_2_0
                        bool need_if = false;
-                       if (StrUtils.StartsWith (value, "Bind", true)) {
+                       if (startsWithBindRegex.Match (value).Success) {
                                valueExpression = CreateEvalInvokeExpression (bindRegexInValue, value, true);
                                if (valueExpression != null)
                                        need_if = true;
                        } else
-#endif
                                if (StrUtils.StartsWith (value, "Eval", true))
                                        valueExpression = CreateEvalInvokeExpression (evalRegexInValue, value, false);
                        
@@ -535,7 +507,6 @@ namespace System.Web.Compilation
                                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
@@ -552,16 +523,13 @@ namespace System.Web.Compilation
                                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);
@@ -570,24 +538,21 @@ 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, builder, "DataBinding", typeof (EventHandler), dbMethodName);
                                return;
-                       }
-#if NET_2_0
-                       else if (isExpression && isWritable) {
+                       } 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 (AddLinePragma (assign, builder));
@@ -624,7 +589,6 @@ namespace System.Web.Compilation
                        return IsDirective (value, '#');
                }
 
-#if NET_2_0
                bool IsExpression (string value)
                {
                        return IsDirective (value, '$');
@@ -645,26 +609,25 @@ namespace System.Web.Compilation
                                        if (templateBuilder.BindingDirection == BindingDirection.OneWay)
                                                return;
                                        
-                                       string id = builder.attribs ["ID"] as string;
-                                       if (id == null)
+                                       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)
@@ -701,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;
@@ -714,11 +673,9 @@ 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;
                                
@@ -729,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;
                        
@@ -761,10 +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
+
                        AddCodeForPropertyOrField (builder, subprop.PropertyType,
                                                   prefix + member.Name + "." + subprop.Name,
                                                   val, subprop, isDataBound, isExpression);
@@ -772,7 +729,6 @@ namespace System.Web.Compilation
                        return true;
                }
 
-#if NET_2_0
                CodeExpression CompileExpression (MemberInfo member, Type type, string value, bool useSetAttribute)
                {
                        // First let's find the correct expression builder
@@ -783,11 +739,7 @@ namespace System.Web.Compilation
                        string prefix = value.Substring (0, colon).Trim ();
                        string expr = value.Substring (colon + 1).Trim ();
                        
-                       System.Configuration.Configuration config = WebConfigurationManager.OpenWebConfiguration ("");
-                       if (config == null)
-                               return null;
-                       
-                       CompilationSection cs = (CompilationSection)config.GetSection ("system.web/compilation");
+                       CompilationSection cs = (CompilationSection)WebConfigurationManager.GetWebApplicationSection ("system.web/compilation");
                        if (cs == null)
                                return null;
                        
@@ -837,7 +789,7 @@ namespace System.Web.Compilation
                        assign.Left = new CodePropertyReferenceExpression (ctrlVar, name);
                        assign.Right = expr;
                        
-                       builder.method.Statements.Add (AddLinePragma (assign, builder));
+                       builder.Method.Statements.Add (AddLinePragma (assign, builder));
                }
 
                BoundPropertyEntry CreateBoundPropertyEntry (PropertyInfo pi, string prefix, string expr, bool useSetAttribute)
@@ -855,6 +807,36 @@ namespace System.Web.Compilation
                        
                        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 (ControlBuilder builder, MemberInfo mi, string attvalue)
                {
@@ -864,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.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;
@@ -892,7 +881,7 @@ namespace System.Web.Compilation
                        assign.Left = new CodePropertyReferenceExpression (ctrlVar, memberName);
                        assign.Right = ResourceExpressionBuilder.CreateGetLocalResourceObject (mi, resname);
                        
-                       builder.method.Statements.Add (AddLinePragma (assign, builder));
+                       builder.Method.Statements.Add (AddLinePragma (assign, builder));
                }
 
                void AssignPropertiesFromResources (ControlBuilder builder, Type controlType, string attvalue)
@@ -923,7 +912,6 @@ namespace System.Web.Compilation
 
                        AssignPropertiesFromResources (builder, controlType, attvalue);
                }
-#endif
                
                void AddEventAssign (CodeMemberMethod method, ControlBuilder builder, string name, Type type, string value)
                {
@@ -942,15 +930,15 @@ 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,
@@ -962,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;
@@ -981,24 +967,20 @@ 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);
 
-                       CodeMemberMethod method = builder.method;
+                       CodeMemberMethod method = builder.Method;
                        bool isDatabound = IsDataBound (attvalue);
-#if NET_2_0
                        bool isExpression = !isDatabound && IsExpression (attvalue);
-#endif
 
                        if (isDatabound) {
                                string value = attvalue.Substring (3, attvalue.Length - 5).Trim ();
                                CodeExpression valueExpression = null;
-#if NET_2_0
-                               if (StrUtils.StartsWith (value, "Bind", true))
+                               if (startsWithBindRegex.Match (value).Success)
                                        valueExpression = CreateEvalInvokeExpression (bindRegexInValue, value, true);
                                else
-#endif
-                               if (StrUtils.StartsWith (value, "Eval", true))
-                                       valueExpression = CreateEvalInvokeExpression (evalRegexInValue, value, false);
+                                       if (StrUtils.StartsWith (value, "Eval", true))
+                                               valueExpression = CreateEvalInvokeExpression (evalRegexInValue, value, false);
                                
                                if (valueExpression == null && value != null && value.Trim () != String.Empty)
                                        valueExpression = new CodeSnippetExpression (value);
@@ -1015,12 +997,10 @@ namespace System.Web.Compilation
                                expr.Parameters.Add (new CodePrimitiveExpression (id));
 
                                CodeExpression valueExpr = null;
-#if NET_2_0
                                if (isExpression)
                                        valueExpr = CompileExpression (null, typeof (string), attvalue, true);
 
                                if (valueExpr == null)
-#endif
                                        valueExpr = new CodePrimitiveExpression (attvalue);
                                
                                expr.Parameters.Add (valueExpr);
@@ -1031,7 +1011,7 @@ namespace System.Web.Compilation
                protected void CreateAssignStatementsFromAttributes (ControlBuilder builder)
                {
                        this.dataBoundAtts = 0;
-                       IDictionary atts = builder.attribs;
+                       IDictionary atts = builder.Attributes;
                        if (atts == null || atts.Count == 0)
                                return;
                        
@@ -1040,16 +1020,14 @@ 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"))
                                        continue; // ignore, this one's processed at the very end of
                                                  // the method
-#endif
                                CreateAssignStatementFromAttribute (builder, id);
                        }
                }
@@ -1061,10 +1039,12 @@ namespace System.Web.Compilation
 
                        string id = builder.GetNextID (null);
                        string dbMethodName = "__DataBind_" + id;
-                       CodeMemberMethod method = builder.method;
+                       CodeMemberMethod method = builder.Method;
                        AddEventAssign (method, builder, "DataBinding", typeof (EventHandler), dbMethodName);
 
                        method = CreateDBMethod (builder, dbMethodName, GetContainerType (builder), builder.ControlType);
+                       builder.DataBindingMethod = method;
+
                        CodeCastExpression cast;
                        CodeMethodReferenceExpression methodExpr;
                        CodeMethodInvokeExpression expr;
@@ -1091,12 +1071,12 @@ 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)
@@ -1104,7 +1084,7 @@ namespace System.Web.Compilation
                        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;
@@ -1131,28 +1111,28 @@ 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));
+                                                             thisRef, child.Method.Name));
 
-                               parent.methodStatements.Add (AddLinePragma (build, parent));
+                               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 (AddLinePragma (expr, parent));
+                               parent.MethodStatements.Add (AddLinePragma (expr, parent));
                                return;
                        }
 
-                       parent.methodStatements.Add (AddLinePragma (expr, parent));
+                       parent.MethodStatements.Add (AddLinePragma (expr, parent));
                        CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (thisRef, child.ID);
                        if (parent.ControlType == null || typeof (IParserAccessor).IsAssignableFrom (parent.ControlType))
                                AddParsedSubObjectStmt (parent, field);
                        else {
                                CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (ctrlVar, "Add");
                                invoke.Parameters.Add (field);
-                               parent.methodStatements.Add (AddLinePragma (invoke, parent));
+                               parent.MethodStatements.Add (AddLinePragma (invoke, parent));
                        }
                                
                        if (parent.HasAspCode)
@@ -1170,10 +1150,9 @@ namespace System.Web.Compilation
                        newCompiled.Parameters.Add (newBuild);
 
                        CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
-                       builder.method.Statements.Add (AddLinePragma (assign, builder));
+                       builder.Method.Statements.Add (AddLinePragma (assign, builder));
                }
 
-#if NET_2_0
                void AddBindableTemplateInvocation (ControlBuilder builder, string name, string methodName, string extractMethodName)
                {
                        CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
@@ -1189,7 +1168,7 @@ namespace System.Web.Compilation
                        newCompiled.Parameters.Add (newExtract);
                        
                        CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
-                       builder.method.Statements.Add (AddLinePragma (assign, builder));
+                       builder.Method.Statements.Add (AddLinePragma (assign, builder));
                }
                
                string CreateExtractValuesMethod (TemplateBuilder builder)
@@ -1266,7 +1245,6 @@ namespace System.Web.Compilation
 
                        method.Statements.Add (AddLinePragma (invoke, cbuilder));
                }
-#endif
 
                void AddCodeRender (ControlBuilder parent, CodeRenderBuilder cr)
                {
@@ -1275,7 +1253,7 @@ namespace System.Web.Compilation
 
                        if (!cr.IsAssign) {
                                CodeSnippetStatement code = new CodeSnippetStatement (cr.Code);
-                               parent.renderMethod.Statements.Add (AddLinePragma (code, cr));
+                               parent.RenderMethod.Statements.Add (AddLinePragma (code, cr));
                                return;
                        }
 
@@ -1284,49 +1262,25 @@ namespace System.Web.Compilation
                                                        new CodeArgumentReferenceExpression ("__output"),
                                                        "Write");
 
-                       expr.Parameters.Add (new CodeSnippetExpression (cr.Code));
-                       parent.renderMethod.Statements.Add (AddLinePragma (expr, cr));
+                       expr.Parameters.Add (GetWrappedCodeExpression (cr));
+                       parent.RenderMethod.Statements.Add (AddLinePragma (expr, cr));
                }
 
-               static PropertyInfo GetContainerProperty (Type type, string[] propNames)
+               CodeExpression GetWrappedCodeExpression (CodeRenderBuilder cr)
                {
-                       PropertyInfo prop;
-                       
-                       foreach (string name in propNames) {
-                               prop = type.GetProperty (name, noCaseFlags & ~BindingFlags.NonPublic);
-                               if (prop != null)
-                                       return prop;
-                       }
-
-                       return null;
-               }
-
-#if !NET_2_0
-               static string[] containerPropNames = {"Items", "Rows"};
+                       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)
                {
-                       Type type = builder.BindingContainerType;
-                       
-#if NET_2_0
-                       return type;
-#else
-                       
-                       PropertyInfo prop = GetContainerProperty (type, containerPropNames);
-                       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
+                       return builder.BindingContainerType;
                }
                
                CodeMemberMethod CreateDBMethod (ControlBuilder builder, string name, Type container, Type target)
@@ -1376,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;
+                       CodeMemberMethod method = db.Method;
                        AddEventAssign (method, builder, "DataBinding", typeof (EventHandler), dbMethodName);
                        method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
 
                        // Add the DataBind handler
                        method = CreateDBMethod (builder, dbMethodName, GetContainerType (builder), typeof (DataBoundLiteralControl));
+                       builder.DataBindingMethod = method;
 
                        CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
                        CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
@@ -1397,7 +1352,7 @@ namespace System.Web.Compilation
                        method.Statements.Add (AddLinePragma (invoke, builder));
                        
                        mainClass.Members.Add (method);
-
+                       
                        AddChildCall (builder, db);
                }
 
@@ -1417,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;
                                        }
                                        
@@ -1436,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);
                        }
 
@@ -1460,96 +1411,83 @@ 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 (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);
+                                               AddContentTemplateInvocation (cb, builder.Method, cb.Method.Name);
                                                continue;
                                        }
-#endif
-                                       // Ignore TemplateBuilders - they are processed in InitMethod
-                                       if (b is TemplateBuilder)
-                                               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 (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 NET_2_0
                        if (builder is RootBuilder)
                                if (!String.IsNullOrEmpty (parser.MetaResourceKey))
                                        AssignPropertiesFromResources (builder, parser.BaseType, parser.MetaResourceKey);
                        
-                       if ((!isTemplate || builder is RootBuilder) && builder.attribs != null && builder.attribs ["meta:resourcekey"] != null)
+                       if ((!isTemplate || builder is RootBuilder) && !String.IsNullOrEmpty (builder.GetAttribute ("meta:resourcekey")))
                                CreateAssignStatementFromAttribute (builder, "meta:resourcekey");
-#endif
 
                        if (!childrenAsProperties && typeof (Control).IsAssignableFrom (builder.ControlType))
-                               builder.method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
+                               builder.Method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
+
+                       builder.ProcessGeneratedCode (CompileUnit, BaseType, DerivedType, builder.Method, builder.DataBindingMethod);
                }
 
-#if NET_2_0
                protected override void AddStatementsToConstructor (CodeConstructor ctor)
                {
                        if (masterPageContentPlaceHolders == null || masterPageContentPlaceHolders.Count == 0)
@@ -1567,11 +1505,10 @@ namespace System.Web.Compilation
                        CodeMethodInvokeExpression mcall;
                        foreach (string id in masterPageContentPlaceHolders) {
                                mcall = new CodeMethodInvokeExpression (ilistRef, "Add");
-                               mcall.Parameters.Add (new CodePrimitiveExpression (id));
+                               mcall.Parameters.Add (new CodePrimitiveExpression (id.ToLowerInvariant ()));
                                statements.Add (mcall);
                        }
                }
-#endif
                
                protected internal override void CreateMethods ()
                {
@@ -1582,14 +1519,30 @@ namespace System.Web.Compilation
                        CreateFrameworkInitializeMethod ();
                }
 
-#if NET_2_0
+               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);
                }
-#endif
                
                void CallSetStringResourcePointer (CodeMemberMethod method)
                {
@@ -1608,9 +1561,7 @@ namespace System.Web.Compilation
                        method.Name = "FrameworkInitialize";
                        method.Attributes = MemberAttributes.Family | MemberAttributes.Override;
                        PrependStatementsToFrameworkInitialize (method);
-#if NET_2_0
                        CallBaseFrameworkInitialize (method);
-#endif
                        CallSetStringResourcePointer (method);
                        AppendStatementsToFrameworkInitialize (method);
                        mainClass.Members.Add (method);
@@ -1688,15 +1639,12 @@ 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);
                }
 
-#if NET_2_0
                void CreateContentPlaceHolderTemplateProperty (string backingField, string name)
                {
                        CodeMemberProperty prop = new CodeMemberProperty ();
@@ -1725,7 +1673,6 @@ namespace System.Web.Compilation
 
                        mainClass.Members.Add (prop);
                }
-#endif
                
                void CreateAutoHandlers ()
                {
@@ -1742,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
@@ -1766,66 +1710,36 @@ 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 = HttpApplication.LoadType (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)
@@ -1864,25 +1778,23 @@ 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);
                        } else if (type == typeof (bool)) {
                                if (preConverted)
@@ -1894,10 +1806,8 @@ 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.");
@@ -1911,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 [])) {
@@ -1996,10 +1906,34 @@ 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;
+
+                                       converter = TypeDescriptor.GetConverter (memberType);
+                               }
+                       }
+                       
                        if (preConverted || (converter != null && SafeCanConvertFrom (typeof (string), converter))) {
                                object value = preConverted ? convertedFromAttr : converter.ConvertFromInvariantString (str);
 
@@ -2009,7 +1943,11 @@ namespace System.Web.Compilation
                                                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);
@@ -2112,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,
@@ -2123,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;