X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Web%2FSystem.Web.Compilation%2FTemplateControlCompiler.cs;h=201801b31e7fbf4062c17febac0481f344da35c5;hb=96b54e28f09a43a3563572024f151ccb7da384bd;hp=703be5eba3c6c78030f83fcf032b6bc47b3c46f8;hpb=217ddc29c40bc8b11f8fbd4800e61db7f4f22bbf;p=mono.git diff --git a/mcs/class/System.Web/System.Web.Compilation/TemplateControlCompiler.cs b/mcs/class/System.Web/System.Web.Compilation/TemplateControlCompiler.cs index 703be5eba3c..201801b31e7 100644 --- a/mcs/class/System.Web/System.Web.Compilation/TemplateControlCompiler.cs +++ b/mcs/class/System.Web/System.Web.Compilation/TemplateControlCompiler.cs @@ -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,12 +64,22 @@ namespace System.Web.Compilation internal static CodeVariableReferenceExpression ctrlVar = new CodeVariableReferenceExpression ("__ctrl"); -#if NET_2_0 + List 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*\).*", RegexOptions.Compiled | RegexOptions.IgnoreCase); -#endif - static Regex evalRegexInValue = new Regex (@"Eval\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 MasterPageContentPlaceHolders { + get { + if (masterPageContentPlaceHolders == null) + masterPageContentPlaceHolders = new List (); + return masterPageContentPlaceHolders; + } + } + public TemplateControlCompiler (TemplateControlParser parser) : base (parser) { @@ -87,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)); } @@ -130,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; @@ -146,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; - - string tailname = ((builder is RootBuilder) ? "Tree" : ("_" + builder.ID)); + currentLocation = builder.Location; + bool inBuildControlTree = builder is RootBuilder; + string tailname = (inBuildControlTree ? "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; @@ -177,16 +176,14 @@ namespace System.Web.Compilation /* in the case this is the __BuildControlTree * method, allow subclasses to insert control * specific code. */ - if (builder is RootBuilder) { -#if NET_2_0 + if (inBuildControlTree) { SetCustomAttributes (method); -#endif - AddStatementsToInitMethod (method); + AddStatementsToInitMethodTop (builder, 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 (); @@ -205,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 @@ -258,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; @@ -287,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)) @@ -300,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); @@ -308,31 +302,31 @@ 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)) { - CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (thisRef, "ContentPlaceHolders"); - CodeMethodInvokeExpression addPlaceholder = new CodeMethodInvokeExpression (prop, "Add"); - addPlaceholder.Parameters.Add (ctrlVar); - method.Statements.Add (addPlaceholder); - + List 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"])); // } @@ -343,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; @@ -378,10 +372,12 @@ 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 } + + if (inBuildControlTree) + AddStatementsToInitMethodBottom (builder, method); mainClass.Members.Add (method); } @@ -392,18 +388,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 (); @@ -428,12 +421,15 @@ namespace System.Web.Compilation foreach (UnknownAttributeDescriptor uad in attrs) SetCustomAttribute (method, uad); } -#endif - protected virtual void AddStatementsToInitMethod (CodeMemberMethod method) + protected virtual void AddStatementsToInitMethodTop (ControlBuilder builder, CodeMemberMethod method) { } + protected virtual void AddStatementsToInitMethodBottom (ControlBuilder builder, CodeMemberMethod method) + { + } + void AddLiteralSubObject (ControlBuilder builder, string str) { if (!builder.HasAspCode) { @@ -447,7 +443,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); } } @@ -467,31 +463,50 @@ namespace System.Web.Compilation CodeExpression CreateEvalInvokeExpression (Regex regex, string value, bool isBind) { Match match = regex.Match (value); - if (!match.Success) + if (!match.Success) { + if (isBind) + throw new HttpParseException ("Bind invocation wasn't formatted properly."); return null; + } + string sanitizedSnippet; if (isBind) - return new CodeSnippetExpression ("Eval" + value.Substring (4)); + sanitizedSnippet = SanitizeBindCall (match); + else + sanitizedSnippet = value; - return new CodeSnippetExpression (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, 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); @@ -499,7 +514,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 @@ -516,16 +530,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); @@ -534,66 +545,26 @@ 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)); } - bool IsDirective (string value, char directiveChar) - { - if (value == null || value == String.Empty) - return false; - - value = value.Trim (); - if (!StrUtils.StartsWith (value, "<%") || !StrUtils.EndsWith (value, "%>")) - return false; - - 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) - { - return IsDirective (value, '$'); - } - void RegisterBindingInfo (ControlBuilder builder, string propName, ref string value) { string str = TrimDB (value, false); @@ -609,29 +580,28 @@ 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) + internal static MemberInfo GetFieldOrProperty (Type type, string name) { MemberInfo member = null; try { @@ -664,12 +634,8 @@ 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 + bool isDataBound = BaseParser.IsDataBound (attValue); + bool isExpression = !isDataBound && BaseParser.IsExpression (attValue); Type type; if (isPropertyInfo) { type = ((PropertyInfo) member).PropertyType; @@ -678,11 +644,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; @@ -693,7 +657,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; @@ -725,10 +689,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); @@ -736,8 +700,7 @@ namespace System.Web.Compilation return true; } -#if NET_2_0 - CodeExpression CompileExpression (MemberInfo member, Type type, string value, bool useSetAttribute) + internal CodeExpression CompileExpression (MemberInfo member, Type type, string value, bool useSetAttribute) { // First let's find the correct expression builder value = value.Substring (3, value.Length - 5).Trim (); @@ -747,11 +710,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; @@ -799,11 +758,95 @@ namespace System.Web.Compilation CodeAssignStatement assign = new CodeAssignStatement (); assign.Left = new CodePropertyReferenceExpression (ctrlVar, name); - assign.Right = expr; + + TypeCode typeCode = Type.GetTypeCode (type); + if (typeCode != TypeCode.Empty && typeCode != TypeCode.Object && typeCode != TypeCode.DBNull) + assign.Right = CreateConvertToCall (typeCode, expr); + else + assign.Right = new CodeCastExpression (type, expr); - builder.method.Statements.Add (AddLinePragma (assign, builder)); + builder.Method.Statements.Add (AddLinePragma (assign, builder)); } + CodeMethodInvokeExpression CreateConvertToCall (TypeCode typeCode, CodeExpression expr) + { + var ret = new CodeMethodInvokeExpression (); + string methodName; + + switch (typeCode) { + case TypeCode.Boolean: + methodName = "ToBoolean"; + break; + + case TypeCode.Char: + methodName = "ToChar"; + break; + + case TypeCode.SByte: + methodName = "ToSByte"; + break; + + case TypeCode.Byte: + methodName = "ToByte"; + break; + + case TypeCode.Int16: + methodName = "ToInt16"; + break; + + case TypeCode.UInt16: + methodName = "ToUInt16"; + break; + + case TypeCode.Int32: + methodName = "ToInt32"; + break; + + case TypeCode.UInt32: + methodName = "ToUInt32"; + break; + + case TypeCode.Int64: + methodName = "ToInt64"; + break; + + case TypeCode.UInt64: + methodName = "ToUInt64"; + break; + + case TypeCode.Single: + methodName = "ToSingle"; + break; + + case TypeCode.Double: + methodName = "ToDouble"; + break; + + case TypeCode.Decimal: + methodName = "ToDecimal"; + break; + + case TypeCode.DateTime: + methodName = "ToDateTime"; + break; + + case TypeCode.String: + methodName = "ToString"; + break; + + default: + throw new InvalidOperationException (String.Format ("Unsupported TypeCode '{0}'", typeCode)); + } + + var typeRef = new CodeTypeReferenceExpression (typeof (Convert)); + typeRef.Type.Options = CodeTypeReferenceOptions.GlobalReference; + + ret.Method = new CodeMethodReferenceExpression (typeRef, methodName); + ret.Parameters.Add (expr); + + return ret; + } + BoundPropertyEntry CreateBoundPropertyEntry (PropertyInfo pi, string prefix, string expr, bool useSetAttribute) { BoundPropertyEntry ret = new BoundPropertyEntry (); @@ -819,6 +862,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) { @@ -828,9 +901,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; @@ -856,7 +936,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) @@ -887,7 +967,6 @@ namespace System.Web.Compilation AssignPropertiesFromResources (builder, controlType, attvalue); } -#endif void AddEventAssign (CodeMemberMethod method, ControlBuilder builder, string name, Type type, string value) { @@ -906,15 +985,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, @@ -926,12 +1005,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; @@ -945,24 +1022,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; - bool isDatabound = IsDataBound (attvalue); -#if NET_2_0 - bool isExpression = !isDatabound && IsExpression (attvalue); -#endif + CodeMemberMethod method = builder.Method; + bool isDatabound = BaseParser.IsDataBound (attvalue); + bool isExpression = !isDatabound && BaseParser.IsExpression (attvalue); 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); @@ -979,12 +1052,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); @@ -995,7 +1066,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; @@ -1004,16 +1075,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); } } @@ -1025,10 +1094,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; @@ -1055,12 +1126,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) @@ -1068,7 +1139,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; @@ -1095,28 +1166,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) @@ -1134,10 +1205,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); @@ -1153,7 +1223,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) @@ -1230,7 +1300,6 @@ namespace System.Web.Compilation method.Statements.Add (AddLinePragma (invoke, cbuilder)); } -#endif void AddCodeRender (ControlBuilder parent, CodeRenderBuilder cr) { @@ -1239,7 +1308,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; } @@ -1248,49 +1317,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) @@ -1340,12 +1385,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 (); @@ -1361,7 +1407,7 @@ namespace System.Web.Compilation method.Statements.Add (AddLinePragma (invoke, builder)); mainClass.Members.Add (method); - + AddChildCall (builder, db); } @@ -1381,16 +1427,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; } @@ -1400,12 +1444,10 @@ namespace System.Web.Compilation } if (!singleInstance) -#endif builder.ID = builder.GetNextID (null); -#if NET_2_0 else doCheck = true; -#endif + CreateField (builder, doCheck); } @@ -1424,93 +1466,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 (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); + } + + 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 () @@ -1522,14 +1574,30 @@ namespace System.Web.Compilation CreateFrameworkInitializeMethod (); } -#if NET_2_0 + protected override void InitializeType () + { + List 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) { @@ -1548,9 +1616,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); @@ -1628,14 +1694,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 @@ -1651,11 +1744,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 @@ -1675,66 +1765,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) @@ -1773,25 +1833,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) @@ -1803,10 +1861,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."); @@ -1820,7 +1876,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 [])) { @@ -1905,10 +1961,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); @@ -1918,7 +1998,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); @@ -2021,6 +2105,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, @@ -2032,6 +2120,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;