diff --git a/src/Umbraco.Tests/Macros/MacroTests.cs b/src/Umbraco.Tests/Macros/MacroTests.cs index 76da493251..c4f8977b35 100644 --- a/src/Umbraco.Tests/Macros/MacroTests.cs +++ b/src/Umbraco.Tests/Macros/MacroTests.cs @@ -1,6 +1,8 @@ using System; using System.IO; using System.Web.Caching; +using System.Web.UI; +using System.Web.UI.WebControls; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Profiling; @@ -34,6 +36,40 @@ namespace Umbraco.Tests.Macros ApplicationContext.Current = null; } + [TestCase("123", "IntProp", typeof(int))] + [TestCase("Hello", "StringProp", typeof(string))] + [TestCase("123456789.01", "DoubleProp", typeof(double))] + [TestCase("1234567", "FloatProp", typeof(float))] + [TestCase("1", "BoolProp", typeof(bool))] + [TestCase("true", "BoolProp", typeof(bool))] + [TestCase("0", "BoolProp", typeof(bool))] + [TestCase("false", "BoolProp", typeof(bool))] + [TestCase("2001-05-10", "DateProp", typeof(DateTime))] + [TestCase("123px", "UnitProp", typeof(Unit))] + [TestCase("456pt", "UnitProp", typeof(Unit))] + [TestCase("CEC063D3-D73E-4B7D-93ED-7F69CA9BF2D0", "GuidProp", typeof(Guid))] + [TestCase("CEC063D3D73E4B7D93ED7F69CA9BF2D0", "GuidProp", typeof(Guid))] + [TestCase("", "NullDateProp", typeof(DateTime?))] + [TestCase("2001-05-10", "NullDateProp", typeof(DateTime?))] + [TestCase("", "NullUnitProp", typeof(Unit?))] + [TestCase("456pt", "NullUnitProp", typeof(Unit?))] + public void SetUserControlProperty(string val, string macroPropName, Type convertTo) + { + var ctrl = new UserControlTest(); + var macroModel = new MacroModel("test", "test", "", "~/usercontrols/menu.ascx", "", "", 0, false, false); + macroModel.Properties.Add(new MacroPropertyModel(macroPropName, val)); + + macro.UpdateControlProperties(ctrl, macroModel); + + var ctrlType = ctrl.GetType(); + var prop = ctrlType.GetProperty(macroPropName); + var converted = val.TryConvertTo(convertTo); + + Assert.IsTrue(converted.Success); + Assert.NotNull(prop); + Assert.AreEqual(converted.Result, prop.GetValue(ctrl, null)); + } + [TestCase("text.xslt", "", "", "", "XSLT")] [TestCase("", "razor-script.cshtml", "", "", "Script")] [TestCase("", "~/Views/MacroPartials/test.cshtml", "", "", "PartialView")] @@ -116,5 +152,18 @@ namespace Umbraco.Tests.Macros //var asdf = macro.GetCacheIdentifier() } + private class UserControlTest : UserControl + { + public int IntProp { get; set; } + public string StringProp { get; set; } + public double DoubleProp { get; set; } + public float FloatProp { get; set; } + public bool BoolProp { get; set; } + public DateTime DateProp { get; set; } + public Unit UnitProp { get; set; } + public Guid GuidProp { get; set; } + public DateTime? NullDateProp { get; set; } + public Unit? NullUnitProp { get; set; } + } } } diff --git a/src/Umbraco.Tests/ObjectExtensionsTests.cs b/src/Umbraco.Tests/ObjectExtensionsTests.cs index f3aab4772c..a130137569 100644 --- a/src/Umbraco.Tests/ObjectExtensionsTests.cs +++ b/src/Umbraco.Tests/ObjectExtensionsTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; +using System.Web.UI.WebControls; using NUnit.Framework; using Umbraco.Core; using Umbraco.Tests.PartialTrust; @@ -19,6 +20,20 @@ namespace Umbraco.Tests TestHelper.SetupLog4NetForTests(); } + [Test] + public void CanParseStringToUnit() + { + var stringUnit = "1234px"; + object objUnit = "1234px"; + var result = stringUnit.TryConvertTo(); + var result2 = objUnit.TryConvertTo(); + var unit = new Unit("1234px"); + Assert.IsTrue(result.Success); + Assert.IsTrue(result2.Success); + Assert.AreEqual(unit, result.Result); + Assert.AreEqual(unit, result2.Result); + } + [Test] public void Can_Convert_List_To_Enumerable() { diff --git a/src/Umbraco.Web/umbraco.presentation/macro.cs b/src/Umbraco.Web/umbraco.presentation/macro.cs index 3531cb81d1..02b9f79466 100644 --- a/src/Umbraco.Web/umbraco.presentation/macro.cs +++ b/src/Umbraco.Web/umbraco.presentation/macro.cs @@ -1595,156 +1595,55 @@ namespace umbraco return new LiteralControl(string.Format("Unable to create control {0} from assembly {1}", controlName, asm.FullName)); - AddCurrentNodeToControl(control, type); + AddCurrentNodeToControl(control); // Properties - UpdateControlProperties(type, control, model); + UpdateControlProperties(control, model); return control; } - private static void UpdateControlProperties(Type type, Control control, MacroModel model) + //TODO: SD : We *really* need to get macro's rendering properly with a real macro engine + // and move logic like this (after it is completely overhauled) to a UserControlMacroEngine. + internal static void UpdateControlProperties(Control control, MacroModel model) { - foreach (MacroPropertyModel mp in model.Properties) + var type = control.GetType(); + + foreach (var mp in model.Properties) { - PropertyInfo prop = type.GetProperty(mp.Key); + var prop = type.GetProperty(mp.Key); if (prop == null) { TraceWarn("macro", string.Format("control property '{0}' doesn't exist or aren't accessible (public)", mp.Key)); continue; } - object propValue = mp.Value; - bool propValueSet = false; - // Special case for types of webControls.unit - if (prop.PropertyType == typeof(Unit)) - { - propValue = Unit.Parse(propValue.ToString()); - propValueSet = true; - } - else + var tryConvert = mp.Value.TryConvertTo(prop.PropertyType); + if (tryConvert.Success) { try { - if (mp.CLRType == null) - continue; - var st = (TypeCode)Enum.Parse(typeof(TypeCode), mp.CLRType, true); - - // Special case for booleans - if (prop.PropertyType == typeof(bool)) - { - bool parseResult; - if ( - Boolean.TryParse( - propValue.ToString().Replace("1", "true").Replace("0", "false"), - out parseResult)) - propValue = parseResult; - else - propValue = false; - propValueSet = true; - - } - else - { - string sPropValue = string.Format("{0}", propValue); - Type propType = prop.PropertyType; - if (!string.IsNullOrWhiteSpace(sPropValue)) - { - try - { - propValue = Convert.ChangeType(propValue, st); - propValueSet = true; - } - catch (FormatException) - { - propValue = Convert.ChangeType(propValue, propType); - propValueSet = true; - } - } - /* NH 06-01-2012: Remove the lines below as they would only get activated if the values are empty - else - { - if (propType != null) - { - if (propType.IsValueType) - { - propValue = Activator.CreateInstance(propType); - } - else - { - propValue = null; - } - } - }*/ - } - - if (GlobalSettings.DebugMode) - TraceInfo("macro.loadControlProperties", - string.Format("Property added '{0}' with value '{1}'", - mp.Key, - propValue)); + prop.SetValue(control, tryConvert.Result, null); } - catch (Exception PropException) + catch (Exception ex) { - LogHelper.WarnWithException(string.Format( - "Error adding property '{0}' with value '{1}'", - mp.Key, propValue), PropException); + LogHelper.WarnWithException(string.Format("Error adding property '{0}' with value '{1}'", mp.Key, mp.Value), ex); + if (GlobalSettings.DebugMode) + { + TraceWarn("macro.loadControlProperties", string.Format("Error adding property '{0}' with value '{1}'", mp.Key, mp.Value), ex); + } + } - if (GlobalSettings.DebugMode) - { - TraceWarn("macro.loadControlProperties", - string.Format( - "Error adding property '{0}' with value '{1}'", - mp.Key, propValue), PropException); - } + if (GlobalSettings.DebugMode) + { + TraceInfo("macro.UpdateControlProperties", string.Format("Property added '{0}' with value '{1}'", mp.Key, mp.Value)); } } - - // NH 06-01-2012: Only set value if it has content - if (propValueSet) + else { - //GE 06-05-2012: Handle Nullable properties - if (prop.PropertyType.IsGenericType && prop.PropertyType.Name == "Nullable`1") + LogHelper.Warn(string.Format("Error adding property '{0}' with value '{1}'", mp.Key, mp.Value)); + if (GlobalSettings.DebugMode) { - Type underlyingType = Nullable.GetUnderlyingType(prop.PropertyType); - if (underlyingType != null) - { - object safeValue = null; - if (propValue != null) - { - if (!(underlyingType == typeof(Guid))) - { - prop.SetValue(control, Convert.ChangeType(propValue, underlyingType), null); - } - else - { - Guid g = Guid.Empty; - if (Guid.TryParse(string.Format("{0}", propValue), out g)) - { - prop.SetValue(control, g, null); - } - } - } - else - { - prop.SetValue(control, safeValue, null); - } - } - } - else - { - //GE 06-05-2012: Handle Guid properties as Convert.ChangeType throws on string->Guid - if (!(prop.PropertyType == typeof(Guid))) - { - prop.SetValue(control, Convert.ChangeType(propValue, prop.PropertyType), null); - } - else - { - Guid g = Guid.Empty; - if (Guid.TryParse(string.Format("{0}", propValue), out g)) - { - prop.SetValue(control, g, null); - } - } + TraceWarn("macro.loadControlProperties", string.Format("Error adding property '{0}' with value '{1}'", mp.Key, mp.Value)); } } } @@ -1784,10 +1683,8 @@ namespace umbraco TraceInfo(LoadUserControlKey, string.Format("Usercontrol added with id '{0}'", oControl.ID)); - Type type = oControl.GetType(); - - AddCurrentNodeToControl(oControl, type); - UpdateControlProperties(type, oControl, model); + AddCurrentNodeToControl(oControl); + UpdateControlProperties(oControl, model); return oControl; } catch (Exception e) @@ -1797,8 +1694,10 @@ namespace umbraco } } - private static void AddCurrentNodeToControl(Control control, Type type) + private static void AddCurrentNodeToControl(Control control) { + var type = control.GetType(); + PropertyInfo currentNodeProperty = type.GetProperty("CurrentNode"); if (currentNodeProperty != null && currentNodeProperty.CanWrite && currentNodeProperty.PropertyType.IsAssignableFrom(typeof(Node))) diff --git a/src/umbraco.cms/businesslogic/macro/MacroPropertyModel.cs b/src/umbraco.cms/businesslogic/macro/MacroPropertyModel.cs index a6c0e5a000..497b9e6552 100644 --- a/src/umbraco.cms/businesslogic/macro/MacroPropertyModel.cs +++ b/src/umbraco.cms/businesslogic/macro/MacroPropertyModel.cs @@ -8,7 +8,10 @@ namespace umbraco.cms.businesslogic.macro public string Key { get; set; } public string Value { get; set; } public string Type { get; set; } - public string CLRType { get; set; } + + [Obsolete("This is no longer used an will be removed in future versions")] + public string CLRType { get; set; } + public MacroPropertyModel() {