diff --git a/src/Umbraco.Core/Dynamics/CaseInsensitiveDynamicObject.cs b/src/Umbraco.Core/Dynamics/CaseInsensitiveDynamicObject.cs deleted file mode 100644 index 43d7adc647..0000000000 --- a/src/Umbraco.Core/Dynamics/CaseInsensitiveDynamicObject.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Dynamic; -using System.Linq; -using System.Reflection; - -namespace Umbraco.Core.Dynamics -{ - /// - /// This will check enable dynamic access to properties and methods in a case insensitive manner - /// - /// - /// - /// This works by using reflection on the type - the reflection lookup is lazy so it will not execute unless a dynamic method needs to be accessed - /// - public abstract class CaseInsensitiveDynamicObject : DynamicObject - where T: class - { - /// - /// Used for dynamic access for case insensitive property access - /// ` - private static readonly Lazy>> CaseInsensitivePropertyAccess = new Lazy>>(() => - { - var props = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public) - .DistinctBy(x => x.Name); - return props.Select(propInfo => - { - var name = propInfo.Name.ToLowerInvariant(); - Func getVal = propInfo.GetValue; - return new KeyValuePair>(name, getVal); - - }).ToDictionary(x => x.Key, x => x.Value); - }); - - /// - /// Used for dynamic access for case insensitive property access - /// - private static readonly Lazy>>> CaseInsensitiveMethodAccess - = new Lazy>>>(() => - { - var props = typeof(T).GetMethods(BindingFlags.Instance | BindingFlags.Public) - .Where(x => x.IsSpecialName == false && x.IsVirtual == false) - .DistinctBy(x => x.Name); - return props.Select(methodInfo => - { - var name = methodInfo.Name.ToLowerInvariant(); - Func getVal = methodInfo.Invoke; - var val = new Tuple>(methodInfo.GetParameters(), getVal); - return new KeyValuePair>>(name, val); - - }).ToDictionary(x => x.Key, x => x.Value); - }); - - public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) - { - var name = binder.Name.ToLowerInvariant(); - if (CaseInsensitiveMethodAccess.Value.ContainsKey(name) == false) - return base.TryInvokeMember(binder, args, out result); - - var val = CaseInsensitiveMethodAccess.Value[name]; - var parameters = val.Item1; - var callback = val.Item2; - var fullArgs = new List(args); - if (args.Length <= parameters.Length) - { - //need to fill them up if they're optional - for (var i = args.Length; i < parameters.Length; i++) - { - if (parameters[i].IsOptional) - { - fullArgs.Add(parameters[i].DefaultValue); - } - } - if (fullArgs.Count == parameters.Length) - { - result = callback((T)(object)this, fullArgs.ToArray()); - return true; - } - } - return base.TryInvokeMember(binder, args, out result); - } - - public override bool TryGetMember(GetMemberBinder binder, out object result) - { - var name = binder.Name.ToLowerInvariant(); - if (CaseInsensitivePropertyAccess.Value.ContainsKey(name) == false) - return base.TryGetMember(binder, out result); - - result = CaseInsensitivePropertyAccess.Value[name]((T)(object)this); - return true; - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Dynamics/ClassFactory.cs b/src/Umbraco.Core/Dynamics/ClassFactory.cs deleted file mode 100644 index 87f4315e76..0000000000 --- a/src/Umbraco.Core/Dynamics/ClassFactory.cs +++ /dev/null @@ -1,182 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Reflection.Emit; -using System.Threading; - -namespace Umbraco.Core.Dynamics -{ - internal class ClassFactory - { - public static readonly ClassFactory Instance = new ClassFactory(); - - static ClassFactory() { } // Trigger lazy initialization of static fields - - ModuleBuilder module; - Dictionary classes; - int classCount; - ReaderWriterLock rwLock; - - protected ClassFactory() - { - AssemblyName name = new AssemblyName("DynamicClasses"); - AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run); -#if ENABLE_LINQ_PARTIAL_TRUST - new ReflectionPermission(PermissionState.Unrestricted).Assert(); -#endif - try - { - module = assembly.DefineDynamicModule("Module"); - } - finally - { -#if ENABLE_LINQ_PARTIAL_TRUST - PermissionSet.RevertAssert(); -#endif - } - classes = new Dictionary(); - rwLock = new ReaderWriterLock(); - } - - public Type GetDynamicClass(IEnumerable properties) - { - rwLock.AcquireReaderLock(Timeout.Infinite); - try - { - Signature signature = new Signature(properties); - Type type; - if (!classes.TryGetValue(signature, out type)) - { - type = CreateDynamicClass(signature.Properties); - classes.Add(signature, type); - } - return type; - } - finally - { - rwLock.ReleaseReaderLock(); - } - } - - Type CreateDynamicClass(DynamicProperty[] properties) - { - LockCookie cookie = rwLock.UpgradeToWriterLock(Timeout.Infinite); - try - { - string typeName = "DynamicClass" + (classCount + 1); -#if ENABLE_LINQ_PARTIAL_TRUST - new ReflectionPermission(PermissionState.Unrestricted).Assert(); -#endif - try - { - TypeBuilder tb = this.module.DefineType(typeName, TypeAttributes.Class | - TypeAttributes.Public, typeof(DynamicClass)); - FieldInfo[] fields = GenerateProperties(tb, properties); - GenerateEquals(tb, fields); - GenerateGetHashCode(tb, fields); - Type result = tb.CreateType(); - classCount++; - return result; - } - finally - { -#if ENABLE_LINQ_PARTIAL_TRUST - PermissionSet.RevertAssert(); -#endif - } - } - finally - { - rwLock.DowngradeFromWriterLock(ref cookie); - } - } - - FieldInfo[] GenerateProperties(TypeBuilder tb, DynamicProperty[] properties) - { - FieldInfo[] fields = new FieldBuilder[properties.Length]; - for (int i = 0; i < properties.Length; i++) - { - DynamicProperty dp = properties[i]; - FieldBuilder fb = tb.DefineField("_" + dp.Name, dp.Type, FieldAttributes.Private); - PropertyBuilder pb = tb.DefineProperty(dp.Name, PropertyAttributes.HasDefault, dp.Type, null); - MethodBuilder mbGet = tb.DefineMethod("get_" + dp.Name, - MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, - dp.Type, Type.EmptyTypes); - ILGenerator genGet = mbGet.GetILGenerator(); - genGet.Emit(OpCodes.Ldarg_0); - genGet.Emit(OpCodes.Ldfld, fb); - genGet.Emit(OpCodes.Ret); - MethodBuilder mbSet = tb.DefineMethod("set_" + dp.Name, - MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, - null, new Type[] { dp.Type }); - ILGenerator genSet = mbSet.GetILGenerator(); - genSet.Emit(OpCodes.Ldarg_0); - genSet.Emit(OpCodes.Ldarg_1); - genSet.Emit(OpCodes.Stfld, fb); - genSet.Emit(OpCodes.Ret); - pb.SetGetMethod(mbGet); - pb.SetSetMethod(mbSet); - fields[i] = fb; - } - return fields; - } - - void GenerateEquals(TypeBuilder tb, FieldInfo[] fields) - { - MethodBuilder mb = tb.DefineMethod("Equals", - MethodAttributes.Public | MethodAttributes.ReuseSlot | - MethodAttributes.Virtual | MethodAttributes.HideBySig, - typeof(bool), new Type[] { typeof(object) }); - ILGenerator gen = mb.GetILGenerator(); - LocalBuilder other = gen.DeclareLocal(tb); - Label next = gen.DefineLabel(); - gen.Emit(OpCodes.Ldarg_1); - gen.Emit(OpCodes.Isinst, tb); - gen.Emit(OpCodes.Stloc, other); - gen.Emit(OpCodes.Ldloc, other); - gen.Emit(OpCodes.Brtrue_S, next); - gen.Emit(OpCodes.Ldc_I4_0); - gen.Emit(OpCodes.Ret); - gen.MarkLabel(next); - foreach (FieldInfo field in fields) - { - Type ft = field.FieldType; - Type ct = typeof(EqualityComparer<>).MakeGenericType(ft); - next = gen.DefineLabel(); - gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null); - gen.Emit(OpCodes.Ldarg_0); - gen.Emit(OpCodes.Ldfld, field); - gen.Emit(OpCodes.Ldloc, other); - gen.Emit(OpCodes.Ldfld, field); - gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("Equals", new Type[] { ft, ft }), null); - gen.Emit(OpCodes.Brtrue_S, next); - gen.Emit(OpCodes.Ldc_I4_0); - gen.Emit(OpCodes.Ret); - gen.MarkLabel(next); - } - gen.Emit(OpCodes.Ldc_I4_1); - gen.Emit(OpCodes.Ret); - } - - void GenerateGetHashCode(TypeBuilder tb, FieldInfo[] fields) - { - MethodBuilder mb = tb.DefineMethod("GetHashCode", - MethodAttributes.Public | MethodAttributes.ReuseSlot | - MethodAttributes.Virtual | MethodAttributes.HideBySig, - typeof(int), Type.EmptyTypes); - ILGenerator gen = mb.GetILGenerator(); - gen.Emit(OpCodes.Ldc_I4_0); - foreach (FieldInfo field in fields) - { - Type ft = field.FieldType; - Type ct = typeof(EqualityComparer<>).MakeGenericType(ft); - gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null); - gen.Emit(OpCodes.Ldarg_0); - gen.Emit(OpCodes.Ldfld, field); - gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("GetHashCode", new Type[] { ft }), null); - gen.Emit(OpCodes.Xor); - } - gen.Emit(OpCodes.Ret); - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Dynamics/DynamicClass.cs b/src/Umbraco.Core/Dynamics/DynamicClass.cs deleted file mode 100644 index 13914cad42..0000000000 --- a/src/Umbraco.Core/Dynamics/DynamicClass.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Reflection; -using System.Text; - -namespace Umbraco.Core.Dynamics -{ - public abstract class DynamicClass - { - public override string ToString() - { - PropertyInfo[] props = this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); - StringBuilder sb = new StringBuilder(); - sb.Append("{"); - for (int i = 0; i < props.Length; i++) - { - if (i > 0) sb.Append(", "); - sb.Append(props[i].Name); - sb.Append("="); - sb.Append(props[i].GetValue(this, null)); - } - sb.Append("}"); - return sb.ToString(); - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Dynamics/DynamicDictionary.cs b/src/Umbraco.Core/Dynamics/DynamicDictionary.cs deleted file mode 100644 index f3ab75413f..0000000000 --- a/src/Umbraco.Core/Dynamics/DynamicDictionary.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Collections.Generic; -using System.Dynamic; - -namespace Umbraco.Core.Dynamics -{ - public class DynamicDictionary : DynamicObject - { - internal readonly Dictionary SourceItems; - - public DynamicDictionary(Dictionary sourceItems) - { - SourceItems = sourceItems; - } - public override bool TrySetMember(SetMemberBinder binder, object value) - { - if (SourceItems.ContainsKey(binder.Name)) - { - SourceItems[binder.Name.ToLower()] = value; - } - else - { - SourceItems.Add(binder.Name.ToLower(), value); - } - return true; - } - public override bool TryGetMember(GetMemberBinder binder, out object result) - { - if (SourceItems != null) - { - if (SourceItems.TryGetValue(binder.Name.ToLower(), out result)) - { - return true; - } - } - result = null; - return true; - } - } -} diff --git a/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs b/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs deleted file mode 100644 index 59f149ef09..0000000000 --- a/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs +++ /dev/null @@ -1,194 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Dynamic; -using System.Linq; -using System.Reflection; -using System.Text; -using Umbraco.Core.Cache; -using Umbraco.Core.Logging; - -namespace Umbraco.Core.Dynamics -{ - /// - /// A helper class to try invoke members, find properties, etc... - /// - internal class DynamicInstanceHelper - { - - internal class TryInvokeMemberResult - { - public object ObjectResult { get; private set; } - public TryInvokeMemberSuccessReason Reason { get; private set; } - - public TryInvokeMemberResult(object result, TryInvokeMemberSuccessReason reason) - { - ObjectResult = result; - Reason = reason; - } - } - - internal enum TryInvokeMemberSuccessReason - { - FoundProperty, - FoundMethod, - FoundExtensionMethod - } - - /// - /// Attempts to invoke a member based on the dynamic instance - /// - /// - /// - /// The object instance to invoke the extension method for - /// - /// - /// - /// - /// First tries to find a property with the binder name, if that fails it will try to find a static or instance method - /// on the object that matches the binder name - /// - public static Attempt TryInvokeMember(IRuntimeCacheProvider runtimeCache, T thisObject, InvokeMemberBinder binder, object[] args) - { - return TryInvokeMember(runtimeCache, thisObject, binder, args, null); - } - - /// - /// Attempts to invoke a member based on the dynamic instance - /// - /// - /// - /// The object instance to invoke the extension method for - /// - /// - /// The types to scan for extension methods - /// - /// - /// First tries to find a property with the binder name, if that fails it will try to find a static or instance method - /// on the object that matches the binder name, if that fails it will then attempt to invoke an extension method - /// based on the binder name and the extension method types to scan. - /// - public static Attempt TryInvokeMember( - IRuntimeCacheProvider runtimeCache, - T thisObject, - InvokeMemberBinder binder, - object[] args, - IEnumerable findExtensionMethodsOnTypes) - { - //TODO: We MUST cache the result here, it is very expensive to keep finding extension methods! - object result; - try - { - //Property? - result = typeof(T).InvokeMember(binder.Name, - BindingFlags.Instance | - BindingFlags.Public | - BindingFlags.GetProperty, - null, - thisObject, - args); - return Attempt.Succeed(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundProperty)); - } - catch (MissingMethodException) - { - try - { - //Static or Instance Method? - result = typeof(T).InvokeMember(binder.Name, - BindingFlags.Instance | - BindingFlags.Public | - BindingFlags.Static | - BindingFlags.InvokeMethod, - null, - thisObject, - args); - return Attempt.Succeed(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundMethod)); - } - catch (MissingMethodException) - { - if (findExtensionMethodsOnTypes != null) - { - try - { - result = FindAndExecuteExtensionMethod(runtimeCache, thisObject, args, binder.Name, findExtensionMethodsOnTypes); - return Attempt.Succeed(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundExtensionMethod)); - } - catch (TargetInvocationException ext) - { - //don't log here, we return this exception because the caller may need to do something specific when - //this exception occurs. - var mresult = new TryInvokeMemberResult(null, TryInvokeMemberSuccessReason.FoundExtensionMethod); - return Attempt.Fail(mresult, ext); - } - catch (Exception ex) - { - var sb = new StringBuilder(); - sb.AppendFormat("An error occurred finding and executing extension method \"{0}\" ", binder.Name); - sb.AppendFormat("for type \"{0}\". ", typeof (T)); - sb.Append("Types searched for extension methods were "); - sb.Append(string.Join(", ", findExtensionMethodsOnTypes)); - sb.Append("."); - LogHelper.Error(sb.ToString(), ex); - var mresult = new TryInvokeMemberResult(null, TryInvokeMemberSuccessReason.FoundExtensionMethod); - return Attempt.Fail(mresult, ex); - } - } - return Attempt.Fail(); - } - } - catch (Exception ex) - { - LogHelper.Error("An unhandled exception occurred in method TryInvokeMember", ex); - return Attempt.Fail(ex); - } - } - - /// - /// Attempts to find an extension method that matches the name and arguments based on scanning the Type's passed in - /// to the findMethodsOnTypes parameter - /// - /// - /// The instance object to execute the extension method for - /// - /// - /// - /// - internal static object FindAndExecuteExtensionMethod( - IRuntimeCacheProvider runtimeCache, - T thisObject, - object[] args, - string name, - IEnumerable findMethodsOnTypes) - { - object result = null; - - //find known extension methods that match the first type in the list - MethodInfo toExecute = null; - foreach (var t in findMethodsOnTypes) - { - toExecute = ExtensionMethodFinder.FindExtensionMethod(runtimeCache, t, args, name, false); - if (toExecute != null) - break; - } - - if (toExecute != null) - { - var genericArgs = (new[] { (object)thisObject }).Concat(args); - - // else we'd get an exception w/ message "Late bound operations cannot - // be performed on types or methods for which ContainsGenericParameters is true." - // because MakeGenericMethod must be used to obtain an actual method that can run - if (toExecute.ContainsGenericParameters) - throw new InvalidOperationException("Method contains generic parameters, something's wrong."); - - result = toExecute.Invoke(null, genericArgs.ToArray()); - } - else - { - throw new MissingMethodException(typeof(T).FullName, name); - } - return result; - } - - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Dynamics/DynamicNull.cs b/src/Umbraco.Core/Dynamics/DynamicNull.cs deleted file mode 100644 index 593808e867..0000000000 --- a/src/Umbraco.Core/Dynamics/DynamicNull.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections; -using System.Dynamic; -using System.Web; - -namespace Umbraco.Core.Dynamics -{ - //This type is used as a return type when TryGetMember fails on a DynamicNode - //.Where explicitly checks for this type, to indicate that nothing was returned - //Because it's IEnumerable, if the user is actually trying @Model.TextPages or similar - //it will still return an enumerable object (assuming the call actually failed because there were no children of that type) - //but in .Where, if they use a property that doesn't exist, the lambda will bypass this and return false - - // returned when TryGetMember fails on a DynamicPublishedContent - // - // so if user does @CurrentPage.TextPages it will get something that is enumerable (but empty) - // note - not sure I understand the stuff about .Where, though - - public class DynamicNull : DynamicObject, IEnumerable, IHtmlString - { - public static readonly DynamicNull Null = new DynamicNull(); - - private DynamicNull() {} - - public IEnumerator GetEnumerator() - { - return (new List()).GetEnumerator(); - } - - public DynamicNull Where(string predicate, params object[] values) - { - return this; - } - - public DynamicNull OrderBy(string orderBy) - { - return this; - } - - public DynamicNull ToContentSet() - { - return this; - } - - public int Count() - { - return 0; - } - - public override string ToString() - { - return string.Empty; - } - - public override bool TryGetMember(GetMemberBinder binder, out object result) - { - result = this; - return true; - } - - public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) - { - result = this; - return true; - } - - public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) - { - result = this; - return true; - } - - public bool IsNull() - { - return true; - } - - public bool HasValue() - { - return false; - } - - public string Name - { - get { return string.Empty; } - } - - public int Id - { - get { return 0; } - } - - public static implicit operator bool(DynamicNull n) - { - return false; - } - - public static implicit operator DateTime(DynamicNull n) - { - return DateTime.MinValue; - } - - public static implicit operator int(DynamicNull n) - { - return 0; - } - - public static implicit operator string(DynamicNull n) - { - return string.Empty; - } - - public string ToHtmlString() - { - return string.Empty; - } - } -} diff --git a/src/Umbraco.Core/Dynamics/DynamicOrdering.cs b/src/Umbraco.Core/Dynamics/DynamicOrdering.cs deleted file mode 100644 index b4f0bf0d3a..0000000000 --- a/src/Umbraco.Core/Dynamics/DynamicOrdering.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Linq.Expressions; - -namespace Umbraco.Core.Dynamics -{ - internal class DynamicOrdering - { - public Expression Selector; - public bool Ascending; - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Dynamics/DynamicProperty.cs b/src/Umbraco.Core/Dynamics/DynamicProperty.cs deleted file mode 100644 index acb29bf387..0000000000 --- a/src/Umbraco.Core/Dynamics/DynamicProperty.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; - -namespace Umbraco.Core.Dynamics -{ - internal class DynamicProperty - { - readonly string _name; - readonly Type _type; - - public DynamicProperty(string name, Type type) - { - if (name == null) throw new ArgumentNullException("name"); - if (type == null) throw new ArgumentNullException("type"); - this._name = name; - this._type = type; - } - - public string Name - { - get { return _name; } - } - - public Type Type - { - get { return _type; } - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Dynamics/DynamicQueryableGetMemberBinder.cs b/src/Umbraco.Core/Dynamics/DynamicQueryableGetMemberBinder.cs deleted file mode 100644 index 92d7cfcdc9..0000000000 --- a/src/Umbraco.Core/Dynamics/DynamicQueryableGetMemberBinder.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Dynamic; - -namespace Umbraco.Core.Dynamics -{ - internal class DynamicQueryableGetMemberBinder : GetMemberBinder - { - public DynamicQueryableGetMemberBinder(string name, bool ignoreCase) : base(name, ignoreCase) { } - - public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Umbraco.Core/Dynamics/DynamicXml.cs b/src/Umbraco.Core/Dynamics/DynamicXml.cs deleted file mode 100644 index bedb25a69c..0000000000 --- a/src/Umbraco.Core/Dynamics/DynamicXml.cs +++ /dev/null @@ -1,849 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Dynamic; -using System.Reflection; -using System.Xml.Linq; -using System.Xml.XPath; -using System.Collections; -using System.IO; -using System.Web; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Xml; - -namespace Umbraco.Core.Dynamics -{ - [TypeConverter(typeof(DynamicXmlConverter))] - public class DynamicXml : DynamicObject, IEnumerable, IEnumerable - { - /// - /// Returns the XElement used to create the DynamicXml structure - /// - public XElement BaseElement { get; set; } - - /// - /// Returns the raw XElement used to create the DynamicXml structure if one was specified otherwise returns the - /// same value as BaseElement. - /// - /// - /// This is purely used for when an instance of DynamicXml is created with the overload that supports - /// passing in both a raw xml version and a dash-stripped xml version. Otherwise this value is exactly the - /// same as BaseElement. - /// - public XElement RawXmlElement { get; internal set; } - - /// - /// Constructor - /// - /// - public DynamicXml(XElement baseElement) - { - if (baseElement == null) return; - - //same - RawXmlElement = baseElement; - BaseElement = baseElement; - } - - /// - /// When this constructor is used the BaseElement becomes equivalent to the strippedXml structure - /// - /// - /// - internal DynamicXml(XElement strippedXml, XElement rawXml) - { - if (rawXml == null) return; - if (strippedXml == null) return; - - RawXmlElement = rawXml; - BaseElement = strippedXml; - } - - /// - /// When this constructor is used the BaseElement becomes equivalent to the strippedXml structure - /// - /// - /// - internal DynamicXml(string strippedXml, string rawXml) - { - if (rawXml == null) return; - if (strippedXml == null) return; - - RawXmlElement = XElement.Parse(rawXml); - BaseElement = XElement.Parse(strippedXml); - } - - /// - /// Constructor - /// - /// - public DynamicXml(string xml) - { - if (xml.IsNullOrWhiteSpace()) return; - - var baseElement = XElement.Parse(xml); - - //same - RawXmlElement = baseElement; - BaseElement = baseElement; - } - - /// - /// Constructor - /// - /// - public DynamicXml(XPathNodeIterator xpni) - { - if (xpni == null) return; - if (xpni.Current == null) return; - - //TODO: OuterXml is really bad for performance! Should actually use the XPathNodeIterator api - var xml = xpni.Current.OuterXml; - var baseElement = XElement.Parse(xml); - - //same - RawXmlElement = baseElement; - BaseElement = baseElement; - } - - /// - /// Returns the InnertText based on the BaseElement object - /// - public string InnerText - { - get - { - return BaseElement.Value; - } - } - - /// - /// Returns the string representation of the BaseElement object - /// - /// - public string ToXml() - { - return BaseElement.ToString(SaveOptions.DisableFormatting); - } - - /// - /// Returns the string representation of the RawXmlElement object - /// - /// - public string ToRawXml() - { - return RawXmlElement.ToString(SaveOptions.DisableFormatting); - } - - public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) - { - int index = 0; - if (indexes.Length > 0) - { - index = (int)indexes[0]; - result = new DynamicXml( - RawXmlElement.Elements().ElementAt(index), - BaseElement.Elements().ElementAt(index)); - return true; - } - return base.TryGetIndex(binder, indexes, out result); - } - public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) - { - if (args.Length == 0 && binder.Name == "ToXml") - { - result = BaseElement.ToString(); - return true; - } - if (args.Length == 1 && binder.Name == "XPath") - { - var elements = BaseElement.XPathSelectElements(args[0].ToString()); - HandleIEnumerableXElement(elements, out result); - return true; //anyway - } - - var runtimeCache = ApplicationContext.Current != null ? ApplicationContext.Current.ApplicationCache.RuntimeCache : new NullCacheProvider(); - - //ok, now lets try to match by member, property, extensino method - var attempt = DynamicInstanceHelper.TryInvokeMember(runtimeCache, this, binder, args, new[] - { - typeof (IEnumerable), - typeof (IEnumerable), - typeof (DynamicXml) - }); - - if (attempt.Success) - { - result = attempt.Result.ObjectResult; - - //need to check the return type and possibly cast if result is from an extension method found - if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod) - { - //if the result is already a DynamicXml instance, then we do not need to cast - if (attempt.Result.ObjectResult != null && !(attempt.Result.ObjectResult is DynamicXml)) - { - if (attempt.Result.ObjectResult is XElement) - { - result = new DynamicXml((XElement)attempt.Result.ObjectResult); - } - else if (attempt.Result.ObjectResult is IEnumerable) - { - result = ((IEnumerable)attempt.Result.ObjectResult).Select(x => new DynamicXml(x)); - } - else if (attempt.Result.ObjectResult is IEnumerable) - { - result = ((IEnumerable) attempt.Result.ObjectResult).Select(x => new DynamicXml( - x.RawXmlElement, - x.BaseElement)); - } - } - } - return true; - } - - //this is the result of an extension method execution gone wrong so we return dynamic null - if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod - && attempt.Exception != null && attempt.Exception is TargetInvocationException) - { - result = DynamicNull.Null; - return true; - } - - result = null; - return false; - - } - public override bool TryGetMember(GetMemberBinder binder, out object result) - { - if (RawXmlElement == null || binder == null) - { - result = null; - return false; - } - - //Check if the name matches a node based on the BaseElement (which if the correct ctor is used, will be dash stripped) - var elementByNameAttempt = CheckNodeNameMatch(binder.Name, BaseElement); - if (elementByNameAttempt.Success) - { - if (HandleIEnumerableXElement(elementByNameAttempt.Result, out result)) - { - return true; - } - } - - //Check if the name matches a node based on the BaseElement (which if the correct ctor is used, will be dash stripped) - var attributeByNameAttempt = CheckAttributeNameMatch(binder.Name, BaseElement); - if (attributeByNameAttempt.Success) - { - if (attributeByNameAttempt.Result.Count() > 1) - { - //more than one attribute matched, lets return the collection - result = attributeByNameAttempt.Result; - } - else - { - //only one attribute matched, lets just return it - result = attributeByNameAttempt.Result.FirstOrDefault(); - } - return true; - } - - - return base.TryGetMember(binder, out result); - } - - /// - /// Checks if the 'name' matches any attributes of xmlElement - /// - /// The name to match - /// The xml element to check against - /// - private static Attempt> CheckAttributeNameMatch(string name, XElement xmlElement) - { - var attributes = xmlElement.Attributes(name).Select(attr => attr.Value).ToArray(); - if (attributes.Any()) - { - return Attempt>.Succeed(attributes); - } - - if (!attributes.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1) - { - //no elements matched and this node is called 'root' and only has one child... lets see if it matches. - var childElements = xmlElement.Elements().ElementAt(0).Attributes(name).Select(attr => attr.Value).ToArray(); - if (childElements.Any()) - { - //we've found a match by the first child of an element called 'root' (strange, but sure) - return Attempt>.Succeed(childElements); - } - } - - //no deal - return Attempt>.Fail(); - } - - /// - /// Checks if the 'name' matches any elements of xmlElement - /// - /// The name to match - /// The xml element to check against - /// - private Attempt> CheckNodeNameMatch(string name, XElement xmlElement) - { - //Go ahead and try to fetch all of the elements matching the member name, and wrap them - var elements = xmlElement.Elements(name).ToArray(); - - //Check if we've got any matches, if so then return true - if (elements.Any()) - { - return Attempt>.Succeed(elements); - } - - if (!elements.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1) - { - //no elements matched and this node is called 'root' and only has one child... lets see if it matches. - var childElements = xmlElement.Elements().ElementAt(0).Elements(name).ToArray(); - if (childElements.Any()) - { - //we've found a match by the first child of an element called 'root' (strange, but sure) - return Attempt>.Succeed(childElements); - } - } - - //no deal - return Attempt>.Fail(); - } - - private bool HandleIEnumerableXElement(IEnumerable elements, out object result) - { - //Get the count now, so we don't have to call it twice - int count = elements.Count(); - if (count > 0) - { - var firstElement = elements.FirstOrDefault(); - //we have a single element, does it have any children? - if (firstElement != null && firstElement.Elements().Any() == false && firstElement.HasAttributes == false) - { - //no, return the text - result = firstElement.Value; - return true; - } - else - { - //We have more than one matching element, so let's return the collection - //elements is IEnumerable - //but we want to be able to re-enter this code - var root = new XElement(XName.Get("root")); - root.Add(elements); - result = new DynamicXml(root); - - //From here, you'll either end up back here (because you have ) - //or you use [] indexing and you end up with a single element - return true; - } - } - result = null; - return false; - } - - /// - /// Executes an XPath expression over the BaseElement object - /// - /// - /// - public DynamicXml XPath(string expression) - { - var matched = BaseElement.XPathSelectElements(expression); - var root = new DynamicXml(""); - foreach (var element in matched) - { - root.BaseElement.Add(element); - } - return root; - } - - /// - /// Return the string version of the BaseElement object - /// - /// - public override string ToString() - { - return ToXml(); - } - - public IHtmlString ToHtml() - { - return new HtmlString(this.ToXml()); - } - public DynamicXml Find(string expression) - { - return new DynamicXml(BaseElement.XPathSelectElements(expression).FirstOrDefault()); - } - - public DynamicXml Find(string attributeName, object value) - { - string expression = string.Format("//*[{0}='{1}']", attributeName, value); - return new DynamicXml(BaseElement.XPathSelectElements(expression).FirstOrDefault()); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return BaseElement.Elements().GetEnumerator(); - } - - public IEnumerator GetEnumerator() - { - return BaseElement.Elements().Select(e => new DynamicXml(e)).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public int Count() - { - return ((IEnumerable)this).Count(); - } - - public bool Any() - { - return ((IEnumerable)this).Any(); - } - - public IEnumerable Take(int count) - { - return ((IEnumerable)this).Take(count); - } - - public IEnumerable Skip(int count) - { - return ((IEnumerable)this).Skip(count); - } - - public bool IsNull() - { - return false; - } - public bool HasValue() - { - return true; - } - - public bool IsFirst() - { - return IsHelper(n => n.Index() == 0); - } - public HtmlString IsFirst(string valueIfTrue) - { - return IsHelper(n => n.Index() == 0, valueIfTrue); - } - public HtmlString IsFirst(string valueIfTrue, string valueIfFalse) - { - return IsHelper(n => n.Index() == 0, valueIfTrue, valueIfFalse); - } - public bool IsNotFirst() - { - return !IsHelper(n => n.Index() == 0); - } - public HtmlString IsNotFirst(string valueIfTrue) - { - return IsHelper(n => n.Index() != 0, valueIfTrue); - } - public HtmlString IsNotFirst(string valueIfTrue, string valueIfFalse) - { - return IsHelper(n => n.Index() != 0, valueIfTrue, valueIfFalse); - } - public bool IsPosition(int index) - { - if (BaseElement == null || BaseElement.Parent == null) - { - return false; - } - return IsHelper(n => n.Index() == index); - } - public HtmlString IsPosition(int index, string valueIfTrue) - { - if (BaseElement == null || BaseElement.Parent == null) - { - return new HtmlString(string.Empty); - } - return IsHelper(n => n.Index() == index, valueIfTrue); - } - public HtmlString IsPosition(int index, string valueIfTrue, string valueIfFalse) - { - if (BaseElement == null || BaseElement.Parent == null) - { - return new HtmlString(valueIfFalse); - } - return IsHelper(n => n.Index() == index, valueIfTrue, valueIfFalse); - } - public bool IsModZero(int modulus) - { - if (BaseElement == null || BaseElement.Parent == null) - { - return false; - } - return IsHelper(n => n.Index() % modulus == 0); - } - public HtmlString IsModZero(int modulus, string valueIfTrue) - { - if (BaseElement == null || BaseElement.Parent == null) - { - return new HtmlString(string.Empty); - } - return IsHelper(n => n.Index() % modulus == 0, valueIfTrue); - } - public HtmlString IsModZero(int modulus, string valueIfTrue, string valueIfFalse) - { - if (BaseElement == null || BaseElement.Parent == null) - { - return new HtmlString(valueIfFalse); - } - return IsHelper(n => n.Index() % modulus == 0, valueIfTrue, valueIfFalse); - } - - public bool IsNotModZero(int modulus) - { - if (BaseElement == null || BaseElement.Parent == null) - { - return false; - } - return IsHelper(n => n.Index() % modulus != 0); - } - public HtmlString IsNotModZero(int modulus, string valueIfTrue) - { - if (BaseElement == null || this.BaseElement.Parent == null) - { - return new HtmlString(string.Empty); - } - return IsHelper(n => n.Index() % modulus != 0, valueIfTrue); - } - public HtmlString IsNotModZero(int modulus, string valueIfTrue, string valueIfFalse) - { - if (this.BaseElement == null || this.BaseElement.Parent == null) - { - return new HtmlString(valueIfFalse); - } - return IsHelper(n => n.Index() % modulus != 0, valueIfTrue, valueIfFalse); - } - public bool IsNotPosition(int index) - { - if (this.BaseElement == null || this.BaseElement.Parent == null) - { - return false; - } - return !IsHelper(n => n.Index() == index); - } - public HtmlString IsNotPosition(int index, string valueIfTrue) - { - if (this.BaseElement == null || this.BaseElement.Parent == null) - { - return new HtmlString(string.Empty); - } - return IsHelper(n => n.Index() != index, valueIfTrue); - } - public HtmlString IsNotPosition(int index, string valueIfTrue, string valueIfFalse) - { - if (this.BaseElement == null || this.BaseElement.Parent == null) - { - return new HtmlString(valueIfFalse); - } - return IsHelper(n => n.Index() != index, valueIfTrue, valueIfFalse); - } - public bool IsLast() - { - if (this.BaseElement == null || this.BaseElement.Parent == null) - { - return false; - } - int count = this.BaseElement.Parent.Elements().Count(); - return IsHelper(n => n.Index() == count - 1); - } - public HtmlString IsLast(string valueIfTrue) - { - if (this.BaseElement == null || this.BaseElement.Parent == null) - { - return new HtmlString(string.Empty); - } - int count = this.BaseElement.Parent.Elements().Count(); - return IsHelper(n => n.Index() == count - 1, valueIfTrue); - } - public HtmlString IsLast(string valueIfTrue, string valueIfFalse) - { - if (this.BaseElement == null || this.BaseElement.Parent == null) - { - return new HtmlString(valueIfFalse); - } - int count = this.BaseElement.Parent.Elements().Count(); - return IsHelper(n => n.Index() == count - 1, valueIfTrue, valueIfFalse); - } - public bool IsNotLast() - { - if (this.BaseElement == null || this.BaseElement.Parent == null) - { - return false; - } - int count = this.BaseElement.Parent.Elements().Count(); - return !IsHelper(n => n.Index() == count - 1); - } - public HtmlString IsNotLast(string valueIfTrue) - { - if (this.BaseElement == null || this.BaseElement.Parent == null) - { - return new HtmlString(string.Empty); - } - int count = this.BaseElement.Parent.Elements().Count(); - return IsHelper(n => n.Index() != count - 1, valueIfTrue); - } - public HtmlString IsNotLast(string valueIfTrue, string valueIfFalse) - { - if (this.BaseElement == null || this.BaseElement.Parent == null) - { - return new HtmlString(valueIfFalse); - } - int count = this.BaseElement.Parent.Elements().Count(); - return IsHelper(n => n.Index() != count - 1, valueIfTrue, valueIfFalse); - } - public bool IsEven() - { - return IsHelper(n => n.Index() % 2 == 0); - } - public HtmlString IsEven(string valueIfTrue) - { - return IsHelper(n => n.Index() % 2 == 0, valueIfTrue); - } - public HtmlString IsEven(string valueIfTrue, string valueIfFalse) - { - return IsHelper(n => n.Index() % 2 == 0, valueIfTrue, valueIfFalse); - } - public bool IsOdd() - { - return IsHelper(n => n.Index() % 2 == 1); - } - public HtmlString IsOdd(string valueIfTrue) - { - return IsHelper(n => n.Index() % 2 == 1, valueIfTrue); - } - public HtmlString IsOdd(string valueIfTrue, string valueIfFalse) - { - return IsHelper(n => n.Index() % 2 == 1, valueIfTrue, valueIfFalse); - } - public bool IsEqual(DynamicXml other) - { - return IsHelper(n => n.BaseElement == other.BaseElement); - } - public HtmlString IsEqual(DynamicXml other, string valueIfTrue) - { - return IsHelper(n => n.BaseElement == other.BaseElement, valueIfTrue); - } - public HtmlString IsEqual(DynamicXml other, string valueIfTrue, string valueIfFalse) - { - return IsHelper(n => n.BaseElement == other.BaseElement, valueIfTrue, valueIfFalse); - } - public bool IsNotEqual(DynamicXml other) - { - return IsHelper(n => n.BaseElement != other.BaseElement); - } - public HtmlString IsNotEqual(DynamicXml other, string valueIfTrue) - { - return IsHelper(n => n.BaseElement != other.BaseElement, valueIfTrue); - } - public HtmlString IsNotEqual(DynamicXml other, string valueIfTrue, string valueIfFalse) - { - return IsHelper(n => n.BaseElement != other.BaseElement, valueIfTrue, valueIfFalse); - } - public bool IsDescendant(DynamicXml other) - { - var ancestors = this.Ancestors(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null); - } - public HtmlString IsDescendant(DynamicXml other, string valueIfTrue) - { - var ancestors = this.Ancestors(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null, valueIfTrue); - } - public HtmlString IsDescendant(DynamicXml other, string valueIfTrue, string valueIfFalse) - { - var ancestors = this.Ancestors(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null, valueIfTrue, valueIfFalse); - } - public bool IsDescendantOrSelf(DynamicXml other) - { - var ancestors = this.AncestorsOrSelf(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null); - } - public HtmlString IsDescendantOrSelf(DynamicXml other, string valueIfTrue) - { - var ancestors = this.AncestorsOrSelf(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null, valueIfTrue); - } - public HtmlString IsDescendantOrSelf(DynamicXml other, string valueIfTrue, string valueIfFalse) - { - var ancestors = this.AncestorsOrSelf(); - return IsHelper(n => ancestors.FirstOrDefault(ancestor => ancestor.BaseElement == other.BaseElement) != null, valueIfTrue, valueIfFalse); - } - public bool IsAncestor(DynamicXml other) - { - var descendants = this.Descendants(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null); - } - public HtmlString IsAncestor(DynamicXml other, string valueIfTrue) - { - var descendants = this.Descendants(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null, valueIfTrue); - } - public HtmlString IsAncestor(DynamicXml other, string valueIfTrue, string valueIfFalse) - { - var descendants = this.Descendants(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null, valueIfTrue, valueIfFalse); - } - public bool IsAncestorOrSelf(DynamicXml other) - { - var descendants = this.DescendantsOrSelf(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null); - } - public HtmlString IsAncestorOrSelf(DynamicXml other, string valueIfTrue) - { - var descendants = this.DescendantsOrSelf(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null, valueIfTrue); - } - public HtmlString IsAncestorOrSelf(DynamicXml other, string valueIfTrue, string valueIfFalse) - { - var descendants = this.DescendantsOrSelf(); - return IsHelper(n => descendants.FirstOrDefault(descendant => descendant.BaseElement == other.BaseElement) != null, valueIfTrue, valueIfFalse); - } - public IEnumerable Descendants() - { - return Descendants(n => true); - } - public IEnumerable Descendants(Func func) - { - //var flattenedNodes = this.BaseElement.Elements().Map(func, n => n.Elements()); - var flattenedNodes = this.BaseElement.Elements().SelectMany(n => n.Elements()).Where(func); - return flattenedNodes.ToList().ConvertAll(n => new DynamicXml(n)); - } - public IEnumerable DescendantsOrSelf() - { - return DescendantsOrSelf(n => true); - } - public IEnumerable DescendantsOrSelf(Func func) - { - //var flattenedNodes = this.BaseElement.Elements().Map(func, n => n.Elements()); - var flattenedNodes = this.BaseElement.Elements().SelectMany(n => n.Elements()).Where(func); - var list = new List(); - list.Add(this); - list.AddRange(flattenedNodes.ToList().ConvertAll(n => new DynamicXml(n))); - return list; - } - public IEnumerable Ancestors() - { - return Ancestors(item => true); - } - public IEnumerable Ancestors(Func func) - { - var ancestorList = new List(); - var node = this.BaseElement; - while (node != null) - { - if (node.Parent == null) break; - XElement parent = node.Parent; - if (parent != null) - { - if (this.BaseElement != parent) - { - node = parent; - if (func(node)) - { - ancestorList.Add(node); - } - } - else - { - break; - } - } - else - { - break; - } - } - ancestorList.Reverse(); - return ancestorList.ConvertAll(item => new DynamicXml(item)); - } - public IEnumerable AncestorsOrSelf() - { - return AncestorsOrSelf(item => true); - } - public IEnumerable AncestorsOrSelf(Func func) - { - List ancestorList = new List(); - var node = this.BaseElement; - ancestorList.Add(node); - while (node != null) - { - if (node.Parent == null) break; - XElement parent = node.Parent; - if (parent != null) - { - if (this.BaseElement != parent) - { - node = parent; - if (func(node)) - { - ancestorList.Add(node); - } - } - else - { - break; - } - } - else - { - break; - } - } - ancestorList.Reverse(); - return ancestorList.ConvertAll(item => new DynamicXml(item)); - } - - public int Index() - { - if (this.BaseElement != null && this.BaseElement.Parent != null) - { - var elements = this.BaseElement.Parent.Elements(); - int index = 0; - foreach (var element in elements) - { - if (element == this.BaseElement) break; - index++; - } - return index; - } - return 0; - } - - public bool IsHelper(Func test) - { - return test(this); - } - public HtmlString IsHelper(Func test, string valueIfTrue) - { - return IsHelper(test, valueIfTrue, string.Empty); - } - public HtmlString IsHelper(Func test, string valueIfTrue, string valueIfFalse) - { - return test(this) ? new HtmlString(valueIfTrue) : new HtmlString(valueIfFalse); - } - - [Obsolete("Use XmlHelper.StripDashesInElementOrAttributeNames instead")] - public static string StripDashesInElementOrAttributeNames(string xml) - { - return XmlHelper.StripDashesInElementOrAttributeNames(xml); - } - - - } -} diff --git a/src/Umbraco.Core/Dynamics/DynamicXmlConverter.cs b/src/Umbraco.Core/Dynamics/DynamicXmlConverter.cs deleted file mode 100644 index 291378ad51..0000000000 --- a/src/Umbraco.Core/Dynamics/DynamicXmlConverter.cs +++ /dev/null @@ -1,151 +0,0 @@ -using System; -using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Xml; -using System.Xml.Linq; -using Umbraco.Core.Plugins; - -namespace Umbraco.Core.Dynamics -{ - /// - /// Used to return the raw xml string value from DynamicXml when using type converters - /// - public class RawXmlString - { - public string Value { get; private set; } - - public RawXmlString(string value) - { - Value = value; - } - } - - /// - /// Used to return the raw xml XElement value from DynamicXml when using type converters - /// - public class RawXElement - { - public XElement Value { get; private set; } - - public RawXElement(XElement value) - { - Value = value; - } - } - - /// - /// Used to return the raw xml XElement value from DynamicXml when using type converters - /// - public class RawXmlElement - { - public XmlElement Value { get; private set; } - - public RawXmlElement(XmlElement value) - { - Value = value; - } - } - - /// - /// Used to return the raw xml XmlDocument value from DynamicXml when using type converters - /// - public class RawXmlDocument - { - public XmlDocument Value { get; private set; } - - public RawXmlDocument(XmlDocument value) - { - Value = value; - } - } - - /// - /// A custom type converter for DynamicXml - /// - public class DynamicXmlConverter : TypeConverter - { - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - var convertableTypes = new[] - { - typeof(string), - typeof(XElement), - typeof(XmlElement), - typeof(XmlDocument), - typeof(RawXmlString), - typeof(RawXElement), - typeof(RawXmlElement), - typeof(RawXmlDocument) - }; - - return convertableTypes.Any(x => TypeHelper.IsTypeAssignableFrom(x, destinationType)) - || base.CanConvertFrom(context, destinationType); - } - - public override object ConvertTo( - ITypeDescriptorContext context, - CultureInfo culture, - object value, - Type destinationType) - { - var dxml = value as DynamicXml; - if (dxml == null) - return null; - //string - if (TypeHelper.IsTypeAssignableFrom(destinationType)) - { - return value.ToString(); - } - - //XElement - if (TypeHelper.IsTypeAssignableFrom(destinationType)) - { - return dxml.BaseElement; - } - //XmlElement - if (TypeHelper.IsTypeAssignableFrom(destinationType)) - { - var xDoc = new XmlDocument(); - xDoc.LoadXml(dxml.ToString()); - return xDoc.DocumentElement; - } - //XmlDocument - if (TypeHelper.IsTypeAssignableFrom(destinationType)) - { - var xDoc = new XmlDocument(); - xDoc.LoadXml(dxml.ToString()); - return xDoc; - } - - //RAW values: - //string - if (TypeHelper.IsTypeAssignableFrom(destinationType)) - { - return new RawXmlString(dxml.ToRawXml()); - } - //XElement - if (TypeHelper.IsTypeAssignableFrom(destinationType)) - { - return new RawXElement(dxml.RawXmlElement); - } - //XmlElement - if (TypeHelper.IsTypeAssignableFrom(destinationType)) - { - var xDoc = new XmlDocument(); - xDoc.LoadXml(dxml.ToRawXml()); - return new RawXmlElement(xDoc.DocumentElement); - } - //XmlDocument - if (TypeHelper.IsTypeAssignableFrom(destinationType)) - { - var xDoc = new XmlDocument(); - xDoc.LoadXml(dxml.ToRawXml()); - return new RawXmlDocument(xDoc); - } - - - return base.ConvertTo(context, culture, value, destinationType); - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs b/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs deleted file mode 100644 index 33a938154a..0000000000 --- a/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs +++ /dev/null @@ -1,183 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Linq.Expressions; -using System.Text; -using System.Web.Services.Description; -using Umbraco.Core.Cache; -using Umbraco.Core.Logging; -using Umbraco.Core.Plugins; - -namespace Umbraco.Core.Dynamics -{ - /// - /// Utility class for finding extension methods on a type to execute - /// - internal static class ExtensionMethodFinder - { - /// - /// The static cache for extension methods found that match the criteria that we are looking for - /// - private static readonly ConcurrentDictionary, MethodInfo[]> MethodCache = new ConcurrentDictionary, MethodInfo[]>(); - - private static IEnumerable GetTypes(Assembly a) - { - try - { - return TypeFinder.GetTypesWithFormattedException(a); - } - catch (ReflectionTypeLoadException ex) - { - // is this going to flood the log? - LogHelper.Error(typeof (ExtensionMethodFinder), "Failed to get types.", ex); - return Enumerable.Empty(); - } - } - - /// - /// Returns the enumerable of all extension method info's in the app domain = USE SPARINGLY!!! - /// - /// - /// - /// We cache this as a sliding 5 minute exiration, in unit tests there's over 1100 methods found, surely that will eat up a bit of memory so we want - /// to make sure we give it back. - /// - private static IEnumerable GetAllExtensionMethodsInAppDomain(IRuntimeCacheProvider runtimeCacheProvider) - { - if (runtimeCacheProvider == null) throw new ArgumentNullException("runtimeCacheProvider"); - - return runtimeCacheProvider.GetCacheItem(typeof (ExtensionMethodFinder).Name, () => TypeFinder.GetAssembliesWithKnownExclusions() - // assemblies that contain extension methods - .Where(a => a.IsDefined(typeof (ExtensionAttribute), false)) - // types that contain extension methods - .SelectMany(a => GetTypes(a) - .Where(t => t.IsDefined(typeof (ExtensionAttribute), false) && t.IsSealed && t.IsGenericType == false && t.IsNested == false)) - // actual extension methods - .SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Public) - .Where(m => m.IsDefined(typeof (ExtensionAttribute), false))) - // and also IEnumerable extension methods - because the assembly is excluded - .Concat(typeof (Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)) - //If we don't do this then we'll be scanning all assemblies each time! - .ToArray(), - - //only cache for 5 minutes - timeout: TimeSpan.FromMinutes(5), - - //each time this is accessed it will be for 5 minutes longer - isSliding:true); - } - - /// - /// Returns all extension methods found matching the definition - /// - /// - /// The runtime cache is used to temporarily cache all extension methods found in the app domain so that - /// while we search for individual extension methods, the process will be reasonably 'quick'. We then statically - /// cache the MethodInfo's that we are looking for and then the runtime cache will expire and give back all that memory. - /// - /// - /// - /// - /// The arguments EXCLUDING the 'this' argument in an extension method - /// - /// - /// - /// NOTE: This will be an intensive method to call! Results will be cached based on the key (args) of this method - /// - internal static IEnumerable GetAllExtensionMethods(IRuntimeCacheProvider runtimeCache, Type thisType, string name, int argumentCount) - { - var key = new Tuple(thisType, name, argumentCount); - - return MethodCache.GetOrAdd(key, tuple => - { - var candidates = GetAllExtensionMethodsInAppDomain(runtimeCache); - - // filter by name - var filtr1 = candidates.Where(m => m.Name == name); - - // filter by args count - // ensure we add + 1 to the arg count because the 'this' arg is not included in the count above! - var filtr2 = filtr1.Where(m => m.GetParameters().Length == argumentCount + 1); - - // filter by first parameter type (target of the extension method) - // ie find the right overload that can take genericParameterType - // (which will be either DynamicNodeList or List which is IEnumerable) - var filtr3 = filtr2.Select(x => - { - var t = x.GetParameters()[0].ParameterType; // exists because of +1 above - var bindings = new Dictionary(); - if (TypeHelper.MatchType(thisType, t, bindings) == false) return null; - - // create the generic method if necessary - if (x.ContainsGenericParameters == false) return x; - var targs = t.GetGenericArguments().Select(y => bindings[y.Name]).ToArray(); - return x.MakeGenericMethod(targs); - }).Where(x => x != null); - - return filtr3.ToArray(); - }); - - } - - private static MethodInfo DetermineMethodFromParams(IEnumerable methods, Type genericType, IEnumerable args) - { - MethodInfo methodToExecute = null; - - //Given the args, lets get the types and compare the type sequence to try and find the correct overload - var argTypes = args.Select(o => - { - var oe = (o as Expression); - return oe != null ? oe.Type : o.GetType(); - }); - - var methodsWithArgTypes = methods.Select(method => new - { - method, - //skip the first arg because that is the extension method type ('this') that we are looking for - types = method.GetParameters().Select(pi => pi.ParameterType).Skip(1) - }); - - //This type comparer will check - var typeComparer = new DelegateEqualityComparer( - //Checks if the argument type passed in can be assigned from the parameter type in the method. For - // example, if the argument type is HtmlHelper but the method parameter type is HtmlHelper then - // it will match because the argument is assignable to that parameter type and will be able to execute - TypeHelper.IsTypeAssignableFrom, - //This will not ever execute but if it does we need to get the hash code of the string because the hash - // code of a type is random - type => type.FullName.GetHashCode()); - - var firstMatchingOverload = methodsWithArgTypes - .FirstOrDefault(m => m.types.SequenceEqual(argTypes, typeComparer)); - - if (firstMatchingOverload != null) - { - methodToExecute = firstMatchingOverload.method; - } - - return methodToExecute; - } - - public static MethodInfo FindExtensionMethod(IRuntimeCacheProvider runtimeCache, Type thisType, object[] args, string name, bool argsContainsThis) - { - Type genericType = null; - if (thisType.IsGenericType) - { - genericType = thisType.GetGenericArguments()[0]; - } - - args = args - //if the args contains 'this', remove the first one since that is 'this' and we don't want to use - //that in the method searching - .Skip(argsContainsThis ? 1 : 0) - .ToArray(); - - var methods = GetAllExtensionMethods(runtimeCache, thisType, name, args.Length).ToArray(); - - return DetermineMethodFromParams(methods, genericType, args); - } - } -} diff --git a/src/Umbraco.Core/Dynamics/ParseException.cs b/src/Umbraco.Core/Dynamics/ParseException.cs deleted file mode 100644 index 5208644306..0000000000 --- a/src/Umbraco.Core/Dynamics/ParseException.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -namespace Umbraco.Core.Dynamics -{ - internal sealed class ParseException : Exception - { - readonly int _position; - - public ParseException(string message, int position) - : base(message) - { - this._position = position; - } - - public int Position - { - get { return _position; } - } - - public override string ToString() - { - return string.Format(Res.ParseExceptionFormat, Message, _position); - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Dynamics/PropertyResult.cs b/src/Umbraco.Core/Dynamics/PropertyResult.cs deleted file mode 100644 index 14689f653a..0000000000 --- a/src/Umbraco.Core/Dynamics/PropertyResult.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using Umbraco.Core.Models; -using System.Web; -using Umbraco.Core.Models.PublishedContent; - -namespace Umbraco.Core.Dynamics -{ - internal class PropertyResult : IPublishedProperty, IHtmlString - { - private readonly IPublishedProperty _source; - private readonly string _alias; - private readonly object _value; - private readonly PropertyResultType _type; - - internal PropertyResult(IPublishedProperty source, PropertyResultType type) - { - if (source == null) throw new ArgumentNullException("source"); - - _type = type; - _source = source; - } - - internal PropertyResult(string alias, object value, PropertyResultType type) - { - if (alias == null) throw new ArgumentNullException("alias"); - if (value == null) throw new ArgumentNullException("value"); - - _type = type; - _alias = alias; - _value = value; - } - - internal PropertyResultType PropertyType { get { return _type; } } - - public string PropertyTypeAlias { get { return _source == null ? _alias : _source.PropertyTypeAlias; } } - public object SourceValue { get { return _source == null ? _value : _source.SourceValue; } } - public bool HasValue { get { return _source == null || _source.HasValue; } } - public object Value { get { return _source == null ? _value : _source.Value; } } - public object XPathValue { get { return Value == null ? null : Value.ToString(); } } - - public string ToHtmlString() - { - var value = Value; - return value == null ? string.Empty : value.ToString(); - } - } -} diff --git a/src/Umbraco.Core/Dynamics/QueryableExtensions.cs b/src/Umbraco.Core/Dynamics/QueryableExtensions.cs deleted file mode 100644 index 25c260d7ca..0000000000 --- a/src/Umbraco.Core/Dynamics/QueryableExtensions.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; - -namespace Umbraco.Core.Dynamics -{ - /// - /// Extension methods for IQueryable - /// - /// - /// NOTE: Ordering code taken from: http://stackoverflow.com/questions/41244/dynamic-linq-orderby-on-ienumerablet - /// - /// ANOTHER NOTE: We have a bastardized version of Dynamic Linq existing at Umbraco.Web.Dynamics however it's been hacked so not - /// sure we can use it for anything other than DynamicNode. - /// - internal static class QueryableExtensions - { - public static IOrderedQueryable OrderBy(this IQueryable source, string property) - { - return ApplyOrder(source, property, "OrderBy"); - } - public static IOrderedQueryable OrderByDescending(this IQueryable source, string property) - { - return ApplyOrder(source, property, "OrderByDescending"); - } - public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string property) - { - return ApplyOrder(source, property, "ThenBy"); - } - public static IOrderedQueryable ThenByDescending(this IOrderedQueryable source, string property) - { - return ApplyOrder(source, property, "ThenByDescending"); - } - static IOrderedQueryable ApplyOrder(IQueryable source, string property, string methodName) - { - string[] props = property.Split('.'); - Type type = typeof(T); - ParameterExpression arg = Expression.Parameter(type, "x"); - Expression expr = arg; - foreach (string prop in props) - { - // use reflection (not ComponentModel) to mirror LINQ - PropertyInfo pi = type.GetProperty(prop, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); - expr = Expression.Property(expr, pi); - type = pi.PropertyType; - } - Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type); - LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg); - - object result = typeof(Queryable).GetMethods().Single( - method => method.Name == methodName - && method.IsGenericMethodDefinition - && method.GetGenericArguments().Length == 2 - && method.GetParameters().Length == 2) - .MakeGenericMethod(typeof(T), type) - .Invoke(null, new object[] { source, lambda }); - return (IOrderedQueryable)result; - } - - - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Dynamics/Res.cs b/src/Umbraco.Core/Dynamics/Res.cs deleted file mode 100644 index 4ea5193d68..0000000000 --- a/src/Umbraco.Core/Dynamics/Res.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace Umbraco.Core.Dynamics -{ - internal static class Res - { - public const string DuplicateIdentifier = "The identifier '{0}' was defined more than once"; - public const string ExpressionTypeMismatch = "Expression of type '{0}' expected"; - public const string ExpressionExpected = "Expression expected"; - public const string InvalidCharacterLiteral = "Character literal must contain exactly one character"; - public const string InvalidIntegerLiteral = "Invalid integer literal '{0}'"; - public const string InvalidRealLiteral = "Invalid real literal '{0}'"; - public const string UnknownIdentifier = "Unknown identifier '{0}'"; - public const string NoItInScope = "No 'it' is in scope"; - public const string IifRequiresThreeArgs = "The 'iif' function requires three arguments"; - public const string FirstExprMustBeBool = "The first expression must be of type 'Boolean'"; - public const string BothTypesConvertToOther = "Both of the types '{0}' and '{1}' convert to the other"; - public const string NeitherTypeConvertsToOther = "Neither of the types '{0}' and '{1}' converts to the other"; - public const string MissingAsClause = "Expression is missing an 'as' clause"; - public const string ArgsIncompatibleWithLambda = "Argument list incompatible with lambda expression"; - public const string TypeHasNoNullableForm = "Type '{0}' has no nullable form"; - public const string NoMatchingConstructor = "No matching constructor in type '{0}'"; - public const string AmbiguousConstructorInvocation = "Ambiguous invocation of '{0}' constructor"; - public const string CannotConvertValue = "A value of type '{0}' cannot be converted to type '{1}'"; - public const string NoApplicableMethod = "No applicable method '{0}' exists in type '{1}'"; - public const string MethodsAreInaccessible = "Methods on type '{0}' are not accessible"; - public const string MethodIsVoid = "Method '{0}' in type '{1}' does not return a value"; - public const string AmbiguousMethodInvocation = "Ambiguous invocation of method '{0}' in type '{1}'"; - public const string UnknownPropertyOrField = "No property or field '{0}' exists in type '{1}'"; - public const string NoApplicableAggregate = "No applicable aggregate method '{0}' exists"; - public const string CannotIndexMultiDimArray = "Indexing of multi-dimensional arrays is not supported"; - public const string InvalidIndex = "Array index must be an integer expression"; - public const string NoApplicableIndexer = "No applicable indexer exists in type '{0}'"; - public const string AmbiguousIndexerInvocation = "Ambiguous invocation of indexer in type '{0}'"; - public const string IncompatibleOperand = "Operator '{0}' incompatible with operand type '{1}'"; - public const string IncompatibleOperands = "Operator '{0}' incompatible with operand types '{1}' and '{2}'"; - public const string UnterminatedStringLiteral = "Unterminated string literal"; - public const string InvalidCharacter = "Syntax error '{0}'"; - public const string DigitExpected = "Digit expected"; - public const string SyntaxError = "Syntax error"; - public const string TokenExpected = "{0} expected"; - public const string ParseExceptionFormat = "{0} (at index {1})"; - public const string ColonExpected = "':' expected"; - public const string OpenParenExpected = "'(' expected"; - public const string CloseParenOrOperatorExpected = "')' or operator expected"; - public const string CloseParenOrCommaExpected = "')' or ',' expected"; - public const string DotOrOpenParenExpected = "'.' or '(' expected"; - public const string OpenBracketExpected = "'[' expected"; - public const string CloseBracketOrCommaExpected = "']' or ',' expected"; - public const string IdentifierExpected = "Identifier expected"; - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Dynamics/Signature.cs b/src/Umbraco.Core/Dynamics/Signature.cs deleted file mode 100644 index cececc502d..0000000000 --- a/src/Umbraco.Core/Dynamics/Signature.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Umbraco.Core.Dynamics -{ - internal class Signature : IEquatable - { - public DynamicProperty[] Properties { get; set; } - public int HashCode { get; set; } - - public Signature(IEnumerable properties) - { - this.Properties = properties.ToArray(); - HashCode = 0; - foreach (DynamicProperty p in this.Properties) - { - HashCode ^= p.Name.GetHashCode() ^ p.Type.GetHashCode(); - } - } - - public override int GetHashCode() - { - return HashCode; - } - - public override bool Equals(object obj) - { - return obj is Signature && Equals((Signature)obj); - } - - public bool Equals(Signature other) - { - if (Properties.Length != other.Properties.Length) return false; - for (int i = 0; i < Properties.Length; i++) - { - if (Properties[i].Name != other.Properties[i].Name || - Properties[i].Type != other.Properties[i].Type) return false; - } - return true; - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/PublishedContent/PropertyResult.cs b/src/Umbraco.Core/Models/PublishedContent/PropertyResult.cs new file mode 100644 index 0000000000..4bf96eedea --- /dev/null +++ b/src/Umbraco.Core/Models/PublishedContent/PropertyResult.cs @@ -0,0 +1,45 @@ +using System; +using System.Web; + +namespace Umbraco.Core.Models.PublishedContent +{ + // fixme - temp + internal class PropertyResult : IPublishedProperty, IHtmlString + { + private readonly IPublishedProperty _source; + private readonly string _alias; + private readonly object _value; + + internal PropertyResult(IPublishedProperty source, PropertyResultType type) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + + PropertyType = type; + _source = source; + } + + internal PropertyResult(string alias, object value, PropertyResultType type) + { + if (alias == null) throw new ArgumentNullException(nameof(alias)); + if (value == null) throw new ArgumentNullException(nameof(value)); + + PropertyType = type; + _alias = alias; + _value = value; + } + + internal PropertyResultType PropertyType { get; } + + public string PropertyTypeAlias => _source == null ? _alias : _source.PropertyTypeAlias; + public object SourceValue => _source == null ? _value : _source.SourceValue; + public bool HasValue => _source == null || _source.HasValue; + public object Value => _source == null ? _value : _source.Value; + public object XPathValue => Value?.ToString(); + + public string ToHtmlString() + { + var value = Value; + return value?.ToString() ?? string.Empty; + } + } +} diff --git a/src/Umbraco.Core/Dynamics/PropertyResultType.cs b/src/Umbraco.Core/Models/PublishedContent/PropertyResultType.cs similarity index 60% rename from src/Umbraco.Core/Dynamics/PropertyResultType.cs rename to src/Umbraco.Core/Models/PublishedContent/PropertyResultType.cs index d1ab0904f5..bf045ef517 100644 --- a/src/Umbraco.Core/Dynamics/PropertyResultType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PropertyResultType.cs @@ -1,23 +1,20 @@ -namespace Umbraco.Core.Dynamics -{ - /// - /// Currently just used for informational purposes as to where a PropertyResult object was created from. - /// - internal enum PropertyResultType - { - /// - /// The property resolved was a normal document property - /// - UserProperty, - - /// - /// The property resolved was a property defined as a member on the document object (IPublishedContent) itself - /// - ReflectedProperty, - - /// - /// The property was created manually for a custom purpose - /// - CustomProperty - } -} \ No newline at end of file +namespace Umbraco.Core.Models.PublishedContent +{ + internal enum PropertyResultType + { + /// + /// The property resolved was a normal document property + /// + UserProperty, + + /// + /// The property resolved was a property defined as a member on the document object (IPublishedContent) itself + /// + ReflectedProperty, + + /// + /// The property was created manually for a custom purpose + /// + CustomProperty + } +} diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs index 2fb88e1002..373e2be299 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs @@ -3,7 +3,6 @@ using System.Globalization; using System.Linq; using System.Xml.Linq; using System.Xml.XPath; -using Umbraco.Core.Dynamics; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Xml; @@ -248,7 +247,7 @@ namespace Umbraco.Core.Models.PublishedContent // use the converter else use dark (& performance-wise expensive) magic return _converter != null ? _converter.ConvertSourceToInter(this, source, preview) - : ConvertUsingDarkMagic(source); + : source; } // converts the inter value into the clr value @@ -287,37 +286,6 @@ namespace Umbraco.Core.Models.PublishedContent return inter.ToString().Trim(); } - internal static object ConvertUsingDarkMagic(object source) - { - // convert to string - var stringSource = source as string; - if (stringSource == null) return source; // not a string => return the object - stringSource = stringSource.Trim(); - if (stringSource.Length == 0) return null; // empty string => return null - - // try numbers and booleans - // make sure we use the invariant culture ie a dot decimal point, comma is for csv - // NOTE far from perfect: "01a" is returned as a string but "012" is returned as an integer... - int i; - if (int.TryParse(stringSource, NumberStyles.Integer, CultureInfo.InvariantCulture, out i)) - return i; - float f; - if (float.TryParse(stringSource, NumberStyles.Float, CultureInfo.InvariantCulture, out f)) - return f; - bool b; - if (bool.TryParse(stringSource, out b)) - return b; - - //TODO: We can change this just like we do for the JSON converter - but to maintain compatibility might mean this still has to remain here - - // try xml - that is expensive, performance-wise - XElement elt; - if (XmlHelper.TryCreateXElementFromPropertyValue(stringSource, out elt)) - return new DynamicXml(elt); // xml => return DynamicXml for compatiblity's sake - - return source; - } - // gets the property CLR type public Type ClrType { diff --git a/src/Umbraco.Core/PropertyEditors/PropertyValueConverterBase.cs b/src/Umbraco.Core/PropertyEditors/PropertyValueConverterBase.cs index 4117685187..1db9ce88ad 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyValueConverterBase.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyValueConverterBase.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.PropertyEditors public virtual object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) { - return PublishedPropertyType.ConvertUsingDarkMagic(source); + return source; } public virtual object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 3bd5d7ed18..b01dd2e1f2 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -220,9 +220,6 @@ - - - @@ -261,6 +258,8 @@ + + @@ -1040,16 +1039,6 @@ - - - - - - - - - - @@ -1117,10 +1106,6 @@ - - - - @@ -1147,7 +1132,6 @@ - diff --git a/src/Umbraco.Tests/DynamicsAndReflection/ExtensionMethodFinderTests.cs b/src/Umbraco.Tests/DynamicsAndReflection/ExtensionMethodFinderTests.cs deleted file mode 100644 index 550310d164..0000000000 --- a/src/Umbraco.Tests/DynamicsAndReflection/ExtensionMethodFinderTests.cs +++ /dev/null @@ -1,395 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Web.Mvc; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Dynamics; - -namespace Umbraco.Tests.DynamicsAndReflection -{ - [TestFixture] - public class ExtensionMethodFinderTests - { - #region Tests Elements - - public class TestClass { } - public class TestClass : TestClass { } - public class TestClassOfInt : TestClass { } - public class TestClassOfString : TestClass { } - - public void TestMethod1(int value) { } - public void TestMethod2(T value) { } - public void TestMethod3(T value1, T value2) { } - public void TestMethod4(T1 value1, T2 value2) { } - public void TestMethod5(List value) { } - public void TestMethod6(int value) { } - public void TestMethod6(string value) { } - public void TestMethod7(IList value) { } - public void TestMethod8(IDictionary value) { } - - public interface ITestDict : IDictionary { } - - #endregion - - #region Utilities - - private static readonly IRuntimeCacheProvider NullCache = new NullCacheProvider(); - - private static MethodInfo FindExtensionMethod(Type thisType, object[] args, string name, bool argsContainsThis) - { - return ExtensionMethodFinder.FindExtensionMethod(NullCache, thisType, args, name, argsContainsThis); - } - - #endregion - - #region Tests Set #1 - - [Test] - public void Find_Non_Overloaded_Method() - { - var class1 = new TestClass(); - - var method = FindExtensionMethod(typeof(TestClass), new object[] { 1 }, "SimpleMethod", false); - Assert.IsNotNull(method); - method.Invoke(null, new object[] { class1, 1 }); - - method = FindExtensionMethod(typeof(TestClass), new object[] { "x" }, "SimpleMethod", false); - Assert.IsNull(method); - } - - [Test] - public void Find_SimpleOverloaded() - { - var class1 = new TestClass(); - - var method = FindExtensionMethod(typeof(TestClass), new object[] { 1 }, "SimpleOverloadMethod", false); - Assert.IsNotNull(method); - method.Invoke(null, new object[] { class1, 1 }); - - method = FindExtensionMethod(typeof(TestClass), new object[] { "x" }, "SimpleOverloadMethod", false); - Assert.IsNotNull(method); - method.Invoke(null, new object[] { class1, "x" }); - } - - [Test] - public void Find_SimpleOverloaded_ArgsContainingThis() - { - var class1 = new TestClass(); - - var method = FindExtensionMethod(typeof(TestClass), new object[] { class1, 1 }, "SimpleOverloadMethod", true); - Assert.IsNotNull(method); - method.Invoke(null, new object[] { class1, 1 }); - - method = FindExtensionMethod(typeof(TestClass), new object[] { class1, "x" }, "SimpleOverloadMethod", true); - Assert.IsNotNull(method); - method.Invoke(null, new object[] { class1, "x" }); - } - - [Test] - public void Find_NonOverloadedGenericEnumerable() - { - var class1 = Enumerable.Empty(); - - var method = FindExtensionMethod(typeof(IEnumerable), new object[] { 1 }, "SimpleEnumerableGenericMethod", false); - Assert.IsNotNull(method); - method.Invoke(null, new object[] { class1, 1 }); - - method = FindExtensionMethod(typeof(IEnumerable), new object[] { "x" }, "SimpleEnumerableGenericMethod", false); - Assert.IsNull(method); - } - - [Test] - public void Find_OverloadedGenericEnumerable() - { - var class1 = Enumerable.Empty(); - - var method = FindExtensionMethod(typeof(IEnumerable), new object[] { 1 }, "SimpleOverloadEnumerableGenericMethod", false); - Assert.IsNotNull(method); - method.Invoke(null, new object[] { class1, 1 }); - - method = FindExtensionMethod(typeof(IEnumerable), new object[] { "x" }, "SimpleOverloadEnumerableGenericMethod", false); - Assert.IsNotNull(method); - method.Invoke(null, new object[] { class1, "x" }); - } - - [Test] - public void Find_InheritedType() - { - var genericTestClass = new TestClass(); - var nonGenericTestClass = new TestClass(); - - // not really testing "generics" here, just inheritance - - var method = FindExtensionMethod(typeof(TestClass), new object[] { genericTestClass }, "GenericParameterMethod", false); - Assert.IsNotNull(method); - - method = FindExtensionMethod(typeof(TestClass), new object[] { nonGenericTestClass }, "GenericParameterMethod", false); - Assert.IsNotNull(method); - } - - [Test] - public void Find_TrueGeneric() - { - var c = new TestClass(); - - var method = FindExtensionMethod(c.GetType(), new object[] { }, "GenericMethod", false); - Assert.IsNotNull(method); - } - - [Test] - public void GetMethodVsGetMethods() - { - Assert.Throws(() => - { - var m = typeof (ExtensionMethodFinderTests).GetMethod("TestMethod6"); - }); - - var ms = typeof (ExtensionMethodFinderTests).GetMethods().Where(x => x.Name == "TestMethod6"); - Assert.AreEqual(2, ms.Count()); - } - - #endregion - - #region Tests Set #2 - Working with Generics - - // To expand on Jon's answer, the reason this doesn't work is because in regular, - // non-dynamic code extension methods work by doing a full search of all the - // classes known to the compiler for a static class that has an extension method - // that match. The search goes in order based on the namespace nesting and available - // "using" directives in each namespace. - // - // That means that in order to get a dynamic extension method invocation resolved - // correctly, somehow the DLR has to know at runtime what all the namespace nestings - // and "using" directives were in your source code. We do not have a mechanism handy - // for encoding all that information into the call site. We considered inventing - // such a mechanism, but decided that it was too high cost and produced too much - // schedule risk to be worth it. - // - // Eric Lippert, http://stackoverflow.com/questions/5311465/extension-method-and-dynamic-object-in-c-sharp - // - // And so... - // Obviously MatchType is broken and incomplete, it does not handle - // - ref & out parameters - // - array types - // - structs - // - generics constraints - // - generics variance - // - ... - - [Test] - public void Temp() - { - var t1 = typeof (IList); - var t2 = typeof (IList<>); - Assert.IsTrue(t2.IsGenericTypeDefinition); - Assert.AreEqual(t2, t1.GetGenericTypeDefinition()); - var m = typeof (ExtensionMethodFinderTests).GetMethod("TestMethod7"); - var parms = m.GetParameters(); - Assert.AreEqual(1, parms.Length); - var parm = parms[0]; - var t3 = parm.ParameterType; // IList - Assert.AreEqual(t2, t3.GetGenericTypeDefinition()); - - Assert.AreEqual(typeof (int), t1.GetGenericArguments()[0]); - Assert.IsFalse(t1.GetGenericArguments()[0].IsGenericParameter); - //Assert.AreEqual(???, t2.GetGenericArguments()[0]); - Assert.IsTrue(t2.GetGenericArguments()[0].IsGenericParameter); - Assert.AreEqual("T", t2.GetGenericArguments()[0].Name); - Assert.IsTrue(t3.GetGenericArguments()[0].IsGenericParameter); - Assert.AreEqual("T", t3.GetGenericArguments()[0].Name); - } - - - - [Test] - public void Find_Generic_Enumerable_Method() - { - MethodInfo method; - var class1 = Enumerable.Empty(); - - method = ExtensionMethodFinder.FindExtensionMethod(new NullCacheProvider(), typeof(IEnumerable), new object[] { }, "GenericMethod", false); - Assert.IsNotNull(method); - method.Invoke(null, new object[] { class1 }); - - var class2 = new TestClassCollection(); - - method = ExtensionMethodFinder.FindExtensionMethod(new NullCacheProvider(), typeof(TestClassCollection), new object[] { }, "GenericMethod", false); - Assert.IsNotNull(method); - method.Invoke(null, new object[] { class2 }); - } - - [Ignore("This is just testing the below GetMethodForArguments method - Stephen was working on this but it's not used in the core")] - [Test] - public void TypesTests() - { - Assert.IsTrue(typeof(int[]).Inherits()); - Assert.IsFalse(typeof(int[]).Inherits()); - - var m1 = typeof(ExtensionMethodFinderTests).GetMethod("TestMethod1"); - - var a1A = new object[] { 1 }; - var m1A = GetMethodForArguments(m1, a1A); - Assert.IsNotNull(m1A); - m1A.Invoke(this, a1A); - - var a1B = new object[] { "foo" }; - var m1B = GetMethodForArguments(m1, a1B); - Assert.IsNull(m1B); - - var m2 = typeof(ExtensionMethodFinderTests).GetMethod("TestMethod2"); - - var m2A = GetMethodForArguments(m2, a1A); - Assert.IsNotNull(m2A); - m2A.Invoke(this, a1A); - - var m2B = GetMethodForArguments(m2, a1B); - Assert.IsNotNull(m2B); - m2B.Invoke(this, a1B); - - var m3 = typeof(ExtensionMethodFinderTests).GetMethod("TestMethod3"); - - var a3A = new object[] { 1, 2 }; - var m3A = GetMethodForArguments(m3, a3A); - Assert.IsNotNull(m3A); - m3A.Invoke(this, a3A); - - var a3B = new object[] { 1, "foo" }; - var m3B = GetMethodForArguments(m3, a3B); - Assert.IsNull(m3B); - - var m4 = typeof(ExtensionMethodFinderTests).GetMethod("TestMethod4"); - - var m4A = GetMethodForArguments(m4, a3A); - Assert.IsNotNull(m4A); - m4A.Invoke(this, a3A); - - var m4B = GetMethodForArguments(m4, a3B); - Assert.IsNotNull(m4B); - m4B.Invoke(this, a3B); - - var m5 = typeof(ExtensionMethodFinderTests).GetMethod("TestMethod5"); - - // note - currently that fails because we can't match List with List - var a5 = new object[] { new List() }; - var m5A = GetMethodForArguments(m5, a5); - Assert.IsNotNull(m5A); - - // note - should we also handle "ref" and "out" parameters? - // SD: NO, lets not make this more complicated than it already is - // note - should we pay attention to array types? - // SD: NO, lets not make this more complicated than it already is - } - - // gets the method that can apply to the arguments - // either the method itself, or a generic one - // or null if it couldn't match - // - // this is a nightmare - if we want to do it right, then we have - // to re-do the whole compiler type inference stuff by ourselves?! - // - static MethodInfo GetMethodForArguments(MethodInfo method, IList arguments) - { - var parameters = method.GetParameters(); - var genericArguments = method.GetGenericArguments(); - - if (parameters.Length != arguments.Count) return null; - - var genericArgumentTypes = new Type[genericArguments.Length]; - var i = 0; - for (; i < parameters.Length; i++) - { - var parameterType = parameters[i].ParameterType; - var argumentType = arguments[i].GetType(); - - Debug.Print("{0} / {1}", parameterType, argumentType); - - if (parameterType == argumentType) continue; // match - if (parameterType.IsGenericParameter) // eg T - { - var pos = parameterType.GenericParameterPosition; - if (genericArgumentTypes[pos] != null) - { - // note - is this OK? what about variance and such? - // it is NOT ok, if the first pass is SomethingElse then next is Something - // it will fail... the specs prob. indicate how it works, trying to find a common - // type... - if (genericArgumentTypes[pos].IsAssignableFrom(argumentType) == false) - break; - } - else - { - genericArgumentTypes[pos] = argumentType; - } - } - else if (parameterType.IsGenericType) // eg List - { - if (argumentType.IsGenericType == false) break; - - var pg = parameterType.GetGenericArguments(); - var ag = argumentType.GetGenericArguments(); - - // then what ?! - // should _variance_ be of some importance? - Debug.Print("generic {0}", argumentType.IsGenericType); - } - else - { - if (parameterType.IsAssignableFrom(argumentType) == false) - break; - } - } - if (i != parameters.Length) return null; - return genericArguments.Length == 0 - ? method - : method.MakeGenericMethod(genericArgumentTypes); - } - - #endregion - - public class TestClassCollection : List - { - - } - - } - - #region Tests Elements - - - static class ExtensionMethodFinderTestsExtensions - { - public static void GenericMethod(this IEnumerable source) - { } - - public static void SimpleMethod(this ExtensionMethodFinderTests.TestClass source, int value) - { } - - public static void SimpleOverloadMethod(this ExtensionMethodFinderTests.TestClass source, int value) - { } - - public static void SimpleOverloadMethod(this ExtensionMethodFinderTests.TestClass source, string value) - { } - - public static void SimpleEnumerableGenericMethod(this IEnumerable source, int value) - { } - - public static void SimpleOverloadEnumerableGenericMethod(this IEnumerable source, int value) - { } - - public static void SimpleOverloadEnumerableGenericMethod(this IEnumerable source, string value) - { } - - public static void GenericParameterMethod(this ExtensionMethodFinderTests.TestClass source, ExtensionMethodFinderTests.TestClass value) - { } - - public static void GenericMethod(this ExtensionMethodFinderTests.TestClass source) - { } - } - - #endregion -} diff --git a/src/Umbraco.Tests/DynamicsAndReflection/QueryableExtensionTests.cs b/src/Umbraco.Tests/DynamicsAndReflection/QueryableExtensionTests.cs deleted file mode 100644 index c2544421a0..0000000000 --- a/src/Umbraco.Tests/DynamicsAndReflection/QueryableExtensionTests.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using NUnit.Framework; -using Umbraco.Core.Dynamics; -using Umbraco.Web.Dynamics; - -namespace Umbraco.Tests.DynamicsAndReflection -{ - //NOTE: there's libraries in both Umbraco.Core.Dynamics and Umbraco.Web.Dynamics - the reason for this is that the Web.Dynamics - // started with the razor macro implementation and is modified with hard coded references to dynamic node and dynamic null, though it seems - // to still work for other regular classes I don't want to move it to the core without removing these references but that would require a lot of work. - - [TestFixture] - public class QueryableExtensionTests - { - - [Test] - public void Order_By_Test_Int() - { - var items = new List - { - new TestModel {Age = 10, Name = "test1", Female = false}, - new TestModel {Age = 31, Name = "someguy", Female = true}, - new TestModel {Age = 11, Name = "test2", Female = true}, - new TestModel {Age = 20, Name = "anothertest", Female = false}, - new TestModel {Age = 55, Name = "blah", Female = false}, - new TestModel {Age = 12, Name = "test3", Female = false} - }; - - var result = items.AsQueryable().OrderBy("Age").ToArray(); - - Assert.AreEqual(10, result.ElementAt(0).Age); - Assert.AreEqual(11, result.ElementAt(1).Age); - Assert.AreEqual(12, result.ElementAt(2).Age); - Assert.AreEqual(20, result.ElementAt(3).Age); - Assert.AreEqual(31, result.ElementAt(4).Age); - Assert.AreEqual(55, result.ElementAt(5).Age); - - } - - [Test] - public void Order_By_Test_String() - { - var items = new List - { - new TestModel {Age = 10, Name = "test1", Female = false}, - new TestModel {Age = 31, Name = "someguy", Female = true}, - new TestModel {Age = 11, Name = "test2", Female = true}, - new TestModel {Age = 20, Name = "anothertest", Female = false}, - new TestModel {Age = 55, Name = "blah", Female = false}, - new TestModel {Age = 12, Name = "test3", Female = false} - }; - - var result = items.AsQueryable().OrderBy("Name").ToArray(); - - Assert.AreEqual("anothertest", result.ElementAt(0).Name); - Assert.AreEqual("blah", result.ElementAt(1).Name); - Assert.AreEqual("someguy", result.ElementAt(2).Name); - Assert.AreEqual("test1", result.ElementAt(3).Name); - Assert.AreEqual("test2", result.ElementAt(4).Name); - Assert.AreEqual("test3", result.ElementAt(5).Name); - - } - - [Test] - public void Where_Test_String() - { - var items = new List - { - new TestModel {Age = 10, Name = "test1", Female = false}, - new TestModel {Age = 31, Name = "someguy", Female = true}, - new TestModel {Age = 11, Name = "test2", Female = true}, - new TestModel {Age = 20, Name = "anothertest", Female = false}, - new TestModel {Age = 55, Name = "blah", Female = false}, - new TestModel {Age = 12, Name = "test3", Female = false} - }; - - var result = items.AsQueryable().Where("Name = \"test1\"").ToArray(); - - Assert.AreEqual(1, result.Count()); - Assert.AreEqual("test1", result.ElementAt(0).Name); - - - } - - [Test] - public void Where_Test_String_With_Params() - { - var items = new List - { - new TestModel {Age = 10, Name = "test1", Female = false}, - new TestModel {Age = 31, Name = "someguy", Female = true}, - new TestModel {Age = 11, Name = "test2", Female = true}, - new TestModel {Age = 20, Name = "anothertest", Female = false}, - new TestModel {Age = 55, Name = "blah", Female = false}, - new TestModel {Age = 12, Name = "test3", Female = false} - }; - - //NOTE: Currently the object query structure is not supported - //var result = items.AsQueryable().Where("Name = @name", new {name = "test1"}).ToArray(); - var result = items.AsQueryable().Where("Name = @Name", new Dictionary { { "Name", "test1" } }).ToArray(); - - Assert.AreEqual(1, result.Count()); - Assert.AreEqual("test1", result.ElementAt(0).Name); - - - } - - [Test] - public void Where_Test_Int_With_Params() - { - var items = new List - { - new TestModel {Age = 10, Name = "test1", Female = false}, - new TestModel {Age = 31, Name = "someguy", Female = true}, - new TestModel {Age = 11, Name = "test2", Female = true}, - new TestModel {Age = 20, Name = "anothertest", Female = false}, - new TestModel {Age = 55, Name = "blah", Female = false}, - new TestModel {Age = 12, Name = "test3", Female = false} - }; - - var result = items.AsQueryable().Where("Age = @Age", new Dictionary { { "Age", 10 } }).ToArray(); - - Assert.AreEqual(1, result.Count()); - Assert.AreEqual("test1", result.ElementAt(0).Name); - - - } - - [Test] - public void Where_Test_Bool_With_Params() - { - var items = new List - { - new TestModel {Age = 10, Name = "test1", Female = false}, - new TestModel {Age = 31, Name = "someguy", Female = true}, - new TestModel {Age = 11, Name = "test2", Female = true}, - new TestModel {Age = 20, Name = "anothertest", Female = false}, - new TestModel {Age = 55, Name = "blah", Female = false}, - new TestModel {Age = 12, Name = "test3", Female = false} - }; - - var result = items.AsQueryable().Where("Female = @Female", new Dictionary { { "Female", true } }).ToArray(); - - Assert.AreEqual(2, result.Count()); - - - } - - private class TestModel - { - public string Name { get; set; } - public int Age { get; set; } - public bool Female { get; set; } - } - - } -} diff --git a/src/Umbraco.Tests/Membership/DynamicMemberContentTests.cs b/src/Umbraco.Tests/Membership/DynamicMemberContentTests.cs deleted file mode 100644 index a93359bd68..0000000000 --- a/src/Umbraco.Tests/Membership/DynamicMemberContentTests.cs +++ /dev/null @@ -1,178 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Web.Security; -using Lucene.Net.Util; -using Moq; -using NUnit.Framework; -using Umbraco.Core.Models; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Tests.PublishedContent; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; -using Umbraco.Web; -using Umbraco.Web.Models; -using Umbraco.Web.PublishedCache; - -namespace Umbraco.Tests.Membership -{ - [DatabaseTestBehavior(DatabaseBehavior.NoDatabasePerFixture)] - [TestFixture] - public class DynamicMemberContentTests : PublishedContentTestBase - { - - public override void Initialize() - { - // required so we can access property.Value - //PropertyValueConvertersResolver.Current = new PropertyValueConvertersResolver(); - - base.Initialize(); - - // need to specify a custom callback for unit tests - // AutoPublishedContentTypes generates properties automatically - // when they are requested, but we must declare those that we - // explicitely want to be here... - - var propertyTypes = new[] - { - // AutoPublishedContentType will auto-generate other properties - new PublishedPropertyType("title", 0, "?"), - new PublishedPropertyType("bodyText", 0, "?"), - new PublishedPropertyType("author", 0, "?") - }; - var type = new AutoPublishedContentType(0, "anything", propertyTypes); - ContentTypesCache.GetPublishedContentTypeByAlias = (alias) => type; - } - - [Test] - public void Can_Get_Built_In_Properties() - { - var date = DateTime.Now; - - var member = new Member("test name", "test@email.com", "test username", "test password", - GetMemberType()); - member.Comments = "test comment"; - member.IsApproved = true; - member.IsLockedOut = false; - member.CreateDate = date; - member.LastLoginDate = date.AddMinutes(1); - member.LastLockoutDate = date.AddMinutes(2); - //NOTE: Last activity date is always the same as last login date since we don't have a place to store that data - //member.LastLoginDate = date.AddMinutes(3); - member.LastPasswordChangeDate = date.AddMinutes(4); - member.PasswordQuestion = "test question"; - - var mpt = ContentTypesCache.Get(PublishedItemType.Member, member.ContentTypeAlias); - var mpc = new PublishedMember(member, mpt); - - var d = mpc.AsDynamic(); - - Assert.AreEqual("test comment", d.Comments); - Assert.AreEqual(date, d.CreationDate); - Assert.AreEqual("test@email.com", d.Email); - Assert.AreEqual(true, d.IsApproved); - Assert.AreEqual(false, d.IsLockedOut); - Assert.AreEqual(date.AddMinutes(1), d.LastActivityDate); - Assert.AreEqual(date.AddMinutes(2), d.LastLockoutDate); - Assert.AreEqual(date.AddMinutes(1), d.LastLoginDate); - Assert.AreEqual(date.AddMinutes(4), d.LastPasswordChangeDate); - Assert.AreEqual("test name", d.Name); - Assert.AreEqual("test question", d.PasswordQuestion); - Assert.AreEqual("test username", d.UserName); - - } - - [Test] - public void Can_Get_Built_In_Properties_Camel_Case() - { - var date = DateTime.Now; - - var member = new Member("test name", "test@email.com", "test username", "test password", - GetMemberType()); - member.Comments = "test comment"; - member.IsApproved = true; - member.IsLockedOut = false; - member.CreateDate = date; - member.LastLoginDate = date.AddMinutes(1); - member.LastLockoutDate = date.AddMinutes(2); - //NOTE: Last activity date is always the same as last login date since we don't have a place to store that data - //member.LastLoginDate = date.AddMinutes(3); - member.LastPasswordChangeDate = date.AddMinutes(4); - member.PasswordQuestion = "test question"; - - var mpt = ContentTypesCache.Get(PublishedItemType.Member, member.ContentTypeAlias); - var mpc = new PublishedMember(member, mpt); - - var d = mpc.AsDynamic(); - - Assert.AreEqual("test comment", d.comments); - Assert.AreEqual(date, d.creationDate); - Assert.AreEqual("test@email.com", d.email); - Assert.AreEqual(true, d.isApproved); - Assert.AreEqual(false, d.isLockedOut); - Assert.AreEqual(date.AddMinutes(1), d.lastActivityDate); - Assert.AreEqual(date.AddMinutes(2), d.lastLockoutDate); - Assert.AreEqual(date.AddMinutes(1), d.lastLoginDate); - Assert.AreEqual(date.AddMinutes(4), d.lastPasswordChangeDate); - Assert.AreEqual("test name", d.name); - Assert.AreEqual("test question", d.passwordQuestion); - Assert.AreEqual("test username", d.userName); - - } - - [Test] - public void Can_Get_Custom_Properties() - { - var date = DateTime.Now; - - var memberType = MockedContentTypes.CreateSimpleMemberType("Member", "Member"); - var member = MockedMember.CreateSimpleMember(memberType, "test name", "test@email.com", "test password", "test username"); - member.Comments = "test comment"; - member.IsApproved = true; - member.IsLockedOut = false; - member.CreateDate = date; - member.LastLoginDate = date.AddMinutes(1); - member.LastLockoutDate = date.AddMinutes(2); - //NOTE: Last activity date is always the same as last login date since we don't have a place to store that data - //member.LastLoginDate = date.AddMinutes(3); - member.LastPasswordChangeDate = date.AddMinutes(4); - member.PasswordQuestion = "test question"; - - member.Properties["title"].Value = "Test Value 1"; - member.Properties["bodyText"].Value = "Test Value 2"; - member.Properties["author"].Value = "Test Value 3"; - - var mpt = ContentTypesCache.Get(PublishedItemType.Member, member.ContentTypeAlias); - var mpc = new PublishedMember(member, mpt); - - var d = mpc.AsDynamic(); - - Assert.AreEqual("Test Value 1", d.title); - Assert.AreEqual("Test Value 1", d.Title); - Assert.AreEqual("Test Value 2", d.bodyText); - Assert.AreEqual("Test Value 2", d.BodyText); - Assert.AreEqual("Test Value 3", d.author); - Assert.AreEqual("Test Value 3", d.Author); - - - } - - private IMemberType GetMemberType() - { - var entity = new MemberType(-1) - { - Alias = "Member" - }; - - entity.AddPropertyGroup(Umbraco.Core.Constants.Conventions.Member.StandardPropertiesGroupName); - var standardPropertyTypes = Umbraco.Core.Constants.Conventions.Member.GetStandardPropertyTypeStubs(); - foreach (var standardPropertyType in standardPropertyTypes) - { - entity.AddPropertyType(standardPropertyType.Value, Umbraco.Core.Constants.Conventions.Member.StandardPropertiesGroupName); - } - return entity; - } - - } -} diff --git a/src/Umbraco.Tests/MockTests.cs b/src/Umbraco.Tests/MockTests.cs index 275678d8da..ba9ee113e3 100644 --- a/src/Umbraco.Tests/MockTests.cs +++ b/src/Umbraco.Tests/MockTests.cs @@ -147,7 +147,6 @@ namespace Umbraco.Tests var helper = new UmbracoHelper(umbCtx, Mock.Of(), Mock.Of(), - Mock.Of(), Mock.Of(), Mock.Of(), new UrlProvider(umbCtx, new[] {Mock.Of()}, UrlProviderMode.Auto), Mock.Of(), @@ -184,7 +183,6 @@ namespace Umbraco.Tests var helper = new UmbracoHelper(umbCtx, Mock.Of(), Mock.Of(), - Mock.Of(), Mock.Of(), Mock.Of(), new UrlProvider(umbCtx, new[] diff --git a/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs b/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs index 51651ad575..95857085d4 100644 --- a/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs +++ b/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs @@ -1,5 +1,4 @@ -using System; -using System.Globalization; +using System.Globalization; using System.Linq; using LightInject; using Moq; @@ -14,7 +13,6 @@ using Umbraco.Core.ObjectResolution; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Web.Models; -using Umbraco.Web.PropertyEditors; using Umbraco.Web; namespace Umbraco.Tests.PropertyEditors @@ -22,94 +20,16 @@ namespace Umbraco.Tests.PropertyEditors [TestFixture] public class ImageCropperTest { - private const string cropperJson1 = "{\"focalPoint\": {\"left\": 0.96,\"top\": 0.80827067669172936},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\":\"thumb\",\"width\": 100,\"height\": 100,\"coordinates\": {\"x1\": 0.58729977382575338,\"y1\": 0.055768992440203169,\"x2\": 0,\"y2\": 0.32457553600198386}}]}"; - private const string cropperJson2 = "{\"focalPoint\": {\"left\": 0.98,\"top\": 0.80827067669172936},\"src\": \"/media/1005/img_0672.jpg\",\"crops\": [{\"alias\":\"thumb\",\"width\": 100,\"height\": 100,\"coordinates\": {\"x1\": 0.58729977382575338,\"y1\": 0.055768992440203169,\"x2\": 0,\"y2\": 0.32457553600198386}}]}"; - private const string cropperJson3 = "{\"focalPoint\": {\"left\": 0.98,\"top\": 0.80827067669172936},\"src\": \"/media/1005/img_0672.jpg\",\"crops\": []}"; - private const string mediaPath = "/media/1005/img_0671.jpg"; - - [Test] - public void ImageCropData_Properties_As_Dynamic() - { - var sourceObj = cropperJson1.SerializeToCropDataSet(); - dynamic d = sourceObj; - - var index = 0; - foreach (var crop in d.crops) - { - var realObjCrop = sourceObj.Crops.ElementAt(index); - Assert.AreEqual(realObjCrop.Alias, crop.Alias); - Assert.AreEqual(realObjCrop.Alias, crop.alias); - - Assert.AreEqual(realObjCrop.Height, crop.Height); - Assert.AreEqual(realObjCrop.Height, crop.height); - - Assert.AreEqual(realObjCrop.Coordinates.X1, crop.Coordinates.X1); - Assert.AreEqual(realObjCrop.Coordinates.X1, crop.coordinates.x1); - - Assert.AreEqual(realObjCrop.Coordinates.X2, crop.Coordinates.X2); - Assert.AreEqual(realObjCrop.Coordinates.X2, crop.coordinates.x2); - - Assert.AreEqual(realObjCrop.Coordinates.Y1, crop.Coordinates.Y1); - Assert.AreEqual(realObjCrop.Coordinates.Y1, crop.coordinates.y1); - - Assert.AreEqual(realObjCrop.Coordinates.Y2, crop.Coordinates.Y2); - Assert.AreEqual(realObjCrop.Coordinates.Y2, crop.coordinates.y2); - index++; - } - - Assert.AreEqual(index, 1); - } - - [Test] - public void ImageCropFocalPoint_Properties_As_Dynamic() - { - var sourceObj = cropperJson1.SerializeToCropDataSet(); - dynamic d = sourceObj; - - Assert.AreEqual(sourceObj.FocalPoint.Left, d.FocalPoint.Left); - Assert.AreEqual(sourceObj.FocalPoint.Left, d.focalPoint.left); - - Assert.AreEqual(sourceObj.FocalPoint.Top, d.FocalPoint.Top); - Assert.AreEqual(sourceObj.FocalPoint.Top, d.focalPoint.top); - } - - [Test] - public void ImageCropDataSet_Properties_As_Dynamic() - { - var sourceObj = cropperJson1.SerializeToCropDataSet(); - dynamic d = sourceObj; - - Assert.AreEqual(sourceObj.Src, d.Src); - Assert.AreEqual(sourceObj.Src, d.src); - - Assert.AreEqual(sourceObj.FocalPoint, d.FocalPoint); - Assert.AreEqual(sourceObj.FocalPoint, d.focalPoint); - - Assert.AreEqual(sourceObj.Crops, d.Crops); - Assert.AreEqual(sourceObj.Crops, d.crops); - } - - [Test] - public void ImageCropDataSet_Methods_As_Dynamic() - { - var sourceObj = cropperJson1.SerializeToCropDataSet(); - dynamic d = sourceObj; - - Assert.AreEqual(sourceObj.HasCrop("thumb"), d.HasCrop("thumb")); - Assert.AreEqual(sourceObj.HasCrop("thumb"), d.hasCrop("thumb")); - - Assert.AreEqual(sourceObj.GetCropUrl("thumb"), d.GetCropUrl("thumb")); - Assert.AreEqual(sourceObj.GetCropUrl("thumb"), d.getCropUrl("thumb")); - - Assert.AreEqual(sourceObj.HasFocalPoint(), d.HasFocalPoint()); - Assert.AreEqual(sourceObj.HasFocalPoint(), d.hasFocalPoint()); - } + private const string CropperJson1 = "{\"focalPoint\": {\"left\": 0.96,\"top\": 0.80827067669172936},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\":\"thumb\",\"width\": 100,\"height\": 100,\"coordinates\": {\"x1\": 0.58729977382575338,\"y1\": 0.055768992440203169,\"x2\": 0,\"y2\": 0.32457553600198386}}]}"; + private const string CropperJson2 = "{\"focalPoint\": {\"left\": 0.98,\"top\": 0.80827067669172936},\"src\": \"/media/1005/img_0672.jpg\",\"crops\": [{\"alias\":\"thumb\",\"width\": 100,\"height\": 100,\"coordinates\": {\"x1\": 0.58729977382575338,\"y1\": 0.055768992440203169,\"x2\": 0,\"y2\": 0.32457553600198386}}]}"; + private const string CropperJson3 = "{\"focalPoint\": {\"left\": 0.98,\"top\": 0.80827067669172936},\"src\": \"/media/1005/img_0672.jpg\",\"crops\": []}"; + private const string MediaPath = "/media/1005/img_0671.jpg"; [Test] public void CanConvertImageCropperDataSetSrcToString() { //cropperJson3 - has not crops - var sourceObj = cropperJson3.SerializeToCropDataSet(); + var sourceObj = CropperJson3.SerializeToCropDataSet(); var destObj = sourceObj.TryConvertTo(); Assert.IsTrue(destObj.Success); Assert.AreEqual(destObj.Result, "/media/1005/img_0672.jpg"); @@ -119,7 +39,7 @@ namespace Umbraco.Tests.PropertyEditors public void CanConvertImageCropperDataSetJObject() { //cropperJson3 - has not crops - var sourceObj = cropperJson3.SerializeToCropDataSet(); + var sourceObj = CropperJson3.SerializeToCropDataSet(); var destObj = sourceObj.TryConvertTo(); Assert.IsTrue(destObj.Success); Assert.AreEqual(sourceObj, destObj.Result.ToObject()); @@ -128,16 +48,16 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void CanConvertImageCropperDataSetJsonToString() { - var sourceObj = cropperJson1.SerializeToCropDataSet(); + var sourceObj = CropperJson1.SerializeToCropDataSet(); var destObj = sourceObj.TryConvertTo(); Assert.IsTrue(destObj.Success); Assert.IsTrue(destObj.Result.DetectIsJson()); - var obj = JsonConvert.DeserializeObject(cropperJson1, new JsonSerializerSettings {Culture = CultureInfo.InvariantCulture, FloatParseHandling = FloatParseHandling.Decimal}); + var obj = JsonConvert.DeserializeObject(CropperJson1, new JsonSerializerSettings {Culture = CultureInfo.InvariantCulture, FloatParseHandling = FloatParseHandling.Decimal}); Assert.AreEqual(sourceObj, obj); } - [TestCase(cropperJson1, cropperJson1, true)] - [TestCase(cropperJson1, cropperJson2, false)] + [TestCase(CropperJson1, CropperJson1, true)] + [TestCase(CropperJson1, CropperJson2, false)] public void CanConvertImageCropperPropertyEditor(string val1, string val2, bool expected) { try @@ -163,15 +83,15 @@ namespace Umbraco.Tests.PropertyEditors } finally { - PropertyValueConvertersResolver.Reset(true); + PropertyValueConvertersResolver.Reset(/*true*/); } } [Test] public void GetCropUrl_CropAliasTest() { - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, cropAlias: "Thumb", useCropDimensions: true); - Assert.AreEqual(mediaPath + "?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true); + Assert.AreEqual(MediaPath + "?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString); } /// @@ -180,29 +100,29 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetCropUrl_CropAliasIgnoreWidthHeightTest() { - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, cropAlias: "Thumb", useCropDimensions: true, width: 50, height: 50); - Assert.AreEqual(mediaPath + "?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true, width: 50, height: 50); + Assert.AreEqual(MediaPath + "?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString); } [Test] public void GetCropUrl_WidthHeightTest() { - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, width: 200, height: 300); - Assert.AreEqual(mediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=200&height=300", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 200, height: 300); + Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=200&height=300", urlString); } [Test] public void GetCropUrl_FocalPointTest() { - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, cropAlias: "thumb", preferFocalPoint: true, useCropDimensions: true); - Assert.AreEqual(mediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=100&height=100", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, cropAlias: "thumb", preferFocalPoint: true, useCropDimensions: true); + Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=100&height=100", urlString); } [Test] public void GetCropUrlFurtherOptionsTest() { - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, width: 200, height: 300, furtherOptions: "&filter=comic&roundedcorners=radius-26|bgcolor-fff"); - Assert.AreEqual(mediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=200&height=300&filter=comic&roundedcorners=radius-26|bgcolor-fff", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 200, height: 300, furtherOptions: "&filter=comic&roundedcorners=radius-26|bgcolor-fff"); + Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=200&height=300&filter=comic&roundedcorners=radius-26|bgcolor-fff", urlString); } /// @@ -211,7 +131,7 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetCropUrlNullTest() { - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, cropAlias: "Banner", useCropDimensions: true); + var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, cropAlias: "Banner", useCropDimensions: true); Assert.AreEqual(null, urlString); } @@ -221,7 +141,7 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetBaseCropUrlFromModelTest() { - var cropDataSet = cropperJson1.SerializeToCropDataSet(); + var cropDataSet = CropperJson1.SerializeToCropDataSet(); var urlString = cropDataSet.GetCropUrl("thumb"); Assert.AreEqual("?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString); } @@ -232,8 +152,8 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetCropUrl_CropAliasHeightRatioModeTest() { - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, cropAlias: "Thumb", useCropDimensions: true, ratioMode:ImageCropRatioMode.Height); - Assert.AreEqual(mediaPath + "?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&heightratio=1", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true, ratioMode:ImageCropRatioMode.Height); + Assert.AreEqual(MediaPath + "?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&heightratio=1", urlString); } /// @@ -242,8 +162,8 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetCropUrl_WidthHeightRatioModeTest() { - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, width: 300, height: 150, ratioMode:ImageCropRatioMode.Height); - Assert.AreEqual(mediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=300&heightratio=0.5", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 300, height: 150, ratioMode:ImageCropRatioMode.Height); + Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=300&heightratio=0.5", urlString); } /// @@ -252,8 +172,8 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetCropUrl_HeightWidthRatioModeTest() { - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, width: 300, height: 150, ratioMode: ImageCropRatioMode.Width); - Assert.AreEqual(mediaPath + "?center=0.80827067669172936,0.96&mode=crop&height=150&widthratio=2", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 300, height: 150, ratioMode: ImageCropRatioMode.Width); + Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&height=150&widthratio=2", urlString); } /// @@ -262,8 +182,8 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetCropUrl_SpecifiedCropModeTest() { - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, width: 300, height: 150, imageCropMode:ImageCropMode.Max); - Assert.AreEqual(mediaPath + "?mode=max&width=300&height=150", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode:ImageCropMode.Max); + Assert.AreEqual(MediaPath + "?mode=max&width=300&height=150", urlString); } /// @@ -272,8 +192,8 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetCropUrl_UploadTypeTest() { - var urlString = mediaPath.GetCropUrl(width: 100, height: 270, imageCropMode: ImageCropMode.Crop, imageCropAnchor: ImageCropAnchor.Center); - Assert.AreEqual(mediaPath + "?mode=crop&anchor=center&width=100&height=270", urlString); + var urlString = MediaPath.GetCropUrl(width: 100, height: 270, imageCropMode: ImageCropMode.Crop, imageCropAnchor: ImageCropAnchor.Center); + Assert.AreEqual(MediaPath + "?mode=crop&anchor=center&width=100&height=270", urlString); } /// @@ -282,10 +202,10 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetCropUrl_PreferFocalPointCenter() { - var cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\":\"thumb\",\"width\": 100,\"height\": 100,\"coordinates\": {\"x1\": 0.58729977382575338,\"y1\": 0.055768992440203169,\"x2\": 0,\"y2\": 0.32457553600198386}}]}"; + const string cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\":\"thumb\",\"width\": 100,\"height\": 100,\"coordinates\": {\"x1\": 0.58729977382575338,\"y1\": 0.055768992440203169,\"x2\": 0,\"y2\": 0.32457553600198386}}]}"; - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson, width: 300, height: 150, preferFocalPoint:true); - Assert.AreEqual(mediaPath + "?anchor=center&mode=crop&width=300&height=150", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: cropperJson, width: 300, height: 150, preferFocalPoint:true); + Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&width=300&height=150", urlString); } /// @@ -294,10 +214,10 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetCropUrl_PreDefinedCropNoCoordinatesWithWidth() { - var cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}"; + const string cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}"; - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson, cropAlias: "home", width: 200); - Assert.AreEqual(mediaPath + "?anchor=center&mode=crop&heightratio=0.5962962962962962962962962963&width=200", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: cropperJson, cropAlias: "home", width: 200); + Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&heightratio=0.5962962962962962962962962963&width=200", urlString); } /// @@ -306,10 +226,10 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetCropUrl_PreDefinedCropNoCoordinatesWithWidthAndFocalPoint() { - var cropperJson = "{\"focalPoint\": {\"left\": 0.4275,\"top\": 0.41},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}"; + const string cropperJson = "{\"focalPoint\": {\"left\": 0.4275,\"top\": 0.41},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}"; - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson, cropAlias: "home", width: 200); - Assert.AreEqual(mediaPath + "?center=0.41,0.4275&mode=crop&heightratio=0.5962962962962962962962962963&width=200", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: cropperJson, cropAlias: "home", width: 200); + Assert.AreEqual(MediaPath + "?center=0.41,0.4275&mode=crop&heightratio=0.5962962962962962962962962963&width=200", urlString); } /// @@ -318,10 +238,10 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetCropUrl_PreDefinedCropNoCoordinatesWithWidthAndFocalPointIgnore() { - var cropperJson = "{\"focalPoint\": {\"left\": 0.4275,\"top\": 0.41},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}"; + const string cropperJson = "{\"focalPoint\": {\"left\": 0.4275,\"top\": 0.41},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}"; - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson, cropAlias: "home", width: 200, useCropDimensions: true); - Assert.AreEqual(mediaPath + "?center=0.41,0.4275&mode=crop&width=270&height=161", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: cropperJson, cropAlias: "home", width: 200, useCropDimensions: true); + Assert.AreEqual(MediaPath + "?center=0.41,0.4275&mode=crop&width=270&height=161", urlString); } /// @@ -330,10 +250,10 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetCropUrl_PreDefinedCropNoCoordinatesWithHeight() { - var cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}"; + const string cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}"; - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson, cropAlias: "home", height: 200); - Assert.AreEqual(mediaPath + "?anchor=center&mode=crop&widthratio=1.6770186335403726708074534161&height=200", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: cropperJson, cropAlias: "home", height: 200); + Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&widthratio=1.6770186335403726708074534161&height=200", urlString); } /// @@ -342,10 +262,10 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetCropUrl_WidthOnlyParameter() { - var cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}"; + const string cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}"; - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson, width: 200); - Assert.AreEqual(mediaPath + "?anchor=center&mode=crop&width=200", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: cropperJson, width: 200); + Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&width=200", urlString); } /// @@ -354,10 +274,10 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void GetCropUrl_HeightOnlyParameter() { - var cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}"; + const string cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}"; - var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson, height: 200); - Assert.AreEqual(mediaPath + "?anchor=center&mode=crop&height=200", urlString); + var urlString = MediaPath.GetCropUrl(imageCropperValue: cropperJson, height: 200); + Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&height=200", urlString); } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/PublishedContent/DynamicDocumentTestsBase.cs b/src/Umbraco.Tests/PublishedContent/DynamicDocumentTestsBase.cs deleted file mode 100644 index 7e4cf93980..0000000000 --- a/src/Umbraco.Tests/PublishedContent/DynamicDocumentTestsBase.cs +++ /dev/null @@ -1,601 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using Moq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Dynamics; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Plugins; -using Umbraco.Core.PropertyEditors; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests.PublishedContent -{ - [TestFixture] - public abstract class DynamicDocumentTestsBase : PublishedContentTestBase - { - private IUmbracoSettingsSection _umbracoSettings; - - public override void Initialize() - { - // required so we can access property.Value - //PropertyValueConvertersResolver.Current = new PropertyValueConvertersResolver(); - - base.Initialize(); - - //generate new mock settings and assign so we can configure in individual tests - _umbracoSettings = SettingsForTests.GenerateMockSettings(); - SettingsForTests.ConfigureSettings(_umbracoSettings); - - // need to specify a custom callback for unit tests - // AutoPublishedContentTypes generates properties automatically - // when they are requested, but we must declare those that we - // explicitely want to be here... - - var propertyTypes = new[] - { - // AutoPublishedContentType will auto-generate other properties - new PublishedPropertyType("umbracoNaviHide", 0, "?"), - new PublishedPropertyType("selectedNodes", 0, "?"), - new PublishedPropertyType("umbracoUrlAlias", 0, "?"), - new PublishedPropertyType("content", 0, Constants.PropertyEditors.TinyMCEAlias), - new PublishedPropertyType("testRecursive", 0, "?"), - new PublishedPropertyType("siteTitle", 0, "?"), - new PublishedPropertyType("creatorName", 0, "?"), - new PublishedPropertyType("blah", 0, "?"), // ugly error when that one is missing... - }; - var type = new AutoPublishedContentType(0, "anything", propertyTypes); - ContentTypesCache.GetPublishedContentTypeByAlias = (alias) => type; - - } - - protected override string GetXmlContent(int templateId) - { - return @" - - - - -]> - - - - - 1 - - - This is some content]]> - - - - - - - - - - - - 1 - - - - - - - - - - - -"; - } - - /// - /// Returns the dynamic node/document to run tests against - /// - /// - /// - protected abstract dynamic GetDynamicNode(int id); - - [Test] - public void Recursive_Property() - { - var doc = GetDynamicNode(1174); - var prop = doc.GetProperty("siteTitle", true); - Assert.IsNotNull(prop); - Assert.AreEqual("This is my site", prop.Value); - prop = doc.GetProperty("_siteTitle"); //test with underscore prefix - Assert.IsNotNull(prop); - Assert.AreEqual("This is my site", prop.Value); - Assert.AreEqual("This is my site", doc._siteTitle); - } - - /// - /// Tests the internal instance level caching of returning properties - /// - /// - /// http://issues.umbraco.org/issue/U4-1824 - /// http://issues.umbraco.org/issue/U4-1825 - /// - [Test] - public void Can_Return_Property_And_Value() - { - var doc = GetDynamicNode(1173); - - Assert.IsTrue(doc.HasProperty(Constants.Conventions.Content.UrlAlias)); - var prop = doc.GetProperty(Constants.Conventions.Content.UrlAlias); - Assert.IsNotNull(prop); - Assert.AreEqual("page2/alias, 2ndpagealias", prop.Value); - Assert.AreEqual("page2/alias, 2ndpagealias", doc.umbracoUrlAlias); - } - - [Test] - public void Single() - { - var doc = GetDynamicNode(4444); - - var result = doc.Children().Single(); - - Assert.IsNotNull(result); - Assert.AreEqual(5555, result.Id); - } - - [Test] - public void Single_With_Query() - { - var doc = GetDynamicNode(1046); - - var result = doc.Children().Single("id==1175"); - - Assert.IsNotNull(result); - Assert.AreEqual(1175, result.Id); - } - - [Test] - public void First() - { - var doc = GetDynamicNode(1173); - - var result = doc.Children().First(); - - Assert.IsNotNull(result); - Assert.AreEqual(1174, result.Id); - } - - [Test] - public void First_With_Query() - { - var doc = GetDynamicNode(1173); - - var result = doc.Children().First("blah==\"some content\""); - - Assert.IsNotNull(result); - Assert.AreEqual(1176, result.Id); - } - - [Test] - public void Where_User_Property_Value() - { - var doc = GetDynamicNode(1173); - - var result = (IEnumerable) doc.Children().Where("blah==\"some content\""); - - Assert.IsNotNull(result); - Assert.AreEqual(1, result.Count()); - Assert.AreEqual(1176, result.Single().Id); - } - - [Test] - public void String_ContainsValue_Extension_Method() - { - var doc = GetDynamicNode(1046); - - var paramVals = new Dictionary { { "searchId", 1173 } }; //this is an integer value - var result = doc.Children() - .Where("selectedNodes.ContainsValue(searchId)", paramVals) //call an extension method - .FirstOrDefault(); - - Assert.IsNotNull(result); - Assert.AreEqual(4444, result.Id); - - //don't find! - paramVals = new Dictionary { { "searchId", 1111777 } }; - result = doc.Children() - .Where("selectedNodes.ContainsValue(searchId)", paramVals) - .FirstOrDefault(); - - Assert.IsNotNull(result); - Assert.IsTrue(result.GetType() == typeof (DynamicNull)); - //Assert.AreEqual(typeof(DynamicNull), result.GetType()); - } - - [Test] - public void String_Contains_Method() - { - var doc = GetDynamicNode(1046); - - var paramVals = new Dictionary { { "searchId", "1173" } }; - var result = doc.Children() - .Where("selectedNodes.Contains(searchId)", paramVals) - .FirstOrDefault(); - - Assert.IsNotNull(result); - Assert.AreEqual(4444, result.Id); - - //don't find! - paramVals = new Dictionary { { "searchId", "1aaa173" } }; - result = doc.Children() - .Where("selectedNodes.Contains(searchId)", paramVals) - .FirstOrDefault(); - - Assert.IsNotNull(result); - Assert.IsTrue(result.GetType() == typeof (DynamicNull)); - //Assert.AreEqual(typeof (DynamicNull), result.GetType()); - } - - [Test] - public void String_Split_Method() - { - var doc = GetDynamicNode(1046); - - var paramVals = new Dictionary - { - { "splitTerm", new char[] { ',' } }, - { "splitOptions", StringSplitOptions.RemoveEmptyEntries } - }; - var result = doc.Children() - .Where("selectedNodes.Split(splitTerm, splitOptions).Length == 3", paramVals) - .FirstOrDefault(); - - Assert.IsNotNull(result); - Assert.AreEqual(4444, result.Id); - } - - [Ignore("We are ignoring this test because currently our ExpressionParser class cannot deal with this... it needs some serious TLC but it is very complex.")] - [Test] - public void Complex_Linq() - { - var doc = GetDynamicNode(1173); - - var paramVals = new Dictionary { { "splitTerm", new char[] { ',' } }, { "searchId", "1173" } }; - var result = doc.Ancestors().OrderBy("level") - .Single() - .Descendants() - .Where("selectedNodes != null && selectedNodes != String.Empty && selectedNodes.Split(splitTerm).Contains(searchId)", paramVals) - .FirstOrDefault(); - - Assert.IsNotNull(result); - Assert.AreEqual(4444, result.Id); - } - - [Test] - public void Children_GroupBy_DocumentTypeAlias() - { - var doc = GetDynamicNode(1046); - - var found1 = doc.Children.GroupBy("DocumentTypeAlias"); - - var casted = (IEnumerable>) (found1); - Assert.AreEqual(2, casted.Count()); - Assert.AreEqual(2, casted.Single(x => x.Key.ToString() == "Home").Count()); - Assert.AreEqual(1, casted.Single(x => x.Key.ToString() == "CustomDocument").Count()); - } - - [Test] - public void Children_Where_DocumentTypeAlias() - { - var doc = GetDynamicNode(1046); - - var found1 = doc.Children.Where("DocumentTypeAlias == \"CustomDocument\""); - var found2 = doc.Children.Where("DocumentTypeAlias == \"Home\""); - - Assert.AreEqual(1, found1.Count()); - Assert.AreEqual(2, found2.Count()); - } - - [Test] - public void Children_Where_NodeTypeAlias() - { - var doc = GetDynamicNode(1046); - - var found1 = doc.Children.Where("NodeTypeAlias == \"CustomDocument\""); - var found2 = doc.Children.Where("NodeTypeAlias == \"Home\""); - - Assert.AreEqual(1, found1.Count()); - Assert.AreEqual(2, found2.Count()); - } - - [Test] - public void Children_Order_By_Update_Date() - { - var asDynamic = GetDynamicNode(1173); - - var ordered = asDynamic.Children.OrderBy("UpdateDate"); - var casted = (IEnumerable) ordered; - - var correctOrder = new[] { 1178, 1177, 1174, 1176 }; - for (var i = 0; i < correctOrder.Length; i++) - { - Assert.AreEqual(correctOrder[i], ((dynamic) casted.ElementAt(i)).Id); - } - - } - - [Test] - public void Children_Order_By_Update_Date_Descending() - { - var asDynamic = GetDynamicNode(1173); - - var ordered = asDynamic.Children.OrderBy("UpdateDate desc"); - var casted = (IEnumerable) ordered; - - var correctOrder = new[] { 1176, 1174, 1177, 1178 }; - for (var i = 0; i < correctOrder.Length; i++) - { - Assert.AreEqual(correctOrder[i], ((dynamic) casted.ElementAt(i)).Id); - } - - } - - [Test] - public void HasProperty() - { - var asDynamic = GetDynamicNode(1173); - - var hasProp = asDynamic.HasProperty(Constants.Conventions.Content.UrlAlias); - - Assert.AreEqual(true, (bool) hasProp); - - } - - [Test] - public void Skip() - { - var asDynamic = GetDynamicNode(1173); - - var skip = asDynamic.Children.Skip(2); - var casted = (IEnumerable) skip; - - Assert.AreEqual(2, casted.Count()); - Assert.IsTrue(casted.Select(x => ((dynamic) x).Id).ContainsAll(new dynamic[] { 1178, 1176 })); - - } - - [Test] - public void HasValue() - { - var asDynamic = GetDynamicNode(1173); - - var hasValue = asDynamic.HasValue(Constants.Conventions.Content.UrlAlias); - var noValue = asDynamic.HasValue("blahblahblah"); - - Assert.IsTrue(hasValue); - Assert.IsFalse(noValue); - } - - [Test] - public void Take() - { - var asDynamic = GetDynamicNode(1173); - - var take = asDynamic.Children.Take(2); - var casted = (IEnumerable) take; - - Assert.AreEqual(2, casted.Count()); - Assert.IsTrue(casted.Select(x => ((dynamic) x).Id).ContainsAll(new dynamic[] { 1174, 1177 })); - } - - [Test] - public void Ancestors_Where_Visible() - { - var asDynamic = GetDynamicNode(1174); - - var whereVisible = asDynamic.Ancestors().Where("Visible"); - var casted = (IEnumerable) whereVisible; - - Assert.AreEqual(1, casted.Count()); - - } - - [Test] - public void Visible() - { - var asDynamicHidden = GetDynamicNode(1046); - var asDynamicVisible = GetDynamicNode(1173); - - Assert.IsFalse(asDynamicHidden.Visible); - Assert.IsTrue(asDynamicVisible.Visible); - } - - [Test] - public void Ensure_TinyMCE_Converted_Type_User_Property() - { - var asDynamic = GetDynamicNode(1173); - - Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(asDynamic.Content.GetType())); - Assert.AreEqual("
This is some content
", asDynamic.Content.ToString()); - } - - [Test] - public void Get_Children_With_Pluralized_Alias() - { - var asDynamic = GetDynamicNode(1173); - - Action doAssert = d => - { - Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(d)); - var casted = (IEnumerable) d; - Assert.AreEqual(2, casted.Count()); - }; - - doAssert(asDynamic.Homes); //pluralized alias - doAssert(asDynamic.homes); //pluralized alias - doAssert(asDynamic.CustomDocuments); //pluralized alias - doAssert(asDynamic.customDocuments); //pluralized alias - } - - [Test] - public void GetPropertyValue_Non_Reflected() - { - var asDynamic = GetDynamicNode(1174); - - Assert.AreEqual("Custom data with same property name as the member name", asDynamic.GetPropertyValue("creatorName")); - Assert.AreEqual("Custom data with same property name as the member name", asDynamic.GetPropertyValue("CreatorName")); - } - - [Test] - public void Get_User_Property_With_Same_Name_As_Member_Property() - { - var asDynamic = GetDynamicNode(1174); - - Assert.AreEqual("Custom data with same property name as the member name", asDynamic.creatorName); - - //because CreatorName is defined on DynamicNode, it will not return the user defined property - Assert.AreEqual("admin", asDynamic.CreatorName); - } - - [Test] - public void Get_Member_Property() - { - var asDynamic = GetDynamicNode(1173); - - Assert.AreEqual((int) 2, (int) asDynamic.Level); - Assert.AreEqual((int) 2, (int) asDynamic.level); - - Assert.AreEqual((int) 1046, (int) asDynamic.ParentId); - Assert.AreEqual((int) 1046, (int) asDynamic.parentId); - } - - [Test] - public void Get_Children() - { - var asDynamic = GetDynamicNode(1173); - - var children = asDynamic.Children; - Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(children)); - - var childrenAsList = asDynamic.ChildrenAsList; //test ChildrenAsList too - Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(childrenAsList)); - - var castChildren = (IEnumerable) children; - Assert.AreEqual(4, castChildren.Count()); - - var castChildrenAsList = (IEnumerable) childrenAsList; - Assert.AreEqual(4, castChildrenAsList.Count()); - } - - [Test] - public void Ancestor_Or_Self() - { - var asDynamic = GetDynamicNode(1173); - - var result = asDynamic.AncestorOrSelf(); - - Assert.IsNotNull(result); - - // ancestor-or-self has to be self! - // but that's not what the "legacy" razor macro engine does... - if (result is Umbraco.Web.Models.DynamicPublishedContent) - Assert.AreEqual(1173, (int) result.Id); // that one works - else - Assert.AreEqual(1046, (int) result.Id); // that one still is fubar - } - - [Test] - public void Ancestors_Or_Self() - { - var asDynamic = GetDynamicNode(1174); - - var result = asDynamic.AncestorsOrSelf(); - - Assert.IsNotNull(result); - - var list = (IEnumerable) result; - Assert.AreEqual(3, list.Count()); - Assert.IsTrue(list.Select(x => ((dynamic) x).Id).ContainsAll(new dynamic[] { 1174, 1173, 1046 })); - } - - [Test] - public void Ancestors() - { - var asDynamic = GetDynamicNode(1174); - - var result = asDynamic.Ancestors(); - - Assert.IsNotNull(result); - - var list = (IEnumerable) result; - Assert.AreEqual(2, list.Count()); - Assert.IsTrue(list.Select(x => ((dynamic) x).Id).ContainsAll(new dynamic[] { 1173, 1046 })); - } - - [Test] - public void Descendants_Or_Self() - { - var asDynamic = GetDynamicNode(1046); - - var result = asDynamic.DescendantsOrSelf(); - - Assert.IsNotNull(result); - - var list = (IEnumerable) result; - Assert.AreEqual(9, list.Count()); - Assert.IsTrue(list.Select(x => ((dynamic) x).Id).ContainsAll(new dynamic[] { 1046, 1173, 1174, 1176, 1175, 4444 })); - } - - [Test] - public void Descendants() - { - var asDynamic = GetDynamicNode(1046); - - var result = asDynamic.Descendants(); - - Assert.IsNotNull(result); - - var list = (IEnumerable) result; - Assert.AreEqual(8, list.Count()); - Assert.IsTrue(list.Select(x => ((dynamic) x).Id).ContainsAll(new dynamic[] { 1173, 1174, 1176, 1175, 4444 })); - } - - [Test] - public void Up() - { - var asDynamic = GetDynamicNode(1173); - - var result = asDynamic.Up(); - - Assert.IsNotNull(result); - - Assert.AreEqual((int) 1046, (int) result.Id); - } - - [Test] - public void Down() - { - var asDynamic = GetDynamicNode(1173); - - var result = asDynamic.Down(); - - Assert.IsNotNull(result); - - Assert.AreEqual((int) 1174, (int) result.Id); - } - } - - /// - /// Extension methods used in tests - /// - public static class TestExtensionMethods - { - public static bool ContainsValue(this string s, int val) - { - return s.Contains(val.ToString()); - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Tests/PublishedContent/DynamicPublishedContentCustomExtensionMethods.cs b/src/Umbraco.Tests/PublishedContent/DynamicPublishedContentCustomExtensionMethods.cs deleted file mode 100644 index b2cebf3ed0..0000000000 --- a/src/Umbraco.Tests/PublishedContent/DynamicPublishedContentCustomExtensionMethods.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using Umbraco.Web.Models; - -namespace Umbraco.Tests.PublishedContent -{ - public static class DynamicPublishedContentCustomExtensionMethods - { - - public static string DynamicDocumentNoParameters(this DynamicPublishedContent doc) - { - return "Hello world"; - } - - public static string DynamicDocumentCustomString(this DynamicPublishedContent doc, string custom) - { - return custom; - } - - public static string DynamicDocumentMultiParam(this DynamicPublishedContent doc, string custom, int i, bool b) - { - return custom + i + b; - } - - public static string DynamicDocumentListMultiParam(this DynamicPublishedContentList doc, string custom, int i, bool b) - { - return custom + i + b; - } - - public static string DynamicDocumentEnumerableMultiParam(this IEnumerable doc, string custom, int i, bool b) - { - return custom + i + b; - } - - } -} \ No newline at end of file diff --git a/src/Umbraco.Tests/PublishedContent/DynamicPublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/DynamicPublishedContentTests.cs deleted file mode 100644 index a18215ccd0..0000000000 --- a/src/Umbraco.Tests/PublishedContent/DynamicPublishedContentTests.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Models; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web; -using Umbraco.Web.Models; -using Umbraco.Web.PublishedCache; -using Umbraco.Web.PublishedCache.XmlPublishedCache; -using File = Umbraco.Core.Models.File; - -namespace Umbraco.Tests.PublishedContent -{ - [TestFixture] - public class DynamicPublishedContentTests : DynamicDocumentTestsBase - { - internal DynamicPublishedContent GetNode(int id) - { - //var template = Template.MakeNew("test", new User(0)); - //var ctx = GetUmbracoContext("/test", template.Id); - var ctx = GetUmbracoContext("/test", 1234); - var doc = ctx.ContentCache.GetById(id); - Assert.IsNotNull(doc); - var dynamicNode = new DynamicPublishedContent(doc); - Assert.IsNotNull(dynamicNode); - return dynamicNode; - } - - protected override dynamic GetDynamicNode(int id) - { - return GetNode(id).AsDynamic(); - } - - [Test] - public void FirstChild() - { - var content = GetDynamicNode(1173); - - var x = content.FirstChild(); - Assert.IsNotNull(x); - Assert.IsInstanceOf(x); - Assert.AreEqual(1174, x.Id); - - x = content.FirstChild("CustomDocument"); - Assert.IsNotNull(x); - Assert.IsInstanceOf(x); - Assert.AreEqual(1177, x.Id); - } - - [Test] - public void Children() - { - var content = GetDynamicNode(1173); - - var l = content.Children; - Assert.AreEqual(4, l.Count()); - - // works - but not by calling the extension method - // because the binder will in fact re-route to the property first - l = content.Children(); - Assert.AreEqual(4, l.Count()); - } - - [Test] - public void ChildrenOfType() - { - var content = GetDynamicNode(1173); - - var l = content.Children; - Assert.AreEqual(4, l.Count()); - - // fails - because it fails to find extension methods? - l = content.Children("CustomDocument"); - Assert.AreEqual(2, l.Count()); - } - - [Test] - public void Custom_Extension_Methods() - { - var asDynamic = GetDynamicNode(1173); - - Assert.AreEqual("Hello world", asDynamic.DynamicDocumentNoParameters()); - Assert.AreEqual("Hello world!", asDynamic.DynamicDocumentCustomString("Hello world!")); - Assert.AreEqual("Hello world!" + 123 + false, asDynamic.DynamicDocumentMultiParam("Hello world!", 123, false)); - Assert.AreEqual("Hello world!" + 123 + false, asDynamic.Children.DynamicDocumentListMultiParam("Hello world!", 123, false)); - Assert.AreEqual("Hello world!" + 123 + false, asDynamic.Children.DynamicDocumentEnumerableMultiParam("Hello world!", 123, false)); - - } - - [Test] - public void Returns_IDocument_Object() - { - var helper = new TestHelper(GetNode(1173)); - var doc = helper.GetDoc(); - //HasProperty is only a prop on DynamicPublishedContent, NOT IPublishedContent - Assert.IsFalse(doc.GetType().GetProperties().Any(x => x.Name == "HasProperty")); - } - - [Test] - public void Returns_DynamicDocument_Object() - { - var helper = new TestHelper(GetNode(1173)); - var doc = helper.GetDocAsDynamic(); - //HasProperty is only a prop on DynamicPublishedContent, NOT IPublishedContent - Assert.IsTrue(doc.HasProperty(Constants.Conventions.Content.UrlAlias)); - } - - [Test] - public void Returns_DynamicDocument_Object_After_Casting() - { - var helper = new TestHelper(GetNode(1173)); - var doc = helper.GetDoc(); - var ddoc = (dynamic) doc; - //HasProperty is only a prop on DynamicPublishedContent, NOT IPublishedContent - Assert.IsTrue(ddoc.HasProperty(Constants.Conventions.Content.UrlAlias)); - } - - [Test] - public void U4_4559() - { - var doc = GetDynamicNode(1174); - var result = doc.AncestorOrSelf(1); - Assert.IsNotNull(result); - Assert.AreEqual(1046, result.Id); - } - - /// - /// Test class to mimic UmbracoHelper when returning docs - /// - public class TestHelper - { - private readonly DynamicPublishedContent _doc; - - public TestHelper(DynamicPublishedContent doc) - { - _doc = doc; - } - - public IPublishedContent GetDoc() - { - return _doc; - } - - public dynamic GetDocAsDynamic() - { - return _doc.AsDynamic(); - } - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs b/src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs deleted file mode 100644 index 5075f347e3..0000000000 --- a/src/Umbraco.Tests/PublishedContent/DynamicXmlConverterTests.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System.Xml; -using System.Xml.Linq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Dynamics; -using Umbraco.Core.Xml; - -namespace Umbraco.Tests.PublishedContent -{ - [TestFixture] - public class DynamicXmlConverterTests - { - [Test] - public void Convert_To_Raw_String() - { - var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml( - XmlHelper.StripDashesInElementOrAttributeNames(xml), - xml); - var result = dXml.TryConvertTo(); - Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result.Value); - } - - [Test] - public void Convert_To_Raw_XElement() - { - var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml( - XmlHelper.StripDashesInElementOrAttributeNames(xml), - xml); - var result = dXml.TryConvertTo(); - Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result.Value.ToString(SaveOptions.DisableFormatting)); - } - - [Test] - public void Convert_To_Raw_XmlElement() - { - var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml( - XmlHelper.StripDashesInElementOrAttributeNames(xml), - xml); - var result = dXml.TryConvertTo(); - Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result.Value.OuterXml); - } - - [Test] - public void Convert_To_Raw_XmlDocument() - { - var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml( - XmlHelper.StripDashesInElementOrAttributeNames(xml), - xml); - var result = dXml.TryConvertTo(); - Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result.Value.InnerXml); - } - - [Test] - public void Convert_To_String() - { - var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml(xml); - var result = dXml.TryConvertTo(); - Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result); - } - - [Test] - public void Convert_To_XElement() - { - var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml(xml); - var result = dXml.TryConvertTo(); - Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result.ToString(SaveOptions.DisableFormatting)); - } - - [Test] - public void Convert_To_XmlElement() - { - var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml(xml); - var result = dXml.TryConvertTo(); - Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result.OuterXml); - } - - [Test] - public void Convert_To_XmlDocument() - { - var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var dXml = new DynamicXml(xml); - var result = dXml.TryConvertTo(); - Assert.IsTrue(result.Success); - Assert.AreEqual(xml, result.Result.InnerXml); - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs b/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs deleted file mode 100644 index 0d83fdbf0c..0000000000 --- a/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using System.Diagnostics; -using Microsoft.CSharp.RuntimeBinder; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Dynamics; -using System.Linq; -using Umbraco.Core.Xml; - -namespace Umbraco.Tests.PublishedContent -{ - [TestFixture] - public class DynamicXmlTests - { - /// - /// Ensures that when we return the xml structure we get the real structure, not the replaced hyphen structure - /// see: http://issues.umbraco.org/issue/U4-1405#comment=67-5113 - /// http://issues.umbraco.org/issue/U4-1636 - /// - [Test] - public void Deals_With_Hyphenated_Values() - { - var xml = @" - - True - 1161 - /content/ - 12 december Zorgbeurs Care - -"; - - var typedXml = new DynamicXml( - XmlHelper.StripDashesInElementOrAttributeNames(xml), - xml); - dynamic dynamicXml = typedXml; - - var typedElement = typedXml.RawXmlElement.Element("url-picker"); - var dynamicElementByCleanedName = dynamicXml.urlpicker; - - Assert.IsNotNull(typedElement); - Assert.IsNotNull(dynamicElementByCleanedName); - - Assert.AreEqual( - typedElement.Attribute("some-attribute").Value, - dynamicElementByCleanedName.someattribute); - } - - - - [Test] - public void Custom_Extension_Method() - { - var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var typedXml = new DynamicXml(xml); - - dynamic dynamicXml = typedXml; - - //we haven't explicitly defined ElementAt so this will dynamically invoke this method - var element = dynamicXml.ElementAt(0); - - Assert.AreEqual("1057", Enumerable.First(element.BaseElement.Elements()).Attribute("id").Value); - } - - - - [Test] - public void Take() - { - var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg"; - var typedXml = new DynamicXml(xml); - dynamic dynamicXml = typedXml; - var typedTaken = typedXml.Take(1); - var dynamicTaken = dynamicXml.Take(1); - - Assert.AreEqual(1, typedTaken.Count()); - Assert.AreEqual(1, Enumerable.Count(dynamicTaken)); - - Assert.AreEqual("1057", typedTaken.ElementAt(0).BaseElement.Elements().First().Attribute("id").Value); - Assert.AreEqual("1057", Enumerable.First(Enumerable.ElementAt(dynamicTaken, 0).BaseElement.Elements()).Attribute("id").Value); - } - - - - /// - /// Test the current Core class - /// - [Test] - public void Find_Test_Core_Class() - { - RunFindTest(x => new DynamicXml(x)); - } - - - - private void RunFindTest(Func getDynamicXml) - { - var xmlstring = @" - - - -"; - - dynamic dXml = getDynamicXml(xmlstring); - - var result1 = dXml.Find("@name", "test 1"); - var result2 = dXml.Find("@name", "test 2"); - var result3 = dXml.Find("@name", "test 3"); - var result4 = dXml.Find("@name", "dont find"); - - Assert.AreEqual("found 1", result1.value); - Assert.AreEqual("found 2", result2.value); - Assert.AreEqual("found 3", result3.value); - Assert.Throws(() => - { - //this will throw because result4 is not found - var temp = result4.value; - }); - } - - } -} \ No newline at end of file diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs index 019f6448dd..31d2db1d89 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs @@ -4,7 +4,6 @@ using System.Collections.ObjectModel; using System.Linq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Dynamics; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Tests.TestHelpers; diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 960963b265..c4a33854bd 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -124,7 +124,7 @@ namespace Umbraco.Tests.PublishedContent { var doc = GetNode(1173); - var items = doc.Children.Where("Visible").ToIndexedArray(); + var items = doc.Children.Where(x => x.IsVisible()).ToIndexedArray(); foreach (var item in items) { @@ -334,7 +334,7 @@ namespace Umbraco.Tests.PublishedContent { var doc = GetNode(1046); - var found1 = doc.Children.GroupBy("DocumentTypeAlias").ToArray(); + var found1 = doc.Children.GroupBy(x => x.DocumentTypeAlias).ToArray(); Assert.AreEqual(2, found1.Length); Assert.AreEqual(2, found1.Single(x => x.Key.ToString() == "Home").Count()); @@ -346,8 +346,8 @@ namespace Umbraco.Tests.PublishedContent { var doc = GetNode(1046); - var found1 = doc.Children.Where("DocumentTypeAlias == \"CustomDocument\""); - var found2 = doc.Children.Where("DocumentTypeAlias == \"Home\""); + var found1 = doc.Children.Where(x => x.DocumentTypeAlias == "CustomDocument"); + var found2 = doc.Children.Where(x => x.DocumentTypeAlias == "Home"); Assert.AreEqual(1, found1.Count()); Assert.AreEqual(2, found2.Count()); @@ -358,7 +358,7 @@ namespace Umbraco.Tests.PublishedContent { var doc = GetNode(1173); - var ordered = doc.Children.OrderBy("UpdateDate"); + var ordered = doc.Children.OrderBy(x => x.UpdateDate); var correctOrder = new[] { 1178, 1177, 1174, 1176 }; for (var i = 0; i < correctOrder.Length; i++) @@ -419,7 +419,7 @@ namespace Umbraco.Tests.PublishedContent { var doc = GetNode(1174); - var whereVisible = doc.Ancestors().Where("Visible"); + var whereVisible = doc.Ancestors().Where(x => x.IsVisible()); Assert.AreEqual(1, whereVisible.Count()); } diff --git a/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/UmbracoTemplatePage`T.cs b/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/UmbracoTemplatePage`T.cs deleted file mode 100644 index 1693194542..0000000000 --- a/src/Umbraco.Tests/PublishedContent/StronglyTypedModels/UmbracoTemplatePage`T.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Umbraco.Core.Models; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web.Mvc; - -namespace Umbraco.Tests.PublishedContent.StronglyTypedModels -{ - /// - /// Represents a basic extension of the UmbracoTemplatePage, which allows you to specify - /// the type of a strongly typed model that inherits from TypedModelBase. - /// The model is exposed as TypedModel. - /// - /// Type of the model to create/expose - public abstract class UmbracoTemplatePage : UmbracoTemplatePage where T : TypedModelBase - { - protected override void InitializePage() - { - base.InitializePage(); - - //set the model to the current node if it is not set, this is generally not the case - if (Model != null) - { - //Map CurrentModel here - var constructorInfo = typeof(T).GetConstructor(new []{typeof(IPublishedContent)}); - if (constructorInfo != null) - { - TypedModel = constructorInfo.Invoke(new object[]{Model.Content}) as T; - } - } - } - - /// - /// Returns the a strongly typed model - /// - public T TypedModel { get; private set; } - } -} \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index f2d2b369b5..c4b6f51dad 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -281,7 +281,6 @@ - @@ -352,8 +351,6 @@ - - @@ -385,7 +382,6 @@ - @@ -441,8 +437,6 @@ - - @@ -500,9 +494,6 @@ - - - diff --git a/src/Umbraco.Tests/Web/Mvc/RenderModelBinderTests.cs b/src/Umbraco.Tests/Web/Mvc/RenderModelBinderTests.cs index 6216a3acc8..a0e1bc5f9d 100644 --- a/src/Umbraco.Tests/Web/Mvc/RenderModelBinderTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/RenderModelBinderTests.cs @@ -35,8 +35,6 @@ namespace Umbraco.Tests.Web.Mvc Assert.IsNotNull(found); found = binder.GetBinder(typeof(RenderModel)); Assert.IsNotNull(found); - found = binder.GetBinder(typeof(DynamicPublishedContent)); - Assert.IsNotNull(found); found = binder.GetBinder(typeof(MyContent)); Assert.IsNotNull(found); found = binder.GetBinder(typeof(RenderModel)); diff --git a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs index e7c5a13d76..5fadc27d66 100644 --- a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs @@ -135,7 +135,6 @@ namespace Umbraco.Tests.Web.Mvc Mock.Of(query => query.TypedContent(It.IsAny()) == //return mock of IPublishedContent for any call to GetById Mock.Of(content => content.Id == 2)), - Mock.Of(), Mock.Of(), Mock.Of(), new UrlProvider(umbCtx, Enumerable.Empty()), diff --git a/src/Umbraco.Web/Dynamics/DynamicExpression.cs b/src/Umbraco.Web/Dynamics/DynamicExpression.cs deleted file mode 100644 index ae0befbfe8..0000000000 --- a/src/Umbraco.Web/Dynamics/DynamicExpression.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using Umbraco.Core.Dynamics; - -namespace Umbraco.Web.Dynamics -{ - internal static class DynamicExpression - { - //public static bool ConvertDynamicNullToBooleanFalse = false; - - public static Expression Parse(Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values) - { - //ConvertDynamicNullToBooleanFalse = convertDynamicNullToBooleanFalse; - var parser = new ExpressionParser(null, expression, values, convertDynamicNullToBooleanFalse); - return parser.Parse(resultType); - } - - public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values) - { - return ParseLambda(new ParameterExpression[] { Expression.Parameter(itType, "") }, resultType, expression, convertDynamicNullToBooleanFalse, values); - } - - public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values) - { - //ConvertDynamicNullToBooleanFalse = convertDynamicNullToBooleanFalse; - var parser = new ExpressionParser(parameters, expression, values, convertDynamicNullToBooleanFalse); - return Expression.Lambda(parser.Parse(resultType), parameters); - } - - public static Expression> ParseLambda(string expression, bool convertDynamicNullToBooleanFalse, params object[] values) - { - return (Expression>)ParseLambda(typeof(T), typeof(S), expression, convertDynamicNullToBooleanFalse, values); - } - - public static Type CreateClass(params DynamicProperty[] properties) - { - return ClassFactory.Instance.GetDynamicClass(properties); - } - - public static Type CreateClass(IEnumerable properties) - { - return ClassFactory.Instance.GetDynamicClass(properties); - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Web/Dynamics/DynamicGrouping.cs b/src/Umbraco.Web/Dynamics/DynamicGrouping.cs deleted file mode 100644 index 5eac3973d7..0000000000 --- a/src/Umbraco.Web/Dynamics/DynamicGrouping.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Collections; -using Umbraco.Core.Models; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web.Models; - -namespace Umbraco.Web.Dynamics -{ - public class DynamicGrouping : IEnumerable>, IEnumerable> - { - internal IEnumerable> Inner; - - public DynamicGrouping OrderBy(string expression) - { - return this; - } - - public DynamicGrouping(DynamicPublishedContentList list, string groupBy) - { - Inner = - list - .Items - .Select(node => - { - string predicate = groupBy; - var internalList = new DynamicPublishedContentList(new DynamicPublishedContent[] { node }); - var query = (IQueryable)internalList.Select(predicate, new object[] { }); - var key = query.FirstOrDefault(); - return new - { - Key = key, - Node = node - }; - }) - .Where(item => item.Key != null) - .GroupBy(item => item.Key) - .Select(item => new Grouping() - { - Key = item.Key, - Elements = item.Select(inner => inner.Node) - }); - } - internal DynamicGrouping(IEnumerable> source) - { - this.Inner = source; - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - return Inner.GetEnumerator(); - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - return Inner.GetEnumerator(); - } - - public IEnumerator GetEnumerator() - { - return Inner.GetEnumerator(); - } - } -} diff --git a/src/Umbraco.Web/Dynamics/DynamicPublishedContentIdEqualityComparer.cs b/src/Umbraco.Web/Dynamics/DynamicPublishedContentIdEqualityComparer.cs deleted file mode 100644 index 27bb327bf4..0000000000 --- a/src/Umbraco.Web/Dynamics/DynamicPublishedContentIdEqualityComparer.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using Umbraco.Web.Models; - -namespace Umbraco.Web.Dynamics -{ - internal class DynamicPublishedContentIdEqualityComparer : EqualityComparer - { - - public override bool Equals(DynamicPublishedContent x, DynamicPublishedContent y) - { - //Check whether the compared objects reference the same data. - if (Object.ReferenceEquals(x, y)) return true; - - //Check whether any of the compared objects is null. - if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) - return false; - - //Check whether the nodes ids are equal. - return x.Id == y.Id; - - } - - public override int GetHashCode(DynamicPublishedContent obj) - { - if (Object.ReferenceEquals(obj, null)) return 0; - - //Get hash code for the Name field if it is not null. - int hashId = obj.Id.GetHashCode(); - - return hashId; - } - - } -} diff --git a/src/Umbraco.Web/Dynamics/DynamicPublishedContentListOrdering.cs b/src/Umbraco.Web/Dynamics/DynamicPublishedContentListOrdering.cs deleted file mode 100644 index 3acf23fa61..0000000000 --- a/src/Umbraco.Web/Dynamics/DynamicPublishedContentListOrdering.cs +++ /dev/null @@ -1,251 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using Umbraco.Web.Models; - -namespace Umbraco.Web.Dynamics -{ - public static class DynamicPublishedContentListOrdering - { - - private static TOut Reduce(Func func, DynamicPublishedContent publishedContent) - { - var value = func(publishedContent); - while (value is Func) - { - value = (value as Func)(publishedContent); - } - //when you're sorting a list of properties - //and one of those properties doesn't exist, it will come back as DynamicNull - //when that gets handled by the expression tree parser, it's converted to be false - //which lets .Where work properly with e.g. umbracoNaviHide which may not be defined - //on all properties - //this checks to see if the type of value is bool, and if it is, and it's false - //then return false - //in a case where Reduce is being called, this will return false, which is the - //same as the actual real value - //but when Reduce [a dynamicnode dynamic property call] is called - //it will result in null, (because default(object) is null) - //which will cause the item with the missing property to sort up to the top of the list - if (value.GetType() == typeof(bool) && !((value as bool?) ?? false)) - { - return default(TOut); - } - if (value.GetType() == typeof(string) && string.IsNullOrEmpty((value as string))) - { - return default(TOut); - } - return (TOut)value; - } - public static IOrderedQueryable OrderBy(object source, object key) - { - IEnumerable typedSource = source as IEnumerable; - LambdaExpression lambda = key as LambdaExpression; - //if the lambda we have returns an actual property, not a dynamic one, - //then the TOut of the func will be the actual type, not object - //Func func = (Func)lambda.Compile(); - var func = lambda.Compile(); - var TOut = func.GetType().GetGenericArguments()[1]; - IOrderedQueryable result = null; - if (TOut == typeof(Func)) - { - result = (IOrderedQueryable)typedSource - .OrderBy(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(object)) - { - result = (IOrderedQueryable)typedSource - .OrderBy(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(bool)) - { - result = (IOrderedQueryable)typedSource - .OrderBy(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(decimal)) - { - result = (IOrderedQueryable)typedSource - .OrderBy(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(int)) - { - result = (IOrderedQueryable)typedSource - .OrderBy(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(string)) - { - result = (IOrderedQueryable)typedSource - .OrderBy(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(DateTime)) - { - result = (IOrderedQueryable)typedSource - .OrderBy(x => Reduce(func as Func, x)) - .AsQueryable(); - } - return result; - } - public static IOrderedQueryable ThenBy(object source, object key) - { - IOrderedQueryable typedSource = source as IOrderedQueryable; - LambdaExpression lambda = key as LambdaExpression; - var func = lambda.Compile(); - var TOut = func.GetType().GetGenericArguments()[1]; - IOrderedQueryable result = null; - if (TOut == typeof(Func)) - { - result = (IOrderedQueryable)typedSource - .ThenBy(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(object)) - { - result = (IOrderedQueryable)typedSource - .ThenBy(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(bool)) - { - result = (IOrderedQueryable)typedSource - .ThenBy(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(decimal)) - { - result = (IOrderedQueryable)typedSource - .ThenBy(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(int)) - { - result = (IOrderedQueryable)typedSource - .ThenBy(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(string)) - { - result = (IOrderedQueryable)typedSource - .ThenBy(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(DateTime)) - { - result = (IOrderedQueryable)typedSource - .ThenBy(x => Reduce(func as Func, x)) - .AsQueryable(); - } - return result; - } - public static IOrderedQueryable OrderByDescending(object source, object key) - { - IEnumerable typedSource = source as IEnumerable; - LambdaExpression lambda = key as LambdaExpression; - var func = lambda.Compile(); - var TOut = func.GetType().GetGenericArguments()[1]; - IOrderedQueryable result = null; - if (TOut == typeof(Func)) - { - result = (IOrderedQueryable)typedSource - .OrderByDescending(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(object)) - { - result = (IOrderedQueryable)typedSource - .OrderByDescending(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(bool)) - { - result = (IOrderedQueryable)typedSource - .OrderByDescending(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(decimal)) - { - result = (IOrderedQueryable)typedSource - .OrderByDescending(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(int)) - { - result = (IOrderedQueryable)typedSource - .OrderByDescending(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(string)) - { - result = (IOrderedQueryable)typedSource - .OrderByDescending(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(DateTime)) - { - result = (IOrderedQueryable)typedSource - .OrderByDescending(x => Reduce(func as Func, x)) - .AsQueryable(); - } - return result; - } - public static IOrderedQueryable ThenByDescending(object source, object key) - { - IOrderedQueryable typedSource = source as IOrderedQueryable; - LambdaExpression lambda = key as LambdaExpression; - var func = lambda.Compile(); - var TOut = func.GetType().GetGenericArguments()[1]; - IOrderedQueryable result = null; - if (TOut == typeof(Func)) - { - result = (IOrderedQueryable)typedSource - .ThenByDescending(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(object)) - { - result = (IOrderedQueryable)typedSource - .ThenByDescending(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(bool)) - { - result = (IOrderedQueryable)typedSource - .ThenByDescending(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(decimal)) - { - result = (IOrderedQueryable)typedSource - .ThenByDescending(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(int)) - { - result = (IOrderedQueryable)typedSource - .ThenByDescending(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(string)) - { - result = (IOrderedQueryable)typedSource - .ThenByDescending(x => Reduce(func as Func, x)) - .AsQueryable(); - } - if (TOut == typeof(DateTime)) - { - result = (IOrderedQueryable)typedSource - .ThenByDescending(x => Reduce(func as Func, x)) - .AsQueryable(); - } - return result; - } - - } -} - diff --git a/src/Umbraco.Web/Dynamics/DynamicQueryable.cs b/src/Umbraco.Web/Dynamics/DynamicQueryable.cs deleted file mode 100644 index 85721d7b14..0000000000 --- a/src/Umbraco.Web/Dynamics/DynamicQueryable.cs +++ /dev/null @@ -1,318 +0,0 @@ -//Copyright (C) Microsoft Corporation. All rights reserved. - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Linq.Expressions; -using System.Diagnostics; -using Umbraco.Core.Dynamics; -using Umbraco.Web.Models; - -namespace Umbraco.Web.Dynamics -{ - //TODO: Much of this can move to Umbraco.Core.Dynamics - but somehow need to remove all the hard coded references to things like - // dynamicnull, etc... - //NOTE: The OrderBy stuff here seems to be a bit hacked with hard references to umbraco node objects so don't think it can be - // re-used which is why we have the OrderBy stuff that hasn't been hacked in teh Umbraco.Core.Dynamics - - internal static class DynamicQueryable - { - public static IQueryable Where(this IQueryable source, string predicate, params object[] values) - { - return (IQueryable)Where((IQueryable)source, predicate, values); - } - - public static IQueryable Where(this IQueryable source, string predicate, params object[] values) - { - if (source == null) throw new ArgumentNullException("source"); - if (predicate == null) throw new ArgumentNullException("predicate"); - LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, true, values); - if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(T)) - { - //source list is DynamicNode and the lambda returns a Func - IQueryable typedSource = source as IQueryable; - var compiledFunc = lambda.Compile(); - Func func = null; - Func boolFunc = null; - if (compiledFunc is Func) - { - func = (Func)compiledFunc; - } - if (compiledFunc is Func) - { - boolFunc = (Func)compiledFunc; - } - return typedSource.Where(delegate(T node) - { - object value = -1; - //value = func(node); - //I can't figure out why this is double func<>'d - try - { - if (func != null) - { - var firstFuncResult = func(node); - if (firstFuncResult is Func) - { - value = (firstFuncResult as Func)(node); - } - if (firstFuncResult is Func) - { - value = (firstFuncResult as Func)(node); - } - if (firstFuncResult is bool) - { - return (bool)firstFuncResult; - } - if (value is bool) - { - return (bool)value; - } - } - if (boolFunc != null) - { - return boolFunc(node); - } - return false; - } - catch (Exception ex) - { - Trace.WriteLine(ex.Message); - return false; - } - }).AsQueryable(); - } - else - { - return source.Provider.CreateQuery( - Expression.Call( - typeof(Queryable), "Where", - new Type[] { source.ElementType }, - source.Expression, Expression.Quote(lambda))); - } - } - - public static IQueryable Select(this IQueryable source, string selector, params object[] values) - { - if (source == null) throw new ArgumentNullException("source"); - if (selector == null) throw new ArgumentNullException("selector"); - LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(object), selector, false, values); - if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(T)) - { - //source list is DynamicNode and the lambda returns a Func - IQueryable typedSource = source as IQueryable; - var compiledFunc = lambda.Compile(); - Func func = null; - if (compiledFunc is Func) - { - func = (Func)compiledFunc; - } - return typedSource.Select(delegate(T node) - { - object value = null; - value = func(node); - if (value is Func) - { - var innerValue = (value as Func)(node); - return innerValue; - } - return value; - }).AsQueryable(); - } - else - { - return source.Provider.CreateQuery( - Expression.Call( - typeof(Queryable), "Select", - new Type[] { source.ElementType, lambda.Body.Type }, - source.Expression, Expression.Quote(lambda))); - } - } - - public static IQueryable OrderBy(this IQueryable source, string ordering, Func getDynamicListTypeCallback, params object[] values) - { - return (IQueryable)OrderBy((IQueryable)source, ordering, getDynamicListTypeCallback, values); - } - - public static IQueryable OrderBy(this IQueryable source, string ordering, Func getDynamicListTypeCallback, params object[] values) - { - if (source == null) throw new ArgumentNullException("source"); - if (ordering == null) throw new ArgumentNullException("ordering"); - - IQueryable typedSource = source as IQueryable; - if (!ordering.Contains(",")) - { - bool descending = false; - if (ordering.IndexOf(" descending", StringComparison.CurrentCultureIgnoreCase) >= 0) - { - ordering = ordering.Replace(" descending", ""); - descending = true; - } - if (ordering.IndexOf(" desc", StringComparison.CurrentCultureIgnoreCase) >= 0) - { - ordering = ordering.Replace(" desc", ""); - descending = true; - } - - LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(object), ordering, false, values); - if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(T)) - { - //source list is DynamicNode and the lambda returns a Func - Func func = (Func)lambda.Compile(); - //get the values out - var query = typedSource.ToList().ConvertAll(item => new { node = item, key = EvaluateDynamicNodeFunc(item, func) }); - if (query.Count == 0) - { - return source; - } - var types = from i in query - group i by i.key.GetType() into g - where g.Key != typeof(DynamicNull) - orderby g.Count() descending - select new { g, Instances = g.Count() }; - var dominantType = types.First().g.Key; - - // NH - add culture dependencies - StringComparer comp = StringComparer.Create(CultureInfo.CurrentCulture, true); - - if (!descending) - { - // if the dominant type is a string we'll ensure that strings are sorted based on culture settings on node - if (dominantType.FullName == "System.String") - return query.OrderBy(item => item.key.ToString(), comp).Select(item => item.node).AsQueryable(); - else - return query.OrderBy(item => GetObjectAsTypeOrDefault(item.key, dominantType)).Select(item => item.node).AsQueryable(); - } - else - { - if (dominantType.FullName == "System.String") - return query.OrderByDescending(item => item.key.ToString(), comp).Select(item => item.node).AsQueryable(); - else - return query.OrderByDescending(item => GetObjectAsTypeOrDefault(item.key, dominantType)).Select(item => item.node).AsQueryable(); - } - } - } - - bool isDynamicNodeList = false || typedSource != null; - - ParameterExpression[] parameters = new ParameterExpression[] { - Expression.Parameter(source.ElementType, "") }; - var parser = new ExpressionParser(parameters, ordering, values, false); - IEnumerable orderings = parser.ParseOrdering(); - Expression queryExpr = source.Expression; - string methodAsc = "OrderBy"; - string methodDesc = "OrderByDescending"; - foreach (DynamicOrdering o in orderings) - { - if (!isDynamicNodeList) - { - queryExpr = Expression.Call( - typeof(Queryable), o.Ascending ? methodAsc : methodDesc, - new Type[] { source.ElementType, o.Selector.Type }, - queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters))); - } - else - { - //reroute each stacked Expression.Call into our own methods that know how to deal - //with DynamicNode - queryExpr = Expression.Call( - getDynamicListTypeCallback(), - o.Ascending ? methodAsc : methodDesc, - null, - queryExpr, - Expression.Quote(Expression.Lambda(o.Selector, parameters)) - ); - } - methodAsc = "ThenBy"; - methodDesc = "ThenByDescending"; - } - if (isDynamicNodeList) - { - return typedSource.Provider.CreateQuery(queryExpr); - } - return source.Provider.CreateQuery(queryExpr); - - } - private static object GetObjectAsTypeOrDefault(object value, Type type) - { - if (type.IsInstanceOfType(value)) - { - return (object)Convert.ChangeType(value, type); - } - else - { - if (type.IsValueType) - { - return Activator.CreateInstance(type); - } - return null; - } - } - private static object EvaluateDynamicNodeFunc(T publishedContent, Func func) - { - object value = -1; - var firstFuncResult = func(publishedContent); - if (firstFuncResult is Func) - { - value = (firstFuncResult as Func)(publishedContent); - } - if (firstFuncResult.GetType().IsValueType || firstFuncResult is string) - { - value = firstFuncResult; - } - return value; - } - public static IQueryable Take(this IQueryable source, int count) - { - if (source == null) throw new ArgumentNullException("source"); - return source.Provider.CreateQuery( - Expression.Call( - typeof(Queryable), "Take", - new Type[] { source.ElementType }, - source.Expression, Expression.Constant(count))); - } - - public static IQueryable Skip(this IQueryable source, int count) - { - if (source == null) throw new ArgumentNullException("source"); - return source.Provider.CreateQuery( - Expression.Call( - typeof(Queryable), "Skip", - new Type[] { source.ElementType }, - source.Expression, Expression.Constant(count))); - } - - public static IQueryable GroupBy(this IQueryable source, string keySelector, string elementSelector, params object[] values) - { - if (source == null) throw new ArgumentNullException("source"); - if (keySelector == null) throw new ArgumentNullException("keySelector"); - if (elementSelector == null) throw new ArgumentNullException("elementSelector"); - LambdaExpression keyLambda = DynamicExpression.ParseLambda(source.ElementType, null, keySelector, true, values); - LambdaExpression elementLambda = DynamicExpression.ParseLambda(source.ElementType, null, elementSelector, true, values); - return source.Provider.CreateQuery( - Expression.Call( - typeof(Queryable), "GroupBy", - new Type[] { source.ElementType, keyLambda.Body.Type, elementLambda.Body.Type }, - source.Expression, Expression.Quote(keyLambda), Expression.Quote(elementLambda))); - } - - public static bool Any(this IQueryable source) - { - if (source == null) throw new ArgumentNullException("source"); - return (bool)source.Provider.Execute( - Expression.Call( - typeof(Queryable), "Any", - new Type[] { source.ElementType }, source.Expression)); - } - - public static int Count(this IQueryable source) - { - if (source == null) throw new ArgumentNullException("source"); - return (int)source.Provider.Execute( - Expression.Call( - typeof(Queryable), "Count", - new Type[] { source.ElementType }, source.Expression)); - } - } -} diff --git a/src/Umbraco.Web/Dynamics/ExpressionParser.cs b/src/Umbraco.Web/Dynamics/ExpressionParser.cs deleted file mode 100644 index 3f11a06836..0000000000 --- a/src/Umbraco.Web/Dynamics/ExpressionParser.cs +++ /dev/null @@ -1,2311 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Dynamic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Dynamics; -using Umbraco.Web.Models; - -namespace Umbraco.Web.Dynamics -{ - //SD: I wish all of this wasn't hacked and was just the original dynamic linq from MS... sigh. Just - // means we can't really use it for anything other than dynamic node (i think) - // I'm fairly sure it's just hte convert to dynamic null stuff... still seems to work for normal linq operations would love to make it - // properly one day. - - internal class ExpressionParser - { - struct Token - { - public TokenId Id { get; set; } - public string Text { get; set; } - public int Pos { get; set; } - } - - enum TokenId - { - Unknown, - End, - Identifier, - StringLiteral, - IntegerLiteral, - RealLiteral, - Exclamation, - Percent, - Amphersand, - OpenParen, - CloseParen, - Asterisk, - Plus, - Comma, - Minus, - Dot, - Slash, - Colon, - LessThan, - Equal, - GreaterThan, - Question, - OpenBracket, - CloseBracket, - Bar, - ExclamationEqual, - DoubleAmphersand, - LessThanEqual, - LessGreater, - DoubleEqual, - GreaterThanEqual, - DoubleBar - } - - interface ILogicalSignatures - { - void F(bool x, bool y); - void F(bool? x, bool? y); - } - - interface IArithmeticSignatures - { - void F(int x, int y); - void F(uint x, uint y); - void F(long x, long y); - void F(ulong x, ulong y); - void F(float x, float y); - void F(double x, double y); - void F(decimal x, decimal y); - void F(int? x, int? y); - void F(uint? x, uint? y); - void F(long? x, long? y); - void F(ulong? x, ulong? y); - void F(float? x, float? y); - void F(double? x, double? y); - void F(decimal? x, decimal? y); - } - - interface IRelationalSignatures : IArithmeticSignatures - { - void F(string x, string y); - void F(char x, char y); - void F(DateTime x, DateTime y); - void F(TimeSpan x, TimeSpan y); - void F(char? x, char? y); - void F(DateTime? x, DateTime? y); - void F(TimeSpan? x, TimeSpan? y); - } - - interface IEqualitySignatures : IRelationalSignatures - { - void F(bool x, bool y); - void F(bool? x, bool? y); - } - - interface IAddSignatures : IArithmeticSignatures - { - void F(DateTime x, TimeSpan y); - void F(TimeSpan x, TimeSpan y); - void F(DateTime? x, TimeSpan? y); - void F(TimeSpan? x, TimeSpan? y); - } - - interface ISubtractSignatures : IAddSignatures - { - void F(DateTime x, DateTime y); - void F(DateTime? x, DateTime? y); - } - - interface INegationSignatures - { - void F(int x); - void F(long x); - void F(float x); - void F(double x); - void F(decimal x); - void F(int? x); - void F(long? x); - void F(float? x); - void F(double? x); - void F(decimal? x); - } - - interface INotSignatures - { - void F(bool x); - void F(bool? x); - } - - interface IEnumerableSignatures - { - void Where(bool predicate); - void Any(); - void Any(bool predicate); - void All(bool predicate); - void Count(); - void Count(bool predicate); - void Min(object selector); - void Max(object selector); - void Sum(int selector); - void Sum(int? selector); - void Sum(long selector); - void Sum(long? selector); - void Sum(float selector); - void Sum(float? selector); - void Sum(double selector); - void Sum(double? selector); - void Sum(decimal selector); - void Sum(decimal? selector); - void Average(int selector); - void Average(int? selector); - void Average(long selector); - void Average(long? selector); - void Average(float selector); - void Average(float? selector); - void Average(double selector); - void Average(double? selector); - void Average(decimal selector); - void Average(decimal? selector); - } - - static readonly Type[] predefinedTypes = { - typeof(Object), - typeof(Boolean), - typeof(Char), - typeof(String), - typeof(SByte), - typeof(Byte), - typeof(Int16), - typeof(UInt16), - typeof(Int32), - typeof(UInt32), - typeof(Int64), - typeof(UInt64), - typeof(Single), - typeof(Double), - typeof(Decimal), - typeof(DateTime), - typeof(TimeSpan), - typeof(Guid), - typeof(Math), - typeof(Convert) - }; - - static readonly Expression trueLiteral = Expression.Constant(true); - static readonly Expression falseLiteral = Expression.Constant(false); - static readonly Expression nullLiteral = Expression.Constant(null); - - static readonly string keywordIt = "it"; - static readonly string keywordIif = "iif"; - static readonly string keywordNew = "new"; - - static Dictionary keywords; - - Dictionary symbols; - IDictionary externals; - Dictionary literals; - ParameterExpression it; - string text; - private readonly bool _flagConvertDynamicNullToBooleanFalse; - int textPos; - int textLen; - char ch; - Token token; - - public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values, bool flagConvertDynamicNullToBooleanFalse) - { - if (expression == null) throw new ArgumentNullException("expression"); - if (keywords == null) keywords = CreateKeywords(); - symbols = new Dictionary(StringComparer.OrdinalIgnoreCase); - literals = new Dictionary(); - if (parameters != null) ProcessParameters(parameters); - if (values != null) ProcessValues(values); - text = expression; - _flagConvertDynamicNullToBooleanFalse = flagConvertDynamicNullToBooleanFalse; - textLen = text.Length; - SetTextPos(0); - NextToken(); - } - - void ProcessParameters(ParameterExpression[] parameters) - { - foreach (ParameterExpression pe in parameters) - if (!String.IsNullOrEmpty(pe.Name)) - AddSymbol(pe.Name, pe); - if (parameters.Length == 1 && String.IsNullOrEmpty(parameters[0].Name)) - it = parameters[0]; - } - - void ProcessValues(object[] values) - { - for (int i = 0; i < values.Length; i++) - { - object value = values[i]; - if (i == values.Length - 1 && value is IDictionary) - { - externals = (IDictionary)value; - } - else - { - AddSymbol("@" + i.ToString(System.Globalization.CultureInfo.InvariantCulture), value); - } - } - } - - void AddSymbol(string name, object value) - { - if (symbols.ContainsKey(name)) - throw ParseError(Res.DuplicateIdentifier, name); - symbols.Add(name, value); - } - - public Expression Parse(Type resultType) - { - int exprPos = token.Pos; - Expression expr = ParseExpression(); - if (resultType != null) - if ((expr = PromoteExpression(expr, resultType, true)) == null) - throw ParseError(exprPos, Res.ExpressionTypeMismatch, GetTypeName(resultType)); - ValidateToken(TokenId.End, Res.SyntaxError); - return expr; - } - -#pragma warning disable 0219 - public IEnumerable ParseOrdering() - { - List orderings = new List(); - while (true) - { - Expression expr = ParseExpression(); - bool ascending = true; - if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending")) - { - NextToken(); - } - else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending")) - { - NextToken(); - ascending = false; - } - orderings.Add(new DynamicOrdering { Selector = expr, Ascending = ascending }); - if (token.Id != TokenId.Comma) break; - NextToken(); - } - ValidateToken(TokenId.End, Res.SyntaxError); - return orderings; - } -#pragma warning restore 0219 - - // ?: operator - Expression ParseExpression() - { - int errorPos = token.Pos; - Expression expr = ParseLogicalOr(); - if (token.Id == TokenId.Question) - { - NextToken(); - Expression expr1 = ParseExpression(); - ValidateToken(TokenId.Colon, Res.ColonExpected); - NextToken(); - Expression expr2 = ParseExpression(); - expr = GenerateConditional(expr, expr1, expr2, errorPos); - } - return expr; - } - - // ||, or operator - Expression ParseLogicalOr() - { - Expression left = ParseLogicalAnd(); - while (token.Id == TokenId.DoubleBar || TokenIdentifierIs("or")) - { - Token op = token; - NextToken(); - Expression right = ParseLogicalAnd(); - CheckAndPromoteOperands(typeof(ILogicalSignatures), op.Text, ref left, ref right, op.Pos); - left = HandleDynamicNodeLambdas(ExpressionType.OrElse, left, right); - } - return left; - } - - // &&, and operator - Expression ParseLogicalAnd() - { - Expression left = ParseComparison(); - while (token.Id == TokenId.DoubleAmphersand || TokenIdentifierIs("and")) - { - Token op = token; - NextToken(); - Expression right = ParseComparison(); - CheckAndPromoteOperands(typeof(ILogicalSignatures), op.Text, ref left, ref right, op.Pos); - left = HandleDynamicNodeLambdas(ExpressionType.AndAlso, left, right); - } - return left; - } - - // =, ==, !=, <>, >, >=, <, <= operators - Expression ParseComparison() - { - Expression left = ParseAdditive(); - while (token.Id == TokenId.Equal || token.Id == TokenId.DoubleEqual || - token.Id == TokenId.ExclamationEqual || token.Id == TokenId.LessGreater || - token.Id == TokenId.GreaterThan || token.Id == TokenId.GreaterThanEqual || - token.Id == TokenId.LessThan || token.Id == TokenId.LessThanEqual) - { - Token op = token; - NextToken(); - Expression right = ParseAdditive(); - bool isEquality = op.Id == TokenId.Equal || op.Id == TokenId.DoubleEqual || - op.Id == TokenId.ExclamationEqual || op.Id == TokenId.LessGreater; - if (isEquality && !left.Type.IsValueType && !right.Type.IsValueType) - { - if (left.Type != right.Type) - { - if (left.Type.IsAssignableFrom(right.Type)) - { - right = Expression.Convert(right, left.Type); - } - else if (right.Type.IsAssignableFrom(left.Type)) - { - left = Expression.Convert(left, right.Type); - } - else if (left is LambdaExpression || right is LambdaExpression) - { - //do nothing here (but further down we'll handle the lambdaexpression) - } - else - { - throw IncompatibleOperandsError(op.Text, left, right, op.Pos); - } - } - } - else if (IsEnumType(left.Type) || IsEnumType(right.Type)) - { - if (left.Type != right.Type) - { - Expression e; - if ((e = PromoteExpression(right, left.Type, true)) != null) - { - right = e; - } - else if ((e = PromoteExpression(left, right.Type, true)) != null) - { - left = e; - } - else - { - throw IncompatibleOperandsError(op.Text, left, right, op.Pos); - } - } - } - else - { - CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures), - op.Text, ref left, ref right, op.Pos); - } - switch (op.Id) - { - case TokenId.Equal: - case TokenId.DoubleEqual: - left = HandleDynamicNodeLambdas(ExpressionType.Equal, left, right); - break; - case TokenId.ExclamationEqual: - case TokenId.LessGreater: - left = HandleDynamicNodeLambdas(ExpressionType.NotEqual, left, right); - break; - case TokenId.GreaterThan: - left = HandleDynamicNodeLambdas(ExpressionType.GreaterThan, left, right); - break; - case TokenId.GreaterThanEqual: - left = HandleDynamicNodeLambdas(ExpressionType.GreaterThanOrEqual, left, right); - break; - case TokenId.LessThan: - left = HandleDynamicNodeLambdas(ExpressionType.LessThan, left, right); - break; - case TokenId.LessThanEqual: - left = HandleDynamicNodeLambdas(ExpressionType.LessThanOrEqual, left, right); - break; - } - } - return left; - } - - // +, -, & operators - Expression ParseAdditive() - { - Expression left = ParseMultiplicative(); - while (token.Id == TokenId.Plus || token.Id == TokenId.Minus || - token.Id == TokenId.Amphersand) - { - Token op = token; - NextToken(); - Expression right = ParseMultiplicative(); - switch (op.Id) - { - case TokenId.Plus: - if (left.Type == typeof(string) || right.Type == typeof(string)) - goto case TokenId.Amphersand; - CheckAndPromoteOperands(typeof(IAddSignatures), op.Text, ref left, ref right, op.Pos); - left = GenerateAdd(left, right); - break; - case TokenId.Minus: - CheckAndPromoteOperands(typeof(ISubtractSignatures), op.Text, ref left, ref right, op.Pos); - left = GenerateSubtract(left, right); - break; - case TokenId.Amphersand: - left = GenerateStringConcat(left, right); - break; - } - } - return left; - } - - // *, /, %, mod operators - Expression ParseMultiplicative() - { - Expression left = ParseUnary(); - while (token.Id == TokenId.Asterisk || token.Id == TokenId.Slash || - token.Id == TokenId.Percent || TokenIdentifierIs("mod")) - { - Token op = token; - NextToken(); - Expression right = ParseUnary(); - CheckAndPromoteOperands(typeof(IArithmeticSignatures), op.Text, ref left, ref right, op.Pos); - switch (op.Id) - { - case TokenId.Asterisk: - left = Expression.Multiply(left, right); - break; - case TokenId.Slash: - left = Expression.Divide(left, right); - break; - case TokenId.Percent: - case TokenId.Identifier: - left = HandleDynamicNodeLambdas(ExpressionType.Modulo, left, right); - break; - } - } - return left; - } - - // -, !, not unary operators - Expression ParseUnary() - { - if (token.Id == TokenId.Minus || token.Id == TokenId.Exclamation || - TokenIdentifierIs("not")) - { - Token op = token; - NextToken(); - if (op.Id == TokenId.Minus && (token.Id == TokenId.IntegerLiteral || - token.Id == TokenId.RealLiteral)) - { - token.Text = "-" + token.Text; - token.Pos = op.Pos; - return ParsePrimary(); - } - Expression expr = ParseUnary(); - if (op.Id == TokenId.Minus) - { - CheckAndPromoteOperand(typeof(INegationSignatures), op.Text, ref expr, op.Pos); - expr = Expression.Negate(expr); - } - else - { - CheckAndPromoteOperand(typeof(INotSignatures), op.Text, ref expr, op.Pos); - if (expr is LambdaExpression) - { - ParameterExpression[] parameters = new ParameterExpression[(expr as LambdaExpression).Parameters.Count]; - (expr as LambdaExpression).Parameters.CopyTo(parameters, 0); - var invokedExpr = Expression.Invoke(expr, parameters); - var not = Expression.Not(Expression.TypeAs(invokedExpr, typeof(bool?))); - expr = Expression.Lambda>( - Expression.Condition( - Expression.Property(not, "HasValue"), - Expression.Property(not, "Value"), - Expression.Constant(false, typeof(bool)) - ), parameters); - } - else - { - expr = Expression.Not(expr); - } - } - return expr; - } - return ParsePrimary(); - } - - Expression ParsePrimary() - { - Expression expr = ParsePrimaryStart(); - while (true) - { - if (token.Id == TokenId.Dot) - { - NextToken(); - expr = ParseMemberAccess(null, expr); - } - else if (token.Id == TokenId.OpenBracket) - { - expr = ParseElementAccess(expr); - } - else - { - break; - } - } - return expr; - } - - Expression ParsePrimaryStart() - { - switch (token.Id) - { - case TokenId.Identifier: - return ParseIdentifier(); - case TokenId.StringLiteral: - return ParseStringLiteral(); - case TokenId.IntegerLiteral: - return ParseIntegerLiteral(); - case TokenId.RealLiteral: - return ParseRealLiteral(); - case TokenId.OpenParen: - return ParseParenExpression(); - default: - throw ParseError(Res.ExpressionExpected); - } - } - - Expression ParseStringLiteral() - { - ValidateToken(TokenId.StringLiteral); - char quote = token.Text[0]; - string s = token.Text.Substring(1, token.Text.Length - 2); - int start = 0; - while (true) - { - int i = s.IndexOf(quote, start); - if (i < 0) break; - s = s.Remove(i, 1); - start = i + 1; - } - if (quote == '\'') - { - if (s.Length != 1) - throw ParseError(Res.InvalidCharacterLiteral); - NextToken(); - return CreateLiteral(s[0], s); - } - NextToken(); - return CreateLiteral(s, s); - } - - Expression ParseIntegerLiteral() - { - ValidateToken(TokenId.IntegerLiteral); - string text = token.Text; - if (text[0] != '-') - { - ulong value; - if (!UInt64.TryParse(text, out value)) - throw ParseError(Res.InvalidIntegerLiteral, text); - NextToken(); - if (value <= (ulong)Int32.MaxValue) return CreateLiteral((int)value, text); - if (value <= (ulong)UInt32.MaxValue) return CreateLiteral((uint)value, text); - if (value <= (ulong)Int64.MaxValue) return CreateLiteral((long)value, text); - return CreateLiteral(value, text); - } - else - { - long value; - if (!Int64.TryParse(text, out value)) - throw ParseError(Res.InvalidIntegerLiteral, text); - NextToken(); - if (value >= Int32.MinValue && value <= Int32.MaxValue) - return CreateLiteral((int)value, text); - return CreateLiteral(value, text); - } - } - - Expression ParseRealLiteral() - { - ValidateToken(TokenId.RealLiteral); - string text = token.Text; - object value = null; - char last = text[text.Length - 1]; - if (last == 'F' || last == 'f') - { - float f; - if (Single.TryParse(text.Substring(0, text.Length - 1), out f)) value = f; - } - else - { - double d; - if (Double.TryParse(text, out d)) value = d; - } - if (value == null) throw ParseError(Res.InvalidRealLiteral, text); - NextToken(); - return CreateLiteral(value, text); - } - - Expression CreateLiteral(object value, string text) - { - ConstantExpression expr = Expression.Constant(value); - literals.Add(expr, text); - return expr; - } - - Expression ParseParenExpression() - { - ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); - NextToken(); - Expression e = ParseExpression(); - ValidateToken(TokenId.CloseParen, Res.CloseParenOrOperatorExpected); - NextToken(); - return e; - } - - Expression ParseIdentifier() - { - ValidateToken(TokenId.Identifier); - object value; - if (keywords.TryGetValue(token.Text, out value)) - { - if (value is Type) return ParseTypeAccess((Type)value); - if (value == (object)keywordIt) return ParseIt(); - if (value == (object)keywordIif) return ParseIif(); - if (value == (object)keywordNew) return ParseNew(); - NextToken(); - return (Expression)value; - } - if (symbols.TryGetValue(token.Text, out value) || - externals != null && externals.TryGetValue(token.Text, out value)) - { - Expression expr = value as Expression; - if (expr == null) - { - expr = Expression.Constant(value); - } - else - { - LambdaExpression lambda = expr as LambdaExpression; - if (lambda != null) return ParseLambdaInvocation(lambda); - } - NextToken(); - return expr; - } - if (it != null) return ParseMemberAccess(null, it); - throw ParseError(Res.UnknownIdentifier, token.Text); - } - - Expression ParseIt() - { - if (it == null) - throw ParseError(Res.NoItInScope); - NextToken(); - return it; - } - - Expression ParseIif() - { - int errorPos = token.Pos; - NextToken(); - Expression[] args = ParseArgumentList(); - if (args.Length != 3) - throw ParseError(errorPos, Res.IifRequiresThreeArgs); - return GenerateConditional(args[0], args[1], args[2], errorPos); - } - - Expression GenerateConditional(Expression test, Expression expr1, Expression expr2, int errorPos) - { - if (test.Type != typeof(bool)) - throw ParseError(errorPos, Res.FirstExprMustBeBool); - if (expr1.Type != expr2.Type) - { - Expression expr1as2 = expr2 != nullLiteral ? PromoteExpression(expr1, expr2.Type, true) : null; - Expression expr2as1 = expr1 != nullLiteral ? PromoteExpression(expr2, expr1.Type, true) : null; - if (expr1as2 != null && expr2as1 == null) - { - expr1 = expr1as2; - } - else if (expr2as1 != null && expr1as2 == null) - { - expr2 = expr2as1; - } - else - { - string type1 = expr1 != nullLiteral ? expr1.Type.Name : "null"; - string type2 = expr2 != nullLiteral ? expr2.Type.Name : "null"; - if (expr1as2 != null && expr2as1 != null) - throw ParseError(errorPos, Res.BothTypesConvertToOther, type1, type2); - throw ParseError(errorPos, Res.NeitherTypeConvertsToOther, type1, type2); - } - } - return Expression.Condition(test, expr1, expr2); - } - - Expression ParseNew() - { - NextToken(); - ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); - NextToken(); - List properties = new List(); - List expressions = new List(); - while (true) - { - int exprPos = token.Pos; - Expression expr = ParseExpression(); - string propName; - if (TokenIdentifierIs("as")) - { - NextToken(); - propName = GetIdentifier(); - NextToken(); - } - else - { - MemberExpression me = expr as MemberExpression; - if (me == null) throw ParseError(exprPos, Res.MissingAsClause); - propName = me.Member.Name; - } - expressions.Add(expr); - properties.Add(new DynamicProperty(propName, expr.Type)); - if (token.Id != TokenId.Comma) break; - NextToken(); - } - ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected); - NextToken(); - Type type = DynamicExpression.CreateClass(properties); - MemberBinding[] bindings = new MemberBinding[properties.Count]; - for (int i = 0; i < bindings.Length; i++) - bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]); - return Expression.MemberInit(Expression.New(type), bindings); - } - - Expression ParseLambdaInvocation(LambdaExpression lambda) - { - int errorPos = token.Pos; - NextToken(); - Expression[] args = ParseArgumentList(); - MethodBase method; - if (FindMethod(lambda.Type, "Invoke", false, args, out method) != 1) - throw ParseError(errorPos, Res.ArgsIncompatibleWithLambda); - return Expression.Invoke(lambda, args); - } - - Expression ParseTypeAccess(Type type) - { - int errorPos = token.Pos; - NextToken(); - if (token.Id == TokenId.Question) - { - if (!type.IsValueType || IsNullableType(type)) - throw ParseError(errorPos, Res.TypeHasNoNullableForm, GetTypeName(type)); - type = typeof(Nullable<>).MakeGenericType(type); - NextToken(); - } - if (token.Id == TokenId.OpenParen) - { - Expression[] args = ParseArgumentList(); - MethodBase method; - switch (FindBestMethod(type.GetConstructors(), args, out method)) - { - case 0: - if (args.Length == 1) - return GenerateConversion(args[0], type, errorPos); - throw ParseError(errorPos, Res.NoMatchingConstructor, GetTypeName(type)); - case 1: - return Expression.New((ConstructorInfo)method, args); - default: - throw ParseError(errorPos, Res.AmbiguousConstructorInvocation, GetTypeName(type)); - } - } - ValidateToken(TokenId.Dot, Res.DotOrOpenParenExpected); - NextToken(); - return ParseMemberAccess(type, null); - } - - Expression GenerateConversion(Expression expr, Type type, int errorPos) - { - Type exprType = expr.Type; - if (exprType == type) return expr; - if (exprType.IsValueType && type.IsValueType) - { - if ((IsNullableType(exprType) || IsNullableType(type)) && - GetNonNullableType(exprType) == GetNonNullableType(type)) - return Expression.Convert(expr, type); - if ((IsNumericType(exprType) || IsEnumType(exprType)) && - (IsNumericType(type)) || IsEnumType(type)) - return Expression.ConvertChecked(expr, type); - } - if (exprType.IsAssignableFrom(type) || type.IsAssignableFrom(exprType) || - exprType.IsInterface || type.IsInterface) - return Expression.Convert(expr, type); - throw ParseError(errorPos, Res.CannotConvertValue, - GetTypeName(exprType), GetTypeName(type)); - } - - Expression ParseMemberAccess(Type type, Expression instance) - { - //NOTE: SD: There is a lot of string checking going on here and I'm 99% sure this can all be done better - // in a more generic sense to support any types with any extension methods, etc... - // Too bad whoever wrote this decided not to put any code comments in :( - // This is how to support method calls, etc... in dynamic statements. - - if (instance != null) type = instance.Type; - int errorPos = token.Pos; - string id = GetIdentifier(); - NextToken(); - if (token.Id == TokenId.OpenParen) - { - if (instance != null && type != typeof(string)) - { - Type enumerableType = FindGenericType(typeof(IEnumerable<>), type); - if (enumerableType != null) - { - Type elementType = enumerableType.GetGenericArguments()[0]; - return ParseAggregate(instance, elementType, id, errorPos); - } - } - Expression[] args = ParseArgumentList(); - MethodBase mb; - LambdaExpression instanceAsString = null; - ParameterExpression instanceExpression = Expression.Parameter(typeof(T), "instance"); - if (type.IsGenericType && type != typeof(string)) - { - var typeArgs = type.GetGenericArguments(); - if (typeArgs[0] == typeof(T)) - { - if (instance != null && instance is LambdaExpression) - { - //not sure why this is object or why we need to do this but if we change it, things die... - //also not sure why it is changed to string, i think this might be to ensure string methods are supported - //but seems to me that we then won't support other types of methods? - if (typeArgs[1] == typeof(object)) - { - instanceAsString = StringFormat(instance as LambdaExpression, instanceExpression); - type = typeof(string); - } - else if (typeArgs[1] == typeof(string)) - { - instanceAsString = instance as LambdaExpression; - type = typeof(string); - } - //else - //{ - // instanceAsString = instance as LambdaExpression; - // type = typeArgs[1]; - //} - - } - } - } - switch (FindMethod(type, id, instance == null, args, out mb)) - { - case 0: - //not found - - //SD: I have yet to see extension methods actually being called in the dynamic parsing... need to unit test these - // scenarios and figure out why all this type checking occurs. - - var runtimeCache = ApplicationContext.Current != null ? ApplicationContext.Current.ApplicationCache.RuntimeCache : new NullCacheProvider(); - - if (type == typeof(string) && instanceAsString != null) - { - Expression[] newArgs = (new List() { Expression.Invoke(instanceAsString, instanceExpression) }).Concat(args).ToArray(); - mb = ExtensionMethodFinder.FindExtensionMethod(runtimeCache, typeof(string), newArgs, id, true); - if (mb != null) - { - return CallMethodOnDynamicNode(instance, newArgs, instanceAsString, instanceExpression, (MethodInfo)mb, true); - } - } - if (type == typeof(string) && instanceAsString == null && instance is MemberExpression) - { - Expression[] newArgs = (new List() { instance }).Concat(args).ToArray(); - mb = ExtensionMethodFinder.FindExtensionMethod(runtimeCache, typeof(string), newArgs, id, true); - if (mb != null) - { - return Expression.Call(null, (MethodInfo)mb, newArgs); - } - } - - throw ParseError(errorPos, Res.NoApplicableMethod, - id, GetTypeName(type)); - case 1: - MethodInfo method = (MethodInfo)mb; - if (!IsPredefinedType(method.DeclaringType)) - throw ParseError(errorPos, Res.MethodsAreInaccessible, GetTypeName(method.DeclaringType)); - if (method.ReturnType == typeof(void)) - throw ParseError(errorPos, Res.MethodIsVoid, - id, GetTypeName(method.DeclaringType)); - if (instanceAsString != null) - { - return CallMethodOnDynamicNode(instance, args, instanceAsString, instanceExpression, method, false); - } - return Expression.Call(instance, (MethodInfo)method, args); - default: - throw ParseError(errorPos, Res.AmbiguousMethodInvocation, - id, GetTypeName(type)); - } - } - else - { - //Looks for a member on the type, but above, we're rerouting that into TryGetMember - MemberInfo member = FindPropertyOrField(type, id, instance == null); - if (member == null) - { - if (typeof(DynamicObject).IsAssignableFrom(type)) - { - //We are going to generate a dynamic method by hand coding the expression tree - //this will invoke TryGetMember (but wrapped in an expression tree) - //so that when it's evaluated, DynamicNode should be supported - - ParameterExpression instanceExpression = Expression.Parameter(typeof(T), "instance"); - ParameterExpression convertDynamicNullToBooleanFalse = Expression.Parameter(typeof(bool), "convertDynamicNullToBooleanFalse"); - ParameterExpression result = Expression.Parameter(typeof(object), "result"); - ParameterExpression binder = Expression.Variable(typeof(DynamicQueryableGetMemberBinder), "binder"); - ParameterExpression ignoreCase = Expression.Variable(typeof(bool), "ignoreCase"); - ConstructorInfo getMemberBinderConstructor = typeof(DynamicQueryableGetMemberBinder).GetConstructor(new Type[] { typeof(string), typeof(bool) }); - LabelTarget blockReturnLabel = Expression.Label(typeof(object)); - MethodInfo method = typeof(T).GetMethod("TryGetMember"); - - BlockExpression block = Expression.Block( - typeof(object), - new[] { ignoreCase, binder, result, convertDynamicNullToBooleanFalse }, - Expression.Assign(convertDynamicNullToBooleanFalse, Expression.Constant(_flagConvertDynamicNullToBooleanFalse, typeof(bool))), - Expression.Assign(ignoreCase, Expression.Constant(false, typeof(bool))), - Expression.Assign(binder, Expression.New(getMemberBinderConstructor, Expression.Constant(id, typeof(string)), ignoreCase)), - Expression.Assign(result, Expression.Constant(null)), - Expression.IfThen(Expression.NotEqual(Expression.Constant(null), instanceExpression), - Expression.Call(instanceExpression, method, binder, result)), - Expression.IfThen( - Expression.AndAlso( - Expression.TypeEqual(result, typeof(DynamicNull)), - Expression.Equal(convertDynamicNullToBooleanFalse, Expression.Constant(true, typeof(bool))) - ), - Expression.Assign(result, Expression.Constant(false, typeof(object))) - ), - Expression.Return(blockReturnLabel, result), - Expression.Label(blockReturnLabel, Expression.Constant(-2, typeof(object))) - ); - LambdaExpression lax = Expression.Lambda>(block, instanceExpression); - return lax; - } - if (typeof(Func).IsAssignableFrom(type)) - { - //accessing a property off an already resolved DynamicNode TryGetMember call - //e.g. uBlogsyPostDate.Date - //SD: Removed the NonPublic accessor here because this will never work in medium trust, wondering why it is NonPublic vs Public ? Have changed to Public. - //MethodInfo ReflectPropertyValue = this.GetType().GetMethod("ReflectPropertyValue", BindingFlags.NonPublic | BindingFlags.Static); - MethodInfo reflectPropertyValue = this.GetType().GetMethod("ReflectPropertyValue", BindingFlags.Public | BindingFlags.Static); - ParameterExpression convertDynamicNullToBooleanFalse = Expression.Parameter(typeof(bool), "convertDynamicNullToBooleanFalse"); - ParameterExpression result = Expression.Parameter(typeof(object), "result"); - ParameterExpression idParam = Expression.Parameter(typeof(string), "id"); - ParameterExpression lambdaResult = Expression.Parameter(typeof(object), "lambdaResult"); - ParameterExpression lambdaInstanceExpression = Expression.Parameter(typeof(T), "lambdaInstanceExpression"); - ParameterExpression instanceExpression = Expression.Parameter(typeof(Func), "instance"); - LabelTarget blockReturnLabel = Expression.Label(typeof(object)); - - BlockExpression block = Expression.Block( - typeof(object), - new[] { lambdaResult, result, idParam, convertDynamicNullToBooleanFalse }, - Expression.Assign(convertDynamicNullToBooleanFalse, Expression.Constant(_flagConvertDynamicNullToBooleanFalse, typeof(bool))), - Expression.Assign(lambdaResult, Expression.Invoke(instance, lambdaInstanceExpression)), - Expression.Assign(result, Expression.Call(reflectPropertyValue, lambdaResult, Expression.Constant(id))), - Expression.IfThen( - Expression.AndAlso( - Expression.TypeEqual(result, typeof(DynamicNull)), - Expression.Equal(convertDynamicNullToBooleanFalse, Expression.Constant(true, typeof(bool))) - ), - Expression.Assign(result, Expression.Constant(false, typeof(object))) - ), - Expression.Return(blockReturnLabel, result), - Expression.Label(blockReturnLabel, Expression.Constant(-2, typeof(object))) - ); - LambdaExpression lax = Expression.Lambda>(block, lambdaInstanceExpression); - return lax; - } - } - else - { - return member is PropertyInfo ? - Expression.Property(instance, (PropertyInfo)member) : - Expression.Field(instance, (FieldInfo)member); - } - throw ParseError(errorPos, Res.UnknownPropertyOrField, - id, GetTypeName(type)); - - } - } - public static object ReflectPropertyValue(object o, string name) - { - PropertyInfo propertyInfo = o.GetType().GetProperty(name); - if (propertyInfo != null) - { - object result = propertyInfo.GetValue(o, null); - return result; - } - return null; - } - private static Expression CallMethodOnDynamicNode(Expression instance, Expression[] args, LambdaExpression instanceAsString, ParameterExpression instanceExpression, MethodInfo method, bool isStatic) - { - Type methodReturnType = method.ReturnType; - - var defaultReturnValue = Expression.Constant(methodReturnType.GetDefaultValue(), methodReturnType); - - ParameterExpression result = Expression.Parameter(method.ReturnType, "result"); - LabelTarget blockReturnLabel = Expression.Label(method.ReturnType); - BlockExpression block = Expression.Block( - method.ReturnType, - new[] { result }, - Expression.Assign(result, - Expression.Call( - isStatic ? null : Expression.Invoke(instanceAsString, instanceExpression), - method, - args) - ), - Expression.Return(blockReturnLabel, result), - Expression.Label(blockReturnLabel, defaultReturnValue) - ); - - Type func = typeof(Func<,>); - Type generic = func.MakeGenericType(typeof(T), methodReturnType); - return Expression.Lambda(generic, block, instanceExpression); - - //if (methodReturnType == typeof(string)) - // return Expression.Lambda>(block, instanceExpression); - //if (methodReturnType == typeof(int)) - // return Expression.Lambda>(block, instanceExpression); - //if (methodReturnType == typeof(bool)) - // return Expression.Lambda>(block, instanceExpression); - //if (methodReturnType == typeof(string[])) - //return Expression.Lambda>(block, instanceExpression); - - //return Expression.Call(instance, (MethodInfo)method, args); - - //return Expression.Lambda>( - // Expression.Convert(block, typeof(object)), instanceExpression); - - } - - static Type FindGenericType(Type generic, Type type) - { - while (type != null && type != typeof(object)) - { - if (type.IsGenericType && type.GetGenericTypeDefinition() == generic) return type; - if (generic.IsInterface) - { - foreach (Type intfType in type.GetInterfaces()) - { - Type found = FindGenericType(generic, intfType); - if (found != null) return found; - } - } - type = type.BaseType; - } - return null; - } - LambdaExpression StringFormat(LambdaExpression lax, ParameterExpression instanceExpression) - { - ParameterExpression cresult = Expression.Parameter(typeof(string), "cresult"); - ParameterExpression temp = Expression.Parameter(typeof(object), "temp"); - ParameterExpression stemp = Expression.Parameter(typeof(string), "string"); - LabelTarget cblockReturnLabel = Expression.Label(typeof(string)); - - MethodInfo stringFormat = typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(object) }); - BlockExpression cblock = Expression.Block( - typeof(string), - new[] { cresult, temp }, - Expression.Assign(temp, Expression.Invoke(lax, instanceExpression)), - Expression.Assign(cresult, Expression.Call(stringFormat, Expression.Constant("{0}"), temp)), - Expression.Return(cblockReturnLabel, cresult), - Expression.Label(cblockReturnLabel, Expression.Constant(null, typeof(string)))); - - LambdaExpression lax2 = Expression.Lambda>(cblock, instanceExpression); - var expression = Expression.Lambda>(cblock, instanceExpression); - return expression; - - } - Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos) - { - ParameterExpression outerIt = it; - ParameterExpression innerIt = Expression.Parameter(elementType, ""); - it = innerIt; - Expression[] args = ParseArgumentList(); - it = outerIt; - MethodBase signature; - if (FindMethod(typeof(IEnumerableSignatures), methodName, false, args, out signature) != 1) - throw ParseError(errorPos, Res.NoApplicableAggregate, methodName); - Type[] typeArgs; - if (signature.Name == "Min" || signature.Name == "Max") - { - typeArgs = new Type[] { elementType, args[0].Type }; - } - else - { - typeArgs = new Type[] { elementType }; - } - if (args.Length == 0) - { - args = new Expression[] { instance }; - } - else - { - args = new Expression[] { instance, Expression.Lambda(args[0], innerIt) }; - } - return Expression.Call(typeof(Enumerable), signature.Name, typeArgs, args); - } - - Expression[] ParseArgumentList() - { - ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); - NextToken(); - Expression[] args = token.Id != TokenId.CloseParen ? ParseArguments() : new Expression[0]; - ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected); - NextToken(); - return args; - } - - Expression[] ParseArguments() - { - List argList = new List(); - while (true) - { - argList.Add(ParseExpression()); - if (token.Id != TokenId.Comma) break; - NextToken(); - } - return argList.ToArray(); - } - - Expression ParseElementAccess(Expression expr) - { - int errorPos = token.Pos; - ValidateToken(TokenId.OpenBracket, Res.OpenParenExpected); - NextToken(); - Expression[] args = ParseArguments(); - ValidateToken(TokenId.CloseBracket, Res.CloseBracketOrCommaExpected); - NextToken(); - if (expr.Type.IsArray) - { - if (expr.Type.GetArrayRank() != 1 || args.Length != 1) - throw ParseError(errorPos, Res.CannotIndexMultiDimArray); - Expression index = PromoteExpression(args[0], typeof(int), true); - if (index == null) - throw ParseError(errorPos, Res.InvalidIndex); - return Expression.ArrayIndex(expr, index); - } - else - { - MethodBase mb; - switch (FindIndexer(expr.Type, args, out mb)) - { - case 0: - throw ParseError(errorPos, Res.NoApplicableIndexer, - GetTypeName(expr.Type)); - case 1: - return Expression.Call(expr, (MethodInfo)mb, args); - default: - throw ParseError(errorPos, Res.AmbiguousIndexerInvocation, - GetTypeName(expr.Type)); - } - } - } - - static bool IsPredefinedType(Type type) - { - foreach (Type t in predefinedTypes) if (t == type) return true; - return false; - } - - static bool IsNullableType(Type type) - { - return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); - } - - static Type GetNonNullableType(Type type) - { - return IsNullableType(type) ? type.GetGenericArguments()[0] : type; - } - - static string GetTypeName(Type type) - { - Type baseType = GetNonNullableType(type); - string s = baseType.Name; - if (type != baseType) s += '?'; - return s; - } - - static bool IsNumericType(Type type) - { - return GetNumericTypeKind(type) != 0; - } - - static bool IsSignedIntegralType(Type type) - { - return GetNumericTypeKind(type) == 2; - } - - static bool IsUnsignedIntegralType(Type type) - { - return GetNumericTypeKind(type) == 3; - } - - static int GetNumericTypeKind(Type type) - { - type = GetNonNullableType(type); - if (type.IsEnum) return 0; - switch (Type.GetTypeCode(type)) - { - case TypeCode.Char: - case TypeCode.Single: - case TypeCode.Double: - case TypeCode.Decimal: - return 1; - case TypeCode.SByte: - case TypeCode.Int16: - case TypeCode.Int32: - case TypeCode.Int64: - return 2; - case TypeCode.Byte: - case TypeCode.UInt16: - case TypeCode.UInt32: - case TypeCode.UInt64: - return 3; - default: - return 0; - } - } - - static bool IsEnumType(Type type) - { - return GetNonNullableType(type).IsEnum; - } - - void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos) - { - Expression[] args = new Expression[] { expr }; - MethodBase method; - if (FindMethod(signatures, "F", false, args, out method) != 1) - throw ParseError(errorPos, Res.IncompatibleOperand, - opName, GetTypeName(args[0].Type)); - expr = args[0]; - } - - void CheckAndPromoteOperands(Type signatures, string opName, ref Expression left, ref Expression right, int errorPos) - { - Expression[] args = new Expression[] { left, right }; - MethodBase method; - if (FindMethod(signatures, "F", false, args, out method) != 1) - throw IncompatibleOperandsError(opName, left, right, errorPos); - left = args[0]; - right = args[1]; - } - - Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int pos) - { - return ParseError(pos, Res.IncompatibleOperands, - opName, GetTypeName(left.Type), GetTypeName(right.Type)); - } - - MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess) - { - BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | - (staticAccess ? BindingFlags.Static : BindingFlags.Instance); - foreach (Type t in SelfAndBaseTypes(type)) - { - MemberInfo[] members = t.FindMembers(MemberTypes.Property | MemberTypes.Field, - flags, Type.FilterNameIgnoreCase, memberName); - if (members.Length != 0) return members[0]; - } - return null; - } - - int FindMethod(Type type, string methodName, bool staticAccess, Expression[] args, out MethodBase method) - { - BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | - (staticAccess ? BindingFlags.Static : BindingFlags.Instance); - foreach (Type t in SelfAndBaseTypes(type)) - { - MemberInfo[] members = t.FindMembers(MemberTypes.Method, - flags, Type.FilterNameIgnoreCase, methodName); - int count = FindBestMethod(members.Cast(), args, out method); - if (count != 0) return count; - } - method = null; - return 0; - } - - int FindIndexer(Type type, Expression[] args, out MethodBase method) - { - foreach (Type t in SelfAndBaseTypes(type)) - { - MemberInfo[] members = t.GetDefaultMembers(); - if (members.Length != 0) - { - IEnumerable methods = members. - OfType(). - Select(p => (MethodBase)p.GetGetMethod()). - Where(m => m != null); - int count = FindBestMethod(methods, args, out method); - if (count != 0) return count; - } - } - method = null; - return 0; - } - - static IEnumerable SelfAndBaseTypes(Type type) - { - if (type.IsInterface) - { - List types = new List(); - AddInterface(types, type); - return types; - } - return SelfAndBaseClasses(type); - } - - static IEnumerable SelfAndBaseClasses(Type type) - { - while (type != null) - { - yield return type; - type = type.BaseType; - } - } - - static void AddInterface(List types, Type type) - { - if (!types.Contains(type)) - { - types.Add(type); - foreach (Type t in type.GetInterfaces()) AddInterface(types, t); - } - } - - class MethodData - { - public MethodBase MethodBase; - public ParameterInfo[] Parameters; - public Expression[] Args; - } - - int FindBestMethod(IEnumerable methods, Expression[] args, out MethodBase method) - { - MethodData[] applicable = methods. - Select(m => new MethodData { MethodBase = m, Parameters = m.GetParameters() }). - Where(m => IsApplicable(m, args)). - ToArray(); - if (applicable.Length > 1) - { - applicable = applicable. - Where(m => applicable.All(n => m == n || IsBetterThan(args, m, n))). - ToArray(); - } - if (applicable.Length == 1) - { - MethodData md = applicable[0]; - for (int i = 0; i < args.Length; i++) args[i] = md.Args[i]; - method = md.MethodBase; - } - else - { - method = null; - } - return applicable.Length; - } - - bool IsApplicable(MethodData method, Expression[] args) - { - if (method.Parameters.Length != args.Length) return false; - Expression[] promotedArgs = new Expression[args.Length]; - for (int i = 0; i < args.Length; i++) - { - ParameterInfo pi = method.Parameters[i]; - if (pi.IsOut) return false; - Expression promoted; - - //TODO: Turns out this is real difficult to parse and don't really have time to figure this out at the moment - // to parse params parameter arrays. - - ////here we need to check if it is a params array parameter - //if (pi.ParameterType.IsArray - // && pi.ParameterType.GetElementType() != null - // && pi.GetCustomAttributes(typeof(ParamArrayAttribute), false).Any()) - //{ - // //it is a params parameter so convert the value to an array - // promoted = PromoteExpression(args[i], pi.ParameterType.GetElementType(), false); - //} - //else - //{ - promoted = PromoteExpression(args[i], pi.ParameterType, false); - //} - if (promoted == null) return false; - promotedArgs[i] = promoted; - } - method.Args = promotedArgs; - return true; - } - - Expression PromoteExpression(Expression expr, Type type, bool exact) - { - //if the type of the expression is the correct target type, just return it here - if (expr.Type == type) return expr; - //if the type of the expression is a func - invokable returning object, - //we are going to return it here, because we can get the real value when we actually have the instance - //if (typeof(Func).IsAssignableFrom(expr.Type)) return expr; - if (expr is LambdaExpression && ((LambdaExpression)expr).Parameters.Count > 0 && ((LambdaExpression)expr).Parameters[0].Type == typeof(T)) - { - return expr; - } - if (expr is ConstantExpression) - { - ConstantExpression ce = (ConstantExpression)expr; - if (ce == nullLiteral) - { - if (!type.IsValueType || IsNullableType(type)) - return Expression.Constant(null, type); - } - else - { - string text; - if (literals.TryGetValue(ce, out text)) - { - Type target = GetNonNullableType(type); - Object value = null; - switch (Type.GetTypeCode(ce.Type)) - { - case TypeCode.Int32: - case TypeCode.UInt32: - case TypeCode.Int64: - case TypeCode.UInt64: - value = ParseNumber(text, target); - break; - case TypeCode.Double: - if (target == typeof(decimal)) value = ParseNumber(text, target); - break; - case TypeCode.String: - value = ParseEnum(text, target); - break; - } - if (value != null) - return Expression.Constant(value, type); - } - } - } - if (IsCompatibleWith(expr.Type, type)) - { - if (type.IsValueType || exact) return Expression.Convert(expr, type); - return expr; - } - return null; - } - - static object ParseNumber(string text, Type type) - { - switch (Type.GetTypeCode(GetNonNullableType(type))) - { - case TypeCode.SByte: - sbyte sb; - if (sbyte.TryParse(text, out sb)) return sb; - break; - case TypeCode.Byte: - byte b; - if (byte.TryParse(text, out b)) return b; - break; - case TypeCode.Int16: - short s; - if (short.TryParse(text, out s)) return s; - break; - case TypeCode.UInt16: - ushort us; - if (ushort.TryParse(text, out us)) return us; - break; - case TypeCode.Int32: - int i; - if (int.TryParse(text, out i)) return i; - break; - case TypeCode.UInt32: - uint ui; - if (uint.TryParse(text, out ui)) return ui; - break; - case TypeCode.Int64: - long l; - if (long.TryParse(text, out l)) return l; - break; - case TypeCode.UInt64: - ulong ul; - if (ulong.TryParse(text, out ul)) return ul; - break; - case TypeCode.Single: - float f; - if (float.TryParse(text, out f)) return f; - break; - case TypeCode.Double: - double d; - if (double.TryParse(text, out d)) return d; - break; - case TypeCode.Decimal: - decimal e; - if (decimal.TryParse(text, out e)) return e; - break; - } - return null; - } - - static object ParseEnum(string name, Type type) - { - if (type.IsEnum) - { - MemberInfo[] memberInfos = type.FindMembers(MemberTypes.Field, - BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static, - Type.FilterNameIgnoreCase, name); - if (memberInfos.Length != 0) return ((FieldInfo)memberInfos[0]).GetValue(null); - } - return null; - } - - static bool IsCompatibleWith(Type source, Type target) - { - if (source == target) return true; - if (!target.IsValueType) return target.IsAssignableFrom(source); - Type st = GetNonNullableType(source); - Type tt = GetNonNullableType(target); - if (st != source && tt == target) return false; - TypeCode sc = st.IsEnum ? TypeCode.Object : Type.GetTypeCode(st); - TypeCode tc = tt.IsEnum ? TypeCode.Object : Type.GetTypeCode(tt); - switch (sc) - { - case TypeCode.SByte: - switch (tc) - { - case TypeCode.SByte: - case TypeCode.Int16: - case TypeCode.Int32: - case TypeCode.Int64: - case TypeCode.Single: - case TypeCode.Double: - case TypeCode.Decimal: - return true; - } - break; - case TypeCode.Byte: - switch (tc) - { - case TypeCode.Byte: - case TypeCode.Int16: - case TypeCode.UInt16: - case TypeCode.Int32: - case TypeCode.UInt32: - case TypeCode.Int64: - case TypeCode.UInt64: - case TypeCode.Single: - case TypeCode.Double: - case TypeCode.Decimal: - return true; - } - break; - case TypeCode.Int16: - switch (tc) - { - case TypeCode.Int16: - case TypeCode.Int32: - case TypeCode.Int64: - case TypeCode.Single: - case TypeCode.Double: - case TypeCode.Decimal: - return true; - } - break; - case TypeCode.UInt16: - switch (tc) - { - case TypeCode.UInt16: - case TypeCode.Int32: - case TypeCode.UInt32: - case TypeCode.Int64: - case TypeCode.UInt64: - case TypeCode.Single: - case TypeCode.Double: - case TypeCode.Decimal: - return true; - } - break; - case TypeCode.Int32: - switch (tc) - { - case TypeCode.Int32: - case TypeCode.Int64: - case TypeCode.Single: - case TypeCode.Double: - case TypeCode.Decimal: - return true; - } - break; - case TypeCode.UInt32: - switch (tc) - { - case TypeCode.UInt32: - case TypeCode.Int64: - case TypeCode.UInt64: - case TypeCode.Single: - case TypeCode.Double: - case TypeCode.Decimal: - return true; - } - break; - case TypeCode.Int64: - switch (tc) - { - case TypeCode.Int64: - case TypeCode.Single: - case TypeCode.Double: - case TypeCode.Decimal: - return true; - } - break; - case TypeCode.UInt64: - switch (tc) - { - case TypeCode.UInt64: - case TypeCode.Single: - case TypeCode.Double: - case TypeCode.Decimal: - return true; - } - break; - case TypeCode.Single: - switch (tc) - { - case TypeCode.Single: - case TypeCode.Double: - return true; - } - break; - default: - if (st == tt) return true; - break; - } - return false; - } - - static bool IsBetterThan(Expression[] args, MethodData m1, MethodData m2) - { - bool better = false; - for (int i = 0; i < args.Length; i++) - { - int c = CompareConversions(args[i].Type, - m1.Parameters[i].ParameterType, - m2.Parameters[i].ParameterType); - if (c < 0) return false; - if (c > 0) better = true; - } - return better; - } - - // Return 1 if s -> t1 is a better conversion than s -> t2 - // Return -1 if s -> t2 is a better conversion than s -> t1 - // Return 0 if neither conversion is better - static int CompareConversions(Type s, Type t1, Type t2) - { - if (t1 == t2) return 0; - if (s == t1) return 1; - if (s == t2) return -1; - bool t1t2 = IsCompatibleWith(t1, t2); - bool t2t1 = IsCompatibleWith(t2, t1); - if (t1t2 && !t2t1) return 1; - if (t2t1 && !t1t2) return -1; - if (IsSignedIntegralType(t1) && IsUnsignedIntegralType(t2)) return 1; - if (IsSignedIntegralType(t2) && IsUnsignedIntegralType(t1)) return -1; - return 0; - } - - Expression GenerateEqual(Expression left, Expression right) - { - return HandleDynamicNodeLambdas(ExpressionType.Equal, left, right); - } - - private static Expression HandleDynamicNodeLambdas(ExpressionType expressionType, Expression left, Expression right) - { - bool leftIsLambda = false, rightIsLambda = false; - Expression innerLeft = null; - Expression innerRight = null; - UnaryExpression unboxedLeft = null, unboxedRight = null; - ParameterExpression[] parameters = null; - - if (left is LambdaExpression && (left as LambdaExpression).Type.GetGenericArguments().First() == typeof(T)) - { - leftIsLambda = true; - } - - if (right is LambdaExpression && (right as LambdaExpression).Type.GetGenericArguments().First() == typeof(T)) - { - rightIsLambda = true; - } - - if (leftIsLambda && !rightIsLambda) - { - parameters = new ParameterExpression[(left as LambdaExpression).Parameters.Count]; - (left as LambdaExpression).Parameters.CopyTo(parameters, 0); - if (right is ConstantExpression) - { - //left lambda, right constant - var invokedExpr = Expression.Invoke(left, (left as LambdaExpression).Parameters.Cast()); - innerLeft = Expression.Convert(invokedExpr, (right as ConstantExpression).Type); - } - if (leftIsLambda && !rightIsLambda && right is MemberExpression) - { - var invokedExpr = Expression.Invoke(left, (left as LambdaExpression).Parameters.Cast()); - innerLeft = Expression.Convert(invokedExpr, (right as MemberExpression).Type); - } - } - if (rightIsLambda && !leftIsLambda) - { - parameters = new ParameterExpression[(right as LambdaExpression).Parameters.Count]; - (right as LambdaExpression).Parameters.CopyTo(parameters, 0); - if (left is ConstantExpression) - { - //right lambda, left constant - var invokedExpr = Expression.Invoke(right, (right as LambdaExpression).Parameters.Cast()); - innerRight = Expression.Convert(invokedExpr, (left as ConstantExpression).Type); - } - if (right is MemberExpression) - { - var invokedExpr = Expression.Invoke(right, (right as LambdaExpression).Parameters.Cast()); - innerRight = Expression.Convert(invokedExpr, (left as MemberExpression).Type); - } - } - bool sequenceEqual = false; - if (leftIsLambda && rightIsLambda) - { - { - Type leftType = ((LambdaExpression)left).Type; - Type rightType = ((LambdaExpression)right).Type; - Type[] leftTypeGenericArguments = leftType.GetGenericArguments(); - Type[] rightTypeGenericArguments = rightType.GetGenericArguments(); - if (leftTypeGenericArguments.SequenceEqual(rightTypeGenericArguments)) - { - sequenceEqual = true; - if (leftTypeGenericArguments.Length == 2) - { - Type TOut = leftTypeGenericArguments[1]; - - if (expressionType == ExpressionType.AndAlso) - { - return ExpressionExtensions.And(left as Expression>, right as Expression>); - } - if (expressionType == ExpressionType.OrElse) - { - return ExpressionExtensions.Or(left as Expression>, right as Expression>); - } - - } - } - else - { - if (leftTypeGenericArguments.Length == 2) - { - //sequence not equal - could be Func && Func - if (leftTypeGenericArguments.First() == rightTypeGenericArguments.First()) - { - bool leftIsObject = leftTypeGenericArguments.ElementAt(1) == typeof(object); - bool rightIsObject = rightTypeGenericArguments.ElementAt(1) == typeof(object); - //if one is an object but not the other - if (leftIsObject ^ rightIsObject) - { - if (leftIsObject) - { - //left side is object - if (innerLeft == null) - { - parameters = new ParameterExpression[(left as LambdaExpression).Parameters.Count]; - (left as LambdaExpression).Parameters.CopyTo(parameters, 0); - innerLeft = Expression.Invoke(left, parameters); - } - unboxedLeft = Expression.Unbox(innerLeft, rightTypeGenericArguments.ElementAt(1)); - - //left is invoked and unboxed to right's TOut, right was not boxed - if (expressionType == ExpressionType.AndAlso) - { - return ExpressionExtensions.And(right as Expression>, Expression.Lambda>(unboxedLeft, parameters) as Expression>); - } - if (expressionType == ExpressionType.OrElse) - { - return ExpressionExtensions.And(right as Expression>, Expression.Lambda>(unboxedLeft, parameters) as Expression>); - } - } - else - { - //right side is object - if (innerRight == null) - { - parameters = new ParameterExpression[(right as LambdaExpression).Parameters.Count]; - (right as LambdaExpression).Parameters.CopyTo(parameters, 0); - innerRight = Expression.Invoke(right, parameters); - } - unboxedRight = Expression.Unbox(innerRight, leftTypeGenericArguments.ElementAt(1)); - - //right is invoked and unboxed to left's TOut, left was not boxed - if (expressionType == ExpressionType.AndAlso) - { - return ExpressionExtensions.And(left as Expression>, Expression.Lambda>(unboxedRight, parameters) as Expression>); - } - if (expressionType == ExpressionType.OrElse) - { - return ExpressionExtensions.And(left as Expression>, Expression.Lambda>(unboxedRight, parameters) as Expression>); - } - } - - } - } - } - } - } - } - - if (leftIsLambda && innerLeft == null) - { - //left is a lambda, but the right was an unhandled expression type - //!ConstantExpression, !MemberExpression - //make sure the left gets invoked - if (parameters == null) - { - parameters = new ParameterExpression[(left as LambdaExpression).Parameters.Count]; - (left as LambdaExpression).Parameters.CopyTo(parameters, 0); - } - innerLeft = Expression.Invoke(left, parameters); - } - if (rightIsLambda && innerRight == null) - { - //right is a lambda, but the left was an unhandled expression type - //!ConstantExpression, !MemberExpression - //make sure the right gets invoked - if (parameters == null) - { - parameters = new ParameterExpression[(right as LambdaExpression).Parameters.Count]; - (right as LambdaExpression).Parameters.CopyTo(parameters, 0); - } - innerRight = Expression.Invoke(right, parameters); - } - if (leftIsLambda && !rightIsLambda && innerLeft != null && !(innerLeft is UnaryExpression) && innerLeft.Type == typeof(object)) - { - //innerLeft is an invoke - unboxedLeft = Expression.Unbox(innerLeft, right.Type); - } - if (rightIsLambda && !leftIsLambda && innerRight != null && !(innerRight is UnaryExpression) && innerRight.Type == typeof(object)) - { - //innerRight is an invoke - unboxedRight = Expression.Unbox(innerRight, left.Type); - } - - BinaryExpression binaryExpression = null; - var finalLeft = unboxedLeft ?? innerLeft ?? left; - var finalRight = unboxedRight ?? innerRight ?? right; - switch (expressionType) - { - case ExpressionType.Equal: - binaryExpression = Expression.Equal(finalLeft, finalRight); - break; - case ExpressionType.NotEqual: - binaryExpression = Expression.NotEqual(finalLeft, finalRight); - break; - case ExpressionType.GreaterThan: - binaryExpression = Expression.GreaterThan(finalLeft, finalRight); - break; - case ExpressionType.LessThan: - binaryExpression = Expression.LessThan(finalLeft, finalRight); - break; - case ExpressionType.GreaterThanOrEqual: - binaryExpression = Expression.GreaterThanOrEqual(finalLeft, finalRight); - break; - case ExpressionType.LessThanOrEqual: - binaryExpression = Expression.LessThanOrEqual(finalLeft, finalRight); - break; - case ExpressionType.Modulo: - binaryExpression = Expression.Modulo(finalLeft, finalRight); - return (Expression.Lambda>(binaryExpression, parameters)); - case ExpressionType.AndAlso: - if ((leftIsLambda && rightIsLambda && sequenceEqual) || (!leftIsLambda && !rightIsLambda)) - { - return Expression.AndAlso(left, right); - } - else - { - return (Expression.Lambda>(Expression.AndAlso(finalLeft, finalRight), parameters)); - } - case ExpressionType.OrElse: - if (leftIsLambda && rightIsLambda && sequenceEqual || (!leftIsLambda && !rightIsLambda)) - { - return Expression.OrElse(left, right); - } - else - { - return (Expression.Lambda>(Expression.OrElse(finalLeft, finalRight), parameters)); - } - default: - return Expression.Equal(left, right); - } - if (leftIsLambda || rightIsLambda) - { - var body = Expression.Condition(Expression.TypeEqual(innerLeft, right.Type), binaryExpression, Expression.Constant(false)); - return Expression.Lambda>(body, parameters); - } - else - { - return binaryExpression; - } - - } - - Expression GenerateNotEqual(Expression left, Expression right) - { - return HandleDynamicNodeLambdas(ExpressionType.NotEqual, left, right); - } - - Expression GenerateGreaterThan(Expression left, Expression right) - { - if (left.Type == typeof(string)) - { - return Expression.GreaterThan( - GenerateStaticMethodCall("Compare", left, right), - Expression.Constant(0) - ); - } - return HandleDynamicNodeLambdas(ExpressionType.GreaterThan, left, right); - } - - Expression GenerateGreaterThanEqual(Expression left, Expression right) - { - if (left.Type == typeof(string)) - { - return Expression.GreaterThanOrEqual( - GenerateStaticMethodCall("Compare", left, right), - Expression.Constant(0) - ); - } - return HandleDynamicNodeLambdas(ExpressionType.GreaterThanOrEqual, left, right); - } - - Expression GenerateLessThan(Expression left, Expression right) - { - if (left.Type == typeof(string)) - { - return Expression.LessThan( - GenerateStaticMethodCall("Compare", left, right), - Expression.Constant(0) - ); - } - return HandleDynamicNodeLambdas(ExpressionType.LessThan, left, right); - } - - Expression GenerateLessThanEqual(Expression left, Expression right) - { - if (left.Type == typeof(string)) - { - return Expression.LessThanOrEqual( - GenerateStaticMethodCall("Compare", left, right), - Expression.Constant(0) - ); - } - return HandleDynamicNodeLambdas(ExpressionType.LessThanOrEqual, left, right); - } - - Expression GenerateAdd(Expression left, Expression right) - { - if (left.Type == typeof(string) && right.Type == typeof(string)) - { - return GenerateStaticMethodCall("Concat", left, right); - } - return Expression.Add(left, right); - } - - Expression GenerateSubtract(Expression left, Expression right) - { - return Expression.Subtract(left, right); - } - - Expression GenerateStringConcat(Expression left, Expression right) - { - return Expression.Call( - null, - typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) }), - new[] { left, right }); - } - - MethodInfo GetStaticMethod(string methodName, Expression left, Expression right) - { - return left.Type.GetMethod(methodName, new[] { left.Type, right.Type }); - } - - Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right) - { - return Expression.Call(null, GetStaticMethod(methodName, left, right), new[] { left, right }); - } - - void SetTextPos(int pos) - { - textPos = pos; - ch = textPos < textLen ? text[textPos] : '\0'; - } - - void NextChar() - { - if (textPos < textLen) textPos++; - ch = textPos < textLen ? text[textPos] : '\0'; - } - - void NextToken() - { - while (Char.IsWhiteSpace(ch)) NextChar(); - TokenId t; - int tokenPos = textPos; - switch (ch) - { - case '!': - NextChar(); - if (ch == '=') - { - NextChar(); - t = TokenId.ExclamationEqual; - } - else - { - t = TokenId.Exclamation; - } - break; - case '%': - NextChar(); - t = TokenId.Percent; - break; - case '&': - NextChar(); - if (ch == '&') - { - NextChar(); - t = TokenId.DoubleAmphersand; - } - else - { - t = TokenId.Amphersand; - } - break; - case '(': - NextChar(); - t = TokenId.OpenParen; - break; - case ')': - NextChar(); - t = TokenId.CloseParen; - break; - case '*': - NextChar(); - t = TokenId.Asterisk; - break; - case '+': - NextChar(); - t = TokenId.Plus; - break; - case ',': - NextChar(); - t = TokenId.Comma; - break; - case '-': - NextChar(); - t = TokenId.Minus; - break; - case '.': - NextChar(); - t = TokenId.Dot; - break; - case '/': - NextChar(); - t = TokenId.Slash; - break; - case ':': - NextChar(); - t = TokenId.Colon; - break; - case '<': - NextChar(); - if (ch == '=') - { - NextChar(); - t = TokenId.LessThanEqual; - } - else if (ch == '>') - { - NextChar(); - t = TokenId.LessGreater; - } - else - { - t = TokenId.LessThan; - } - break; - case '=': - NextChar(); - if (ch == '=') - { - NextChar(); - t = TokenId.DoubleEqual; - } - else - { - t = TokenId.Equal; - } - break; - case '>': - NextChar(); - if (ch == '=') - { - NextChar(); - t = TokenId.GreaterThanEqual; - } - else - { - t = TokenId.GreaterThan; - } - break; - case '?': - NextChar(); - t = TokenId.Question; - break; - case '[': - NextChar(); - t = TokenId.OpenBracket; - break; - case ']': - NextChar(); - t = TokenId.CloseBracket; - break; - case '|': - NextChar(); - if (ch == '|') - { - NextChar(); - t = TokenId.DoubleBar; - } - else - { - t = TokenId.Bar; - } - break; - case '"': - case '\'': - char quote = ch; - do - { - NextChar(); - while (textPos < textLen && ch != quote) NextChar(); - if (textPos == textLen) - throw ParseError(textPos, Res.UnterminatedStringLiteral); - NextChar(); - } while (ch == quote); - t = TokenId.StringLiteral; - break; - default: - if (Char.IsLetter(ch) || ch == '@' || ch == '_') - { - do - { - NextChar(); - } while (Char.IsLetterOrDigit(ch) || ch == '_'); - t = TokenId.Identifier; - break; - } - if (Char.IsDigit(ch)) - { - t = TokenId.IntegerLiteral; - do - { - NextChar(); - } while (Char.IsDigit(ch)); - if (ch == '.') - { - t = TokenId.RealLiteral; - NextChar(); - ValidateDigit(); - do - { - NextChar(); - } while (Char.IsDigit(ch)); - } - if (ch == 'E' || ch == 'e') - { - t = TokenId.RealLiteral; - NextChar(); - if (ch == '+' || ch == '-') NextChar(); - ValidateDigit(); - do - { - NextChar(); - } while (Char.IsDigit(ch)); - } - if (ch == 'F' || ch == 'f') NextChar(); - break; - } - if (textPos == textLen) - { - t = TokenId.End; - break; - } - throw ParseError(textPos, Res.InvalidCharacter, ch); - } - token.Id = t; - token.Text = text.Substring(tokenPos, textPos - tokenPos); - token.Pos = tokenPos; - } - - bool TokenIdentifierIs(string id) - { - return token.Id == TokenId.Identifier && String.Equals(id, token.Text, StringComparison.OrdinalIgnoreCase); - } - - string GetIdentifier() - { - ValidateToken(TokenId.Identifier, Res.IdentifierExpected); - string id = token.Text; - if (id.Length > 1 && id[0] == '@') id = id.Substring(1); - return id; - } - - void ValidateDigit() - { - if (!Char.IsDigit(ch)) throw ParseError(textPos, Res.DigitExpected); - } - - void ValidateToken(TokenId t, string errorMessage) - { - if (token.Id != t) throw ParseError(errorMessage); - } - - void ValidateToken(TokenId t) - { - if (token.Id != t) throw ParseError(Res.SyntaxError); - } - - Exception ParseError(string format, params object[] args) - { - return ParseError(token.Pos, format, args); - } - - Exception ParseError(int pos, string format, params object[] args) - { - return new ParseException(string.Format(System.Globalization.CultureInfo.CurrentCulture, format, args), pos); - } - - static Dictionary CreateKeywords() - { - Dictionary d = new Dictionary(StringComparer.OrdinalIgnoreCase); - d.Add("true", trueLiteral); - d.Add("false", falseLiteral); - d.Add("null", nullLiteral); - d.Add(keywordIt, keywordIt); - d.Add(keywordIif, keywordIif); - d.Add(keywordNew, keywordNew); - foreach (Type type in predefinedTypes) d.Add(type.Name, type); - return d; - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Web/Dynamics/ExtensionMethods.cs b/src/Umbraco.Web/Dynamics/ExtensionMethods.cs deleted file mode 100644 index 0ab0acfc3c..0000000000 --- a/src/Umbraco.Web/Dynamics/ExtensionMethods.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Umbraco.Core.Models; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web.Models; - -namespace Umbraco.Web.Dynamics -{ - internal static class ExtensionMethods - { - public static DynamicPublishedContentList Random(this DynamicPublishedContentList source, int min, int max) - { - return Random(source, new Random().Next(min, max)); - } - - public static DynamicPublishedContentList Random(this DynamicPublishedContentList source, int max) - { - return new DynamicPublishedContentList(source.OrderByRandom().Take(max)); - } - - public static DynamicPublishedContent Random(this DynamicPublishedContentList source) - { - return new DynamicPublishedContent(source.OrderByRandom().First()); - } - - private static IEnumerable OrderByRandom(this DynamicPublishedContentList source) - { - return source.Items.OrderBy(x => Guid.NewGuid()); - } - - public static DynamicPublishedContentList Children(this DynamicPublishedContent content) - { - return content.Children; - } - - public static DynamicPublishedContentList Children(this DynamicPublishedContent content, string contentTypeAlias) - { - return new DynamicPublishedContentList(content.PublishedContent.Children().OfTypes(contentTypeAlias)); - } - } -} diff --git a/src/Umbraco.Web/Dynamics/Grouping.cs b/src/Umbraco.Web/Dynamics/Grouping.cs deleted file mode 100644 index 4675b16e1b..0000000000 --- a/src/Umbraco.Web/Dynamics/Grouping.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Collections; -using System.Dynamic; -using Umbraco.Core.Dynamics; -using Umbraco.Web.Models; - -namespace Umbraco.Web.Dynamics -{ - internal class Grouping : IGrouping where T : DynamicObject - { - public K Key { get; set; } - public IEnumerable Elements { get; set; } - - public IEnumerator GetEnumerator() - { - var temp = new DynamicPublishedContentList(Elements.Cast()); - return (IEnumerator)temp.GetEnumerator(); - } - IEnumerator IEnumerable.GetEnumerator() - { - return (IEnumerator)GetEnumerator(); - } - - public DynamicPublishedContentList OrderBy(string ordering) - { - bool descending = false; - if (ordering.IndexOf(" descending", StringComparison.CurrentCultureIgnoreCase) >= 0) - { - ordering = ordering.Replace(" descending", ""); - descending = true; - } - if (ordering.IndexOf(" desc", StringComparison.CurrentCultureIgnoreCase) >= 0) - { - ordering = ordering.Replace(" desc", ""); - descending = true; - } - - if (!descending) - { - return new DynamicPublishedContentList(Elements.OrderBy(item => - { - object key = null; - (item as DynamicObject).TryGetMember(new DynamicQueryableGetMemberBinder(ordering, false), out key); - return key; - }).Cast()); - } - else - { - return new DynamicPublishedContentList(Elements.OrderByDescending(item => - { - object key = null; - (item as DynamicObject).TryGetMember(new DynamicQueryableGetMemberBinder(ordering, false), out key); - return key; - }).Cast()); - } - } - } - -} diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index 8649962cd7..da00a4c2e9 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -25,7 +25,6 @@ using Constants = Umbraco.Core.Constants; using Examine; using Examine.LuceneEngine.SearchCriteria; using Examine.SearchCriteria; -using Umbraco.Web.Dynamics; using umbraco; using System.Text.RegularExpressions; using Umbraco.Core.Xml; @@ -87,9 +86,9 @@ namespace Umbraco.Web.Editors /// /// /// Even though a normal entity search will allow any user to search on a entity type that they may not have access to edit, we need - /// to filter these results to the sections they are allowed to edit since this search function is explicitly for the global search + /// to filter these results to the sections they are allowed to edit since this search function is explicitly for the global search /// so if we showed entities that they weren't allowed to edit they would get errors when clicking on the result. - /// + /// /// The reason a user is allowed to search individual entity types that they are not allowed to edit is because those search /// methods might be used in things like pickers in the content editor. /// @@ -166,7 +165,7 @@ namespace Umbraco.Web.Editors { //TODO: Rename this!!! It's a bit misleading, it should be GetByXPath - + if (type != UmbracoEntityTypes.Document) throw new ArgumentException("Get by query is only compatible with enitities of type Document"); @@ -193,7 +192,7 @@ namespace Umbraco.Web.Editors }, publishedContentExists: i => Umbraco.TypedContent(i) != null); } - + public EntityBasic GetById(int id, UmbracoEntityTypes type) { return GetResultForId(id, type); @@ -227,11 +226,6 @@ namespace Umbraco.Web.Editors return GetResultForAncestors(id, type); } - public IEnumerable GetAll(UmbracoEntityTypes type, string postFilter, [FromUri]IDictionary postFilterParams) - { - return GetResultForAll(type, postFilter, postFilterParams); - } - /// /// Searches for results based on the entity type /// @@ -246,14 +240,14 @@ namespace Umbraco.Web.Editors var sb = new StringBuilder(); string type; - + var fields = new[] { "id", "__NodeId" }; - + //TODO: WE should really just allow passing in a lucene raw query switch (entityType) { case UmbracoEntityTypes.Member: - + type = "member"; fields = new[] { "id", "__NodeId", "email", "loginName"}; if (searchFrom != null && searchFrom != Constants.Conventions.MemberTypes.AllMembersListId && searchFrom.Trim() != "-1") @@ -284,7 +278,7 @@ namespace Umbraco.Web.Editors var contentSearchFrom = int.MinValue; - if (Security.CurrentUser.StartContentId > 0 || + if (Security.CurrentUser.StartContentId > 0 || //if searchFrom is specified and it is greater than 0 (searchFrom != null && int.TryParse(searchFrom, out contentSearchFrom) && contentSearchFrom > 0)) { @@ -296,7 +290,7 @@ namespace Umbraco.Web.Editors } break; default: - throw new NotSupportedException("The " + typeof(EntityController) + " currently does not support searching against object type " + entityType); + throw new NotSupportedException("The " + typeof(EntityController) + " currently does not support searching against object type " + entityType); } var internalSearcher = ExamineManager.Instance.GetSearcher(Constants.Examine.InternalIndexer); @@ -305,12 +299,12 @@ namespace Umbraco.Web.Editors // the __nodeName will be boosted 10x without wildcards // then __nodeName will be matched normally with wildcards // the rest will be normal without wildcards - - + + //check if text is surrounded by single or double quotes, if so, then exact match var surroundedByQuotes = Regex.IsMatch(query, "^\".*?\"$") || Regex.IsMatch(query, "^\'.*?\'$"); - + if (surroundedByQuotes) { //strip quotes, escape string, the replace again @@ -346,7 +340,7 @@ namespace Umbraco.Web.Editors { return new List(); } - + query = Lucene.Net.QueryParsers.QueryParser.Escape(query); var querywords = query.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); @@ -389,11 +383,11 @@ namespace Umbraco.Web.Editors sb.Append(") +__IndexType:"); sb.Append(type); - + var raw = internalSearcher.CreateCriteria().RawQuery(sb.ToString()) //limit results to 200 to avoid huge over processing (CPU) .MaxCount(200); - + var result = internalSearcher.Find(raw); switch (entityType) @@ -401,7 +395,7 @@ namespace Umbraco.Web.Editors case UmbracoEntityTypes.Member: return MemberFromSearchResults(result); case UmbracoEntityTypes.Media: - return MediaFromSearchResults(result); + return MediaFromSearchResults(result); case UmbracoEntityTypes.Document: return ContentFromSearchResults(result); default: @@ -429,7 +423,7 @@ namespace Umbraco.Web.Editors var searchResult = results.First(x => x.LongId.ToInvariantString() == m.Id.ToString()); if (searchResult.Fields.ContainsKey("email") && searchResult.Fields["email"] != null) { - m.AdditionalData["Email"] = results.First(x => x.LongId.ToInvariantString() == m.Id.ToString()).Fields["email"]; + m.AdditionalData["Email"] = results.First(x => x.LongId.ToInvariantString() == m.Id.ToString()).Fields["email"]; } if (searchResult.Fields.ContainsKey("__key") && searchResult.Fields["__key"] != null) { @@ -441,7 +435,7 @@ namespace Umbraco.Web.Editors } } return mapped; - } + } /// /// Returns a collection of entities for media based on search results @@ -457,11 +451,11 @@ namespace Umbraco.Web.Editors //if no icon could be mapped, it will be set to document, so change it to picture if (m.Icon == "icon-document") { - m.Icon = "icon-picture"; + m.Icon = "icon-picture"; } } return mapped; - } + } /// /// Returns a collection of entities for content based on search results @@ -481,7 +475,7 @@ namespace Umbraco.Web.Editors } } return mapped; - } + } private IEnumerable GetResultForChildren(int id, UmbracoEntityTypes entityType) { @@ -534,74 +528,6 @@ namespace Umbraco.Web.Editors } } - /// - /// Gets the result for the entity list based on the type - /// - /// - /// A string where filter that will filter the results dynamically with linq - optional - /// the parameters to fill in the string where filter - optional - /// - private IEnumerable GetResultForAll(UmbracoEntityTypes entityType, string postFilter = null, IDictionary postFilterParams = null) - { - var objectType = ConvertToObjectType(entityType); - if (objectType.HasValue) - { - //TODO: Should we order this by something ? - var entities = Services.EntityService.GetAll(objectType.Value).WhereNotNull().Select(Mapper.Map); - return ExecutePostFilter(entities, postFilter, postFilterParams); - } - //now we need to convert the unknown ones - switch (entityType) - { - case UmbracoEntityTypes.Template: - var templates = Services.FileService.GetTemplates(); - var filteredTemplates = ExecutePostFilter(templates, postFilter, postFilterParams); - return filteredTemplates.Select(Mapper.Map); - - case UmbracoEntityTypes.Macro: - //Get all macros from the macro service - var macros = Services.MacroService.GetAll().WhereNotNull().OrderBy(x => x.Name); - var filteredMacros = ExecutePostFilter(macros, postFilter, postFilterParams); - return filteredMacros.Select(Mapper.Map); - - case UmbracoEntityTypes.PropertyType: - - //get all document types, then combine all property types into one list - var propertyTypes = Services.ContentTypeService.GetAll().Cast() - .Concat(Services.MediaTypeService.GetAll()) - .ToArray() - .SelectMany(x => x.PropertyTypes) - .DistinctBy(composition => composition.Alias); - var filteredPropertyTypes = ExecutePostFilter(propertyTypes, postFilter, postFilterParams); - return Mapper.Map, IEnumerable>(filteredPropertyTypes); - - case UmbracoEntityTypes.PropertyGroup: - - //get all document types, then combine all property types into one list - var propertyGroups = Services.ContentTypeService.GetAll().Cast() - .Concat(Services.MediaTypeService.GetAll()) - .ToArray() - .SelectMany(x => x.PropertyGroups) - .DistinctBy(composition => composition.Name); - var filteredpropertyGroups = ExecutePostFilter(propertyGroups, postFilter, postFilterParams); - return Mapper.Map, IEnumerable>(filteredpropertyGroups); - - case UmbracoEntityTypes.User: - - long total; - var users = Services.UserService.GetAll(0, int.MaxValue, out total); - var filteredUsers = ExecutePostFilter(users, postFilter, postFilterParams); - return Mapper.Map, IEnumerable>(filteredUsers); - - case UmbracoEntityTypes.Domain: - - case UmbracoEntityTypes.Language: - - default: - throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + entityType); - } - } - private IEnumerable GetResultForKeys(IEnumerable keys, UmbracoEntityTypes entityType) { var keysArray = keys.ToArray(); @@ -709,22 +635,22 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } return Mapper.Map(found); - } + } //now we need to convert the unknown ones switch (entityType) { case UmbracoEntityTypes.PropertyType: - + case UmbracoEntityTypes.PropertyGroup: case UmbracoEntityTypes.Domain: - + case UmbracoEntityTypes.Language: - + case UmbracoEntityTypes.User: - + case UmbracoEntityTypes.Macro: - + default: throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + entityType); } @@ -759,27 +685,5 @@ namespace Umbraco.Web.Editors return null; } } - - /// - /// Executes the post filter against a collection of objects - /// - /// - /// - /// - /// - /// - private IEnumerable ExecutePostFilter(IEnumerable entities, string postFilter, IDictionary postFilterParams) - { - //if a post filter is assigned then try to execute it - if (postFilter.IsNullOrWhiteSpace() == false) - { - return postFilterParams == null - ? entities.AsQueryable().Where(postFilter).ToArray() - : entities.AsQueryable().Where(postFilter, postFilterParams).ToArray(); - - } - return entities; - } - } } diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 06badfafda..be2bb9ad7c 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -12,7 +12,6 @@ using System.Web.Http; using System.Web.Http.ModelBinding; using AutoMapper; using Umbraco.Core; -using Umbraco.Core.Dynamics; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; diff --git a/src/Umbraco.Web/Editors/TemplateQueryController.cs b/src/Umbraco.Web/Editors/TemplateQueryController.cs index 60a2034245..f9c7fca7ce 100644 --- a/src/Umbraco.Web/Editors/TemplateQueryController.cs +++ b/src/Umbraco.Web/Editors/TemplateQueryController.cs @@ -8,7 +8,6 @@ using Umbraco.Web.WebApi; using System; using System.Diagnostics; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web.Dynamics; using Umbraco.Web.Models.TemplateQuery; namespace Umbraco.Web.Editors @@ -159,7 +158,9 @@ namespace Umbraco.Web.Editors //clause = "Visible && " + clause; - contents = contents.AsQueryable().Where(clause, model.Filters.Select(this.GetConstraintValue).ToArray()); + // fixme - that cannot work anymore now that we have killed dynamic support + //contents = contents.AsQueryable().Where(clause, model.Filters.Select(this.GetConstraintValue).ToArray()); + // contents = contents.Where(clause, values.ToArray()); contents = contents.Where(x => x.IsVisible()); diff --git a/src/Umbraco.Web/ExamineExtensions.cs b/src/Umbraco.Web/ExamineExtensions.cs index 2d16c9b345..d8043a053a 100644 --- a/src/Umbraco.Web/ExamineExtensions.cs +++ b/src/Umbraco.Web/ExamineExtensions.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Linq; using Examine; -using Umbraco.Core.Dynamics; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Web.PublishedCache; diff --git a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs index 9772531064..9c3f461de0 100644 --- a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs @@ -9,7 +9,6 @@ using System.Web.Mvc.Html; using System.Web.Routing; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.Dynamics; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -842,7 +841,7 @@ namespace Umbraco.Web public static HtmlTagWrapper Wrap(this HtmlHelper html, string tag, object inner, object anonymousAttributes, params IHtmlTagWrapper[] children) { string innerText = null; - if (inner != null && inner.GetType() != typeof(DynamicNull)) + if (inner != null) { innerText = string.Format("{0}", inner); } @@ -856,7 +855,7 @@ namespace Umbraco.Web public static HtmlTagWrapper Wrap(this HtmlHelper html, string tag, object inner) { string innerText = null; - if (inner != null && inner.GetType() != typeof(DynamicNull)) + if (inner != null) { innerText = string.Format("{0}", inner); } diff --git a/src/Umbraco.Web/HtmlStringUtilities.cs b/src/Umbraco.Web/HtmlStringUtilities.cs index 5ba1d17f4e..4189226937 100644 --- a/src/Umbraco.Web/HtmlStringUtilities.cs +++ b/src/Umbraco.Web/HtmlStringUtilities.cs @@ -58,29 +58,36 @@ namespace Umbraco.Web return new HtmlString(doc.DocumentNode.FirstChild.InnerHtml); } - internal string Join(string seperator, params object[] args) + internal string Join(string separator, params object[] args) { - var results = args.Where(arg => arg != null && arg.GetType() != typeof(TIgnore)).Select(arg => string.Format("{0}", arg)).Where(sArg => !string.IsNullOrWhiteSpace(sArg)).ToList(); - return string.Join(seperator, results); + var results = args + .Where(x => x != null) + .Select(x => x.ToString()) + .Where(x => string.IsNullOrWhiteSpace(x) == false); + return string.Join(separator, results); } - internal string Concatenate(params object[] args) + internal string Concatenate(params object[] args) { - var result = new StringBuilder(); - foreach (var sArg in args.Where(arg => arg != null && arg.GetType() != typeof(TIgnore)).Select(arg => string.Format("{0}", arg)).Where(sArg => !string.IsNullOrWhiteSpace(sArg))) + var sb = new StringBuilder(); + foreach (var arg in args + .Where(x => x != null) + .Select(x => x.ToString()) + .Where(x => string.IsNullOrWhiteSpace(x) == false)) { - result.Append(sArg); + sb.Append(arg); } - return result.ToString(); + return sb.ToString(); } - internal string Coalesce(params object[] args) + internal string Coalesce(params object[] args) { - foreach (var sArg in args.Where(arg => arg != null && arg.GetType() != typeof(TIgnore)).Select(arg => string.Format("{0}", arg)).Where(sArg => !string.IsNullOrWhiteSpace(sArg))) - { - return sArg; - } - return string.Empty; + var arg = args + .Where(x => x != null) + .Select(x => x.ToString()) + .FirstOrDefault(x => string.IsNullOrWhiteSpace(x) == false); + + return arg ?? string.Empty; } public IHtmlString Truncate(string html, int length, bool addElipsis, bool treatTagsAsContent) diff --git a/src/Umbraco.Web/IDynamicPublishedContentQuery.cs b/src/Umbraco.Web/IDynamicPublishedContentQuery.cs deleted file mode 100644 index 051ba07ff6..0000000000 --- a/src/Umbraco.Web/IDynamicPublishedContentQuery.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Collections.Generic; -using System.Xml.XPath; -using Umbraco.Core.Xml; - -namespace Umbraco.Web -{ - /// - /// Query methods used for accessing content dynamically in templates - /// - public interface IDynamicPublishedContentQuery - { - dynamic Content(int id); - dynamic ContentSingleAtXPath(string xpath, params XPathVariable[] vars); - dynamic ContentSingleAtXPath(XPathExpression xpath, params XPathVariable[] vars); - dynamic Content(IEnumerable ids); - dynamic ContentAtXPath(string xpath, params XPathVariable[] vars); - dynamic ContentAtXPath(XPathExpression xpath, params XPathVariable[] vars); - dynamic ContentAtRoot(); - - dynamic Media(int id); - dynamic Media(IEnumerable ids); - dynamic MediaAtRoot(); - - /// - /// Searches content - /// - /// - /// - /// - /// - dynamic Search(string term, bool useWildCards = true, string searchProvider = null); - - /// - /// Searhes content - /// - /// - /// - /// - dynamic Search(Examine.SearchCriteria.ISearchCriteria criteria, Examine.Providers.BaseSearchProvider searchProvider = null); - } -} \ No newline at end of file diff --git a/src/Umbraco.Web/IPublishedContentCacheExtensions.cs b/src/Umbraco.Web/IPublishedContentCacheExtensions.cs deleted file mode 100644 index 517c59384d..0000000000 --- a/src/Umbraco.Web/IPublishedContentCacheExtensions.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System.Linq; -using System.Xml.XPath; -using Umbraco.Core.Dynamics; -using Umbraco.Core.Xml; -using Umbraco.Web.Models; -using Umbraco.Web.PublishedCache; - -namespace Umbraco.Web -{ - /// - /// Provides extension methods to ContextualPublishedCache. - /// - public static class IPublishedContentCacheExtensions - { - /// - /// Gets a dynamic content identified by its unique identifier. - /// - /// The contextual cache. - /// The content unique identifier. - /// The dynamic content, or null. - public static dynamic GetDynamicById(this IPublishedContentCache cache, int contentId) - { - var content = cache.GetById(contentId); - return content == null ? DynamicNull.Null : new DynamicPublishedContent(content).AsDynamic(); - } - - /// - /// Gets a dynamic content resulting from an XPath query. - /// - /// The contextual cache. - /// The XPath query. - /// Optional XPath variables - /// The dynamic content, or null. - public static dynamic GetDynamicSingleByXPath(this IPublishedContentCache cache, string xpath, params XPathVariable[] vars) - { - var content = cache.GetSingleByXPath(xpath, vars); - return content == null ? DynamicNull.Null : new DynamicPublishedContent(content).AsDynamic(); - } - - /// - /// Gets a dynamic content resulting from an XPath query. - /// - /// The contextual cache. - /// The XPath query. - /// Optional XPath variables - /// The dynamic content, or null. - public static dynamic GetDynamicSingleByXPath(this IPublishedContentCache cache, XPathExpression xpath, params XPathVariable[] vars) - { - var content = cache.GetSingleByXPath(xpath, vars); - return content == null ? DynamicNull.Null : new DynamicPublishedContent(content).AsDynamic(); - } - - /// - /// Gets dynamic contents resulting from an XPath query. - /// - /// The contextual cache. - /// The XPath query. - /// Optional XPath variables - /// The dynamic contents. - public static dynamic GetDynamicByXPath(this IPublishedContentCache cache, string xpath, params XPathVariable[] vars) - { - var content = cache.GetByXPath(xpath, vars); - return new DynamicPublishedContentList(content.Select(c => new DynamicPublishedContent(c))); - } - - /// - /// Gets dynamic contents resulting from an XPath query. - /// - /// The contextual cache. - /// The XPath query. - /// Optional XPath variables - /// The dynamic contents. - public static dynamic GetDynamicByXPath(this IPublishedContentCache cache, XPathExpression xpath, params XPathVariable[] vars) - { - var content = cache.GetByXPath(xpath, vars); - return new DynamicPublishedContentList(content.Select(c => new DynamicPublishedContent(c))); - } - - /// - /// Gets dynamic contents at root. - /// - /// The contextual cache. - /// The dynamic contents. - public static dynamic GetDynamicAtRoot(this IPublishedContentCache cache) - { - var content = cache.GetAtRoot(); - return new DynamicPublishedContentList(content.Select(c => new DynamicPublishedContent(c))); - } - } -} diff --git a/src/Umbraco.Web/Macros/PartialViewMacroPage.cs b/src/Umbraco.Web/Macros/PartialViewMacroPage.cs index 8f5c11b044..0c6bdfc32e 100644 --- a/src/Umbraco.Web/Macros/PartialViewMacroPage.cs +++ b/src/Umbraco.Web/Macros/PartialViewMacroPage.cs @@ -9,20 +9,5 @@ namespace Umbraco.Web.Macros /// The base view class that PartialViewMacro views need to inherit from /// public abstract class PartialViewMacroPage : UmbracoViewPage - { - protected override void InitializePage() - { - base.InitializePage(); - //set the model to the current node if it is not set, this is generally not the case - if (Model != null) - { - CurrentPage = Model.Content.AsDynamic(); - } - } - - /// - /// Returns the a DynamicPublishedContent object - /// - public dynamic CurrentPage { get; private set; } - } + { } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/DynamicPublishedContent.cs b/src/Umbraco.Web/Models/DynamicPublishedContent.cs deleted file mode 100644 index 2fecf7acef..0000000000 --- a/src/Umbraco.Web/Models/DynamicPublishedContent.cs +++ /dev/null @@ -1,1088 +0,0 @@ -// ENABLE THE FIX in 7.0.0 -// TODO if all goes well, remove the obsolete code eventually -#define FIX_GET_PROPERTY_VALUE - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Dynamic; -using System.Linq; -using System.Web; -using Umbraco.Core.Cache; -using Umbraco.Core.Dynamics; -using Umbraco.Core.Models; -using Umbraco.Core; -using System.Reflection; -using Umbraco.Core.Models.PublishedContent; - -namespace Umbraco.Web.Models -{ - - /// - /// The base dynamic model for views - /// - [DebuggerDisplay("Content Id: {Id}, Name: {Name}")] - public class DynamicPublishedContent : DynamicObject, IPublishedContent - { - protected internal IPublishedContent PublishedContent { get; private set; } - private DynamicPublishedContentList _contentList; - - public PublishedContentType ContentType { get { return PublishedContent.ContentType; } } - - #region Constructors - - public DynamicPublishedContent(IPublishedContent content) - { - if (content == null) throw new ArgumentNullException("content"); - PublishedContent = content; - } - - internal DynamicPublishedContent(IPublishedContent content, DynamicPublishedContentList contentList) - { - PublishedContent = content; - _contentList = contentList; - } - - #endregion - - #region DynamicObject - - private readonly ConcurrentDictionary _cachedMemberOutput = new ConcurrentDictionary(); - - /// - /// Attempts to call a method on the dynamic object - /// - /// - /// - /// - /// - public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) - { - var runtimeCache = ApplicationContext.Current != null ? ApplicationContext.Current.ApplicationCache.RuntimeCache : new NullCacheProvider(); - - var attempt = DynamicInstanceHelper.TryInvokeMember(runtimeCache, this, binder, args, new[] - { - typeof(DynamicPublishedContent) - }); - - if (attempt.Success) - { - result = attempt.Result.ObjectResult; - - //need to check the return type and possibly cast if result is from an extension method found - if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod) - { - //we don't need to cast if it is already DynamicPublishedContent - if (attempt.Result.ObjectResult != null && (!(attempt.Result.ObjectResult is DynamicPublishedContent))) - { - if (attempt.Result.ObjectResult is IPublishedContent) - { - result = new DynamicPublishedContent((IPublishedContent)attempt.Result.ObjectResult); - } - else if (attempt.Result.ObjectResult is IEnumerable) - { - result = new DynamicPublishedContentList((IEnumerable)attempt.Result.ObjectResult); - } - else if (attempt.Result.ObjectResult is IEnumerable) - { - result = new DynamicPublishedContentList((IEnumerable)attempt.Result.ObjectResult); - } - } - } - return true; - } - - //this is the result of an extension method execution gone wrong so we return dynamic null - if (attempt.Result != null - && attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod - && attempt.Exception is TargetInvocationException) - { - result = DynamicNull.Null; - return true; - } - - result = null; - return false; - } - - /// - /// Attempts to return a custom member (generally based on a string match) - /// - /// - /// - protected virtual Attempt TryGetCustomMember(GetMemberBinder binder) - { - // as of 4.5 the CLR is case-sensitive which means that the default binder - // will handle those methods only when using the proper casing. So what - // this method does is ensure that any casing is supported. - - if (binder.Name.InvariantEquals("ChildrenAsList") || binder.Name.InvariantEquals("Children")) - { - return Attempt.Succeed(Children); - } - - if (binder.Name.InvariantEquals("parentId")) - { - var parent = ((IPublishedContent) this).Parent; - if (parent == null) - { - throw new InvalidOperationException(string.Format("The node {0} does not have a parent", Id)); - } - return Attempt.Succeed(parent.Id); - } - - return Attempt.Fail(); - } - - /// - /// Attempts to return the children by the document type's alias (for example: CurrentPage.NewsItems where NewsItem is the - /// document type alias) - /// - /// - /// - /// - /// This method will work by both the plural and non-plural alias (i.e. NewsItem and NewsItems) - /// - protected virtual Attempt TryGetChildrenByAlias(GetMemberBinder binder) - { - - var filteredTypeChildren = PublishedContent.Children - .Where(x => x.DocumentTypeAlias.InvariantEquals(binder.Name) || x.DocumentTypeAlias.MakePluralName().InvariantEquals(binder.Name)) - .ToArray(); - if (filteredTypeChildren.Any()) - { - return Attempt.Succeed( - new DynamicPublishedContentList(filteredTypeChildren.Select(x => new DynamicPublishedContent(x)))); - } - return Attempt.Fail(); - } - - /// - /// Attempts to return a member based on the reflected document property - /// - /// - /// - protected virtual Attempt TryGetDocumentProperty(GetMemberBinder binder) - { - var reflectedProperty = GetReflectedProperty(binder.Name); - var result = reflectedProperty != null - ? reflectedProperty.Value - : null; - - return Attempt.If(result != null, result); - } - - /// - /// Attempts to return a member based on a user defined umbraco property - /// - /// - /// - protected virtual Attempt TryGetUserProperty(GetMemberBinder binder) - { - var name = binder.Name; - var recurse = false; - if (name.StartsWith("_")) - { - name = name.Substring(1, name.Length - 1); - recurse = true; - } - - var value = PublishedContent.GetPropertyValue(name, recurse); - return Attempt.If(value != null, value); - } - - /// - /// Returns the member match methods in the correct order and is used in the TryGetMember method. - /// - /// - protected virtual IEnumerable>> GetMemberMatchMethods() - { - var memberMatchMethods = new List>> - { - TryGetCustomMember, //match custom members - TryGetUserProperty, //then match custom user defined umbraco properties - TryGetChildrenByAlias, //then try to match children based on doc type alias - TryGetDocumentProperty //then try to match on a reflected document property - }; - return memberMatchMethods; - } - - /// - /// Try to return an object based on the dynamic member accessor - /// - /// - /// - /// - /// - /// TODO: SD: This will alwasy return true so that no exceptions are generated, this is only because this is how the - /// old DynamicNode worked, I'm not sure if this is the correct/expected functionality but I've left it like that. - /// IMO I think this is incorrect and it would be better to throw an exception for something that is not supported! - /// - public override bool TryGetMember(GetMemberBinder binder, out object result) - { - if (binder == null) throw new ArgumentNullException("binder"); - - var name = binder.Name; - - //check the cache first! - if (_cachedMemberOutput.TryGetValue(name, out result)) - { - return true; - } - - //loop through each member match method and execute it. - //If it is successful, cache the result and return it. - foreach (var attempt in GetMemberMatchMethods() - .Select(m => m(binder)) - .Where(attempt => attempt.Success)) - { - result = attempt.Result; - //cache the result so we don't have to re-process the whole thing - _cachedMemberOutput.TryAdd(name, result); - return true; - } - - //if property access, type lookup and member invoke all failed - //at this point, we're going to return null - //instead, we return a DynamicNull - see comments in that file - //this will let things like Model.ChildItem work and return nothing instead of crashing - - //.Where explictly checks for this type - //and will make it false - //which means backwards equality (&& property != true) will pass - //forwwards equality (&& property or && property == true) will fail - result = DynamicNull.Null; - - //alwasy return true if we haven't thrown an exception though I'm wondering if we return 'false' if .Net throws an exception for us?? - return true; - } - - /// - /// Returns a property defined on the document object as a member property using reflection - /// - /// - /// - private PropertyResult GetReflectedProperty(string alias) - { - return GetPropertyInternal(alias, PublishedContent, false); - } - - /// - /// Return a user defined property - /// - /// - /// - /// - internal PropertyResult GetUserProperty(string alias, bool recursive = false) - { - if (!recursive) - { - return GetPropertyInternal(alias, PublishedContent); - } - var context = this; - var prop = GetPropertyInternal(alias, PublishedContent); - - while (prop == null || !prop.HasValue) - { - var parent = ((IPublishedContent) context).Parent; - if (parent == null) break; - - // Update the context before attempting to retrieve the property again. - context = parent.AsDynamicOrNull(); - prop = context.GetPropertyInternal(alias, context.PublishedContent); - } - - return prop; - } - - private PropertyResult GetPropertyInternal(string alias, IPublishedContent content, bool checkUserProperty = true) - { - if (alias.IsNullOrWhiteSpace()) throw new ArgumentNullException("alias"); - if (content == null) throw new ArgumentNullException("content"); - - //if we're looking for a user defined property - if (checkUserProperty) - { - var prop = content.GetProperty(alias); - - // get wrap the result in a PropertyResult - just so it's an IHtmlString - ?! - return prop == null - ? null - : new PropertyResult(prop, PropertyResultType.UserProperty); - } - - //reflect - - // as of 4.5 the CLR is case-sensitive which means that the default binder - // can handle properties only when using the proper casing. So what this - // does is ensure that any casing is supported. - - var attempt = content.GetType().GetMemberIgnoreCase(content, alias); - - return attempt.Success == false || attempt.Result == null - ? null - : new PropertyResult(alias, attempt.Result, PropertyResultType.ReflectedProperty); - } - - #endregion - - #region Explicit IPublishedContent implementation - - IPublishedContent IPublishedContent.Parent - { - get { return PublishedContent.Parent; } - } - - int IPublishedContent.Id - { - get { return PublishedContent.Id; } - } - - int IPublishedContent.TemplateId - { - get { return PublishedContent.TemplateId; } - } - - int IPublishedContent.SortOrder - { - get { return PublishedContent.SortOrder; } - } - - string IPublishedContent.Name - { - get { return PublishedContent.Name; } - } - - string IPublishedContent.UrlName - { - get { return PublishedContent.UrlName; } - } - - string IPublishedContent.DocumentTypeAlias - { - get { return PublishedContent.DocumentTypeAlias; } - } - - int IPublishedContent.DocumentTypeId - { - get { return PublishedContent.DocumentTypeId; } - } - - string IPublishedContent.WriterName - { - get { return PublishedContent.WriterName; } - } - - string IPublishedContent.CreatorName - { - get { return PublishedContent.CreatorName; } - } - - int IPublishedContent.WriterId - { - get { return PublishedContent.WriterId; } - } - - int IPublishedContent.CreatorId - { - get { return PublishedContent.CreatorId; } - } - - string IPublishedContent.Path - { - get { return PublishedContent.Path; } - } - - DateTime IPublishedContent.CreateDate - { - get { return PublishedContent.CreateDate; } - } - - DateTime IPublishedContent.UpdateDate - { - get { return PublishedContent.UpdateDate; } - } - - Guid IPublishedContent.Version - { - get { return PublishedContent.Version; } - } - - int IPublishedContent.Level - { - get { return PublishedContent.Level; } - } - - bool IPublishedContent.IsDraft - { - get { return PublishedContent.IsDraft; } - } - - IEnumerable IPublishedFragment.Properties - { - get { return PublishedContent.Properties; } - } - - IEnumerable IPublishedContent.Children - { - get { return PublishedContent.Children; } - } - - IPublishedProperty IPublishedFragment.GetProperty(string alias) - { - return PublishedContent.GetProperty(alias); - } - - #endregion - - #region IPublishedContent implementation - - public int TemplateId - { - get { return PublishedContent.TemplateId; } - } - - public int SortOrder - { - get { return PublishedContent.SortOrder; } - } - - public string Name - { - get { return PublishedContent.Name; } - } - - public string UrlName - { - get { return PublishedContent.UrlName; } - } - - public string DocumentTypeAlias - { - get { return PublishedContent.DocumentTypeAlias; } - } - - public string WriterName - { - get { return PublishedContent.WriterName; } - } - - public string CreatorName - { - get { return PublishedContent.CreatorName; } - } - - public int WriterId - { - get { return PublishedContent.WriterId; } - } - - public int CreatorId - { - get { return PublishedContent.CreatorId; } - } - - public string Path - { - get { return PublishedContent.Path; } - } - - public DateTime CreateDate - { - get { return PublishedContent.CreateDate; } - } - - public int Id - { - get { return PublishedContent.Id; } - } - - public Guid Key - { - get { return PublishedContent.Key; } - } - - public DateTime UpdateDate - { - get { return PublishedContent.UpdateDate; } - } - - public Guid Version - { - get { return PublishedContent.Version; } - } - - public int Level - { - get { return PublishedContent.Level; } - } - - public string Url - { - get { return PublishedContent.Url; } - } - - public PublishedItemType ItemType - { - get { return PublishedContent.ItemType; } - } - - // see note in IPublishedContent - //public bool Published - //{ - // get { return PublishedContent.Published; } - //} - - public IEnumerable Properties - { - get { return PublishedContent.Properties; } - } - - #endregion - - #region GetProperty - - // enhanced versions of the extension methods that exist for IPublishedContent, - // here we support the recursive (_) and reflected (@) syntax - - public IPublishedProperty GetProperty(string alias) - { - return alias.StartsWith("_") - ? GetProperty(alias.Substring(1), true) - : GetProperty(alias, false); - } - - public IPublishedProperty GetProperty(string alias, bool recurse) - { - if (alias.StartsWith("@")) return GetReflectedProperty(alias.Substring(1)); - - // get wrap the result in a PropertyResult - just so it's an IHtmlString - ?! - var property = PublishedContent.GetProperty(alias, recurse); - return property == null ? null : new PropertyResult(property, PropertyResultType.UserProperty); - } - - #endregion - - // IPublishedContent extension methods: - // - // all these methods are IPublishedContent extension methods so they should in - // theory apply to DynamicPublishedContent since it is an IPublishedContent and - // we look for extension methods. But that lookup has to be pretty slow. - // Duplicating the methods here makes things much faster. - - #region IPublishedContent extension methods - Template - - public string GetTemplateAlias() - { - return PublishedContentExtensions.GetTemplateAlias(this); - } - - #endregion - - #region IPublishedContent extension methods - HasProperty - - public bool HasProperty(string name) - { - return PublishedContent.HasProperty(name); - } - - #endregion - - #region IPublishedContent extension methods - HasValue - - public bool HasValue(string alias) - { - return PublishedContent.HasValue(alias); - } - - public bool HasValue(string alias, bool recursive) - { - return PublishedContent.HasValue(alias, recursive); - } - - public IHtmlString HasValue(string alias, string valueIfTrue, string valueIfFalse) - { - return PublishedContent.HasValue(alias, valueIfTrue, valueIfFalse); - } - - public IHtmlString HasValue(string alias, bool recursive, string valueIfTrue, string valueIfFalse) - { - return PublishedContent.HasValue(alias, recursive, valueIfTrue, valueIfFalse); - } - - public IHtmlString HasValue(string alias, string valueIfTrue) - { - return PublishedContent.HasValue(alias, valueIfTrue); - } - - public IHtmlString HasValue(string alias, bool recursive, string valueIfTrue) - { - return PublishedContent.HasValue(alias, recursive, valueIfTrue); - } - - #endregion - - #region IPublishedContent extension methods - GetPropertyValue - - // for whatever reason, some methods returning strings were created in DynamicPublishedContent - // and are now considered a "feature" as of v6. So we can't have the proper GetPropertyValue - // methods returning objects, too. And we don't want to change it in v6 as that would be a - // breaking change. - -#if FIX_GET_PROPERTY_VALUE - - public object GetPropertyValue(string alias) - { - return PublishedContent.GetPropertyValue(alias); - } - - public object GetPropertyValue(string alias, string defaultValue) - { - return PublishedContent.GetPropertyValue(alias, defaultValue); - } - - public object GetPropertyValue(string alias, object defaultValue) - { - return PublishedContent.GetPropertyValue(alias, defaultValue); - } - - public object GetPropertyValue(string alias, bool recurse) - { - return PublishedContent.GetPropertyValue(alias, recurse); - } - - public object GetPropertyValue(string alias, bool recurse, object defaultValue) - { - return PublishedContent.GetPropertyValue(alias, recurse, defaultValue); - } - -#else - - public string GetPropertyValue(string alias) - { - return GetPropertyValue(alias, false); - } - - public string GetPropertyValue(string alias, string defaultValue) - { - var value = GetPropertyValue(alias); - return value.IsNullOrWhiteSpace() ? defaultValue : value; - } - - public string GetPropertyValue(string alias, bool recurse, string defaultValue) - { - var value = GetPropertyValue(alias, recurse); - return value.IsNullOrWhiteSpace() ? defaultValue : value; - } - - public string GetPropertyValue(string alias, bool recursive) - { - var property = GetProperty(alias, recursive); - if (property == null || property.Value == null) return null; - return property.Value.ToString(); - } - -#endif - - #endregion - - #region IPublishedContent extension methods - GetPropertyValue - - public T GetPropertyValue(string alias) - { - return PublishedContent.GetPropertyValue(alias); - } - - public T GetPropertyValue(string alias, T defaultValue) - { - return PublishedContent.GetPropertyValue(alias, defaultValue); - } - - public T GetPropertyValue(string alias, bool recurse) - { - return PublishedContent.GetPropertyValue(alias, recurse); - } - - public T GetPropertyValue(string alias, bool recurse, T defaultValue) - { - return PublishedContent.GetPropertyValue(alias, recurse, defaultValue); - } - - #endregion - - #region IPublishedContent extension methods - Search - - public DynamicPublishedContentList Search(string term, bool useWildCards = true, string searchProvider = null) - { - return new DynamicPublishedContentList(PublishedContent.Search(term, useWildCards, searchProvider)); - } - - public DynamicPublishedContentList SearchDescendants(string term, bool useWildCards = true, string searchProvider = null) - { - return new DynamicPublishedContentList(PublishedContent.SearchDescendants(term, useWildCards, searchProvider)); - } - - public DynamicPublishedContentList SearchChildren(string term, bool useWildCards = true, string searchProvider = null) - { - return new DynamicPublishedContentList(PublishedContent.SearchChildren(term, useWildCards, searchProvider)); - } - - public DynamicPublishedContentList Search(Examine.SearchCriteria.ISearchCriteria criteria, Examine.Providers.BaseSearchProvider searchProvider = null) - { - return new DynamicPublishedContentList(PublishedContent.Search(criteria, searchProvider)); - } - - #endregion - - #region IPublishedContent extension methods - AsDynamic - - public dynamic AsDynamic() - { - return this; - } - - public dynamic AsDynamicOrNull() - { - return this; - } - - #endregion - - #region IPublishedContent extension methods - IsSomething: misc - - public bool Visible - { - get { return PublishedContent.IsVisible(); } - } - - public bool IsVisible() - { - return PublishedContent.IsVisible(); - } - - public bool IsDocumentType(string docTypeAlias) - { - return PublishedContent.IsDocumentType(docTypeAlias); - } - - public bool IsNull(string alias, bool recursive) - { - return PublishedContent.IsNull(alias, recursive); - } - - public bool IsNull(string alias) - { - return PublishedContent.IsNull(alias, false); - } - - #endregion - - #region IPublishedContent extension methods - IsSomething: equality - - public bool IsEqual(DynamicPublishedContent other) - { - return PublishedContent.IsEqual(other); - } - - public HtmlString IsEqual(DynamicPublishedContent other, string valueIfTrue) - { - return PublishedContent.IsEqual(other, valueIfTrue); - } - - public HtmlString IsEqual(DynamicPublishedContent other, string valueIfTrue, string valueIfFalse) - { - return PublishedContent.IsEqual(other, valueIfTrue, valueIfFalse); - } - - public bool IsNotEqual(DynamicPublishedContent other) - { - return PublishedContent.IsNotEqual(other); - } - - public HtmlString IsNotEqual(DynamicPublishedContent other, string valueIfTrue) - { - return PublishedContent.IsNotEqual(other, valueIfTrue); - } - - public HtmlString IsNotEqual(DynamicPublishedContent other, string valueIfTrue, string valueIfFalse) - { - return PublishedContent.IsNotEqual(other, valueIfTrue, valueIfFalse); - } - - #endregion - - #region IPublishedContent extension methods - IsSomething: ancestors and descendants - - public bool IsDescendant(DynamicPublishedContent other) - { - return PublishedContent.IsDescendant(other); - } - - public HtmlString IsDescendant(DynamicPublishedContent other, string valueIfTrue) - { - return PublishedContent.IsDescendant(other, valueIfTrue); - } - - public HtmlString IsDescendant(DynamicPublishedContent other, string valueIfTrue, string valueIfFalse) - { - return PublishedContent.IsDescendant(other, valueIfTrue, valueIfFalse); - } - - public bool IsDescendantOrSelf(DynamicPublishedContent other) - { - return PublishedContent.IsDescendantOrSelf(other); - } - - public HtmlString IsDescendantOrSelf(DynamicPublishedContent other, string valueIfTrue) - { - return PublishedContent.IsDescendantOrSelf(other, valueIfTrue); - } - - public HtmlString IsDescendantOrSelf(DynamicPublishedContent other, string valueIfTrue, string valueIfFalse) - { - return PublishedContent.IsDescendantOrSelf(other, valueIfTrue, valueIfFalse); - } - - public bool IsAncestor(DynamicPublishedContent other) - { - return PublishedContent.IsAncestor(other); - } - - public HtmlString IsAncestor(DynamicPublishedContent other, string valueIfTrue) - { - return PublishedContent.IsAncestor(other, valueIfTrue); - } - - public HtmlString IsAncestor(DynamicPublishedContent other, string valueIfTrue, string valueIfFalse) - { - return PublishedContent.IsAncestor(other, valueIfTrue, valueIfFalse); - } - - public bool IsAncestorOrSelf(DynamicPublishedContent other) - { - return PublishedContent.IsAncestorOrSelf(other); - } - - public HtmlString IsAncestorOrSelf(DynamicPublishedContent other, string valueIfTrue) - { - return PublishedContent.IsAncestorOrSelf(other, valueIfTrue); - } - - public HtmlString IsAncestorOrSelf(DynamicPublishedContent other, string valueIfTrue, string valueIfFalse) - { - return PublishedContent.IsAncestorOrSelf(other, valueIfTrue, valueIfFalse); - } - - #endregion - - // all these methods wrap whatever PublishedContent returns in a new - // DynamicPublishedContentList, for dynamic usage. - - #region Ancestors - - public DynamicPublishedContentList Ancestors(int level) - { - return new DynamicPublishedContentList(PublishedContent.Ancestors(level)); - } - - public DynamicPublishedContentList Ancestors(string contentTypeAlias) - { - return new DynamicPublishedContentList(PublishedContent.Ancestors(contentTypeAlias)); - } - - public DynamicPublishedContentList Ancestors() - { - return new DynamicPublishedContentList(PublishedContent.Ancestors()); - } - - public DynamicPublishedContentList Ancestors(Func func) - { - return new DynamicPublishedContentList(PublishedContent.AncestorsOrSelf(false, func)); - } - - public DynamicPublishedContent AncestorOrSelf() - { - return PublishedContent.AncestorOrSelf().AsDynamicOrNull(); - } - - public DynamicPublishedContent AncestorOrSelf(int level) - { - return PublishedContent.AncestorOrSelf(level).AsDynamicOrNull(); - } - - /// - /// A shortcut method for AncestorOrSelf(1) - /// - /// - /// The site homepage - /// - public DynamicPublishedContent Site() - { - return AncestorOrSelf(1); - } - - public DynamicPublishedContent AncestorOrSelf(string contentTypeAlias) - { - return PublishedContent.AncestorOrSelf(contentTypeAlias).AsDynamicOrNull(); - } - - public DynamicPublishedContent AncestorOrSelf(Func func) - { - return PublishedContent.AncestorsOrSelf(true, func).FirstOrDefault().AsDynamicOrNull(); - } - - public DynamicPublishedContentList AncestorsOrSelf(Func func) - { - return new DynamicPublishedContentList(PublishedContent.AncestorsOrSelf(true, func)); - } - - public DynamicPublishedContentList AncestorsOrSelf() - { - return new DynamicPublishedContentList(PublishedContent.AncestorsOrSelf()); - } - - public DynamicPublishedContentList AncestorsOrSelf(string contentTypeAlias) - { - return new DynamicPublishedContentList(PublishedContent.AncestorsOrSelf(contentTypeAlias)); - } - - public DynamicPublishedContentList AncestorsOrSelf(int level) - { - return new DynamicPublishedContentList(PublishedContent.AncestorsOrSelf(level)); - } - - #endregion - - #region Descendants - - public DynamicPublishedContentList Descendants(string contentTypeAlias) - { - return new DynamicPublishedContentList(PublishedContent.Descendants(contentTypeAlias)); - } - public DynamicPublishedContentList Descendants(int level) - { - return new DynamicPublishedContentList(PublishedContent.Descendants(level)); - } - public DynamicPublishedContentList Descendants() - { - return new DynamicPublishedContentList(PublishedContent.Descendants()); - } - public DynamicPublishedContentList DescendantsOrSelf(int level) - { - return new DynamicPublishedContentList(PublishedContent.DescendantsOrSelf(level)); - } - public DynamicPublishedContentList DescendantsOrSelf(string contentTypeAlias) - { - return new DynamicPublishedContentList(PublishedContent.DescendantsOrSelf(contentTypeAlias)); - } - public DynamicPublishedContentList DescendantsOrSelf() - { - return new DynamicPublishedContentList(PublishedContent.DescendantsOrSelf()); - } - - #endregion - - #region Traversal - - public DynamicPublishedContent Up() - { - return PublishedContent.Up().AsDynamicOrNull(); - } - - public DynamicPublishedContent Up(int number) - { - return PublishedContent.Up(number).AsDynamicOrNull(); - } - - public DynamicPublishedContent Up(string contentTypeAlias) - { - return PublishedContent.Up(contentTypeAlias).AsDynamicOrNull(); - } - - public DynamicPublishedContent Down() - { - return PublishedContent.Down().AsDynamicOrNull(); - } - - public DynamicPublishedContent Down(int number) - { - return PublishedContent.Down(number).AsDynamicOrNull(); - } - - public DynamicPublishedContent Down(string contentTypeAlias) - { - return PublishedContent.Down(contentTypeAlias).AsDynamicOrNull(); - } - - #endregion - - #region Parent - - public DynamicPublishedContent Parent - { - get - { - return PublishedContent.Parent != null ? PublishedContent.Parent.AsDynamicOrNull() : null; - } - } - - #endregion - - #region Children - - // we want to cache the dynamic list of children here - // whether PublishedContent.Children itself is cached, is not our concern - - private DynamicPublishedContentList _children; - - public DynamicPublishedContentList Children - { - get { return _children ?? (_children = new DynamicPublishedContentList(PublishedContent.Children)); } - } - - public DynamicPublishedContent FirstChild() - { - return Children.FirstOrDefault(); - } - - public DynamicPublishedContent FirstChild(string alias) - { - return Children.FirstOrDefault(x => x.DocumentTypeAlias == alias) as DynamicPublishedContent; - } - - #endregion - - // should probably cleanup what's below - - #region Where - - public HtmlString Where(string predicate, string valueIfTrue) - { - return Where(predicate, valueIfTrue, string.Empty); - } - public HtmlString Where(string predicate, string valueIfTrue, string valueIfFalse) - { - if (Where(predicate)) - { - return new HtmlString(valueIfTrue); - } - return new HtmlString(valueIfFalse); - } - public bool Where(string predicate) - { - //Totally gonna cheat here - var dynamicDocumentList = new DynamicPublishedContentList(); - dynamicDocumentList.Add(this); - var filtered = dynamicDocumentList.Where(predicate); - if (Queryable.Count(filtered) == 1) - { - //this node matches the predicate - return true; - } - return false; - } - - #endregion - } -} diff --git a/src/Umbraco.Web/Models/DynamicPublishedContentList.cs b/src/Umbraco.Web/Models/DynamicPublishedContentList.cs deleted file mode 100644 index 8af08bc080..0000000000 --- a/src/Umbraco.Web/Models/DynamicPublishedContentList.cs +++ /dev/null @@ -1,584 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Dynamic; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Dynamics; -using System.Collections; -using System.Reflection; -using Umbraco.Core.Models; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web.Dynamics; - -namespace Umbraco.Web.Models -{ - /// - /// Represents a collection of DynamicPublishedContent items. - /// - public class DynamicPublishedContentList : DynamicObject, IEnumerable - { - private readonly List _content; - internal readonly List Items; - - #region Constructor - - public DynamicPublishedContentList() - { - _content = new List(); - Items = new List(); - } - - public DynamicPublishedContentList(IEnumerable items) - { - _content = items.ToList(); - Items = _content.Select(x => new DynamicPublishedContent(x, this)).ToList(); - } - - public DynamicPublishedContentList(IEnumerable items) - { - _content = items.Select(x => x.PublishedContent).ToList(); - Items = _content.Select(x => new DynamicPublishedContent(x, this)).ToList(); - } - - #endregion - - #region ContentSet - - // so we are ~compatible with strongly typed syntax - public DynamicPublishedContentList ToContentSet() - { - return this; - } - - #endregion - - #region IList (well, part of it) - - /// - /// Adds an item to the collection. - /// - /// The item to add. - public void Add(DynamicPublishedContent dynamicContent) - { - var content = dynamicContent.PublishedContent; - _content.Add(content); - Items.Add(new DynamicPublishedContent(content, this)); - } - - /// - /// Removes an item from the collection. - /// - /// The item to remove. - public void Remove(DynamicPublishedContent dynamicContent) - { - if (Items.Contains(dynamicContent) == false) return; - Items.Remove(dynamicContent); - _content.Remove(dynamicContent.PublishedContent); - } - - #endregion - - #region DynamicObject - - // because we want to return DynamicNull and not null, we need to implement the index property - // via the dynamic getter and not natively - otherwise it's not possible to return DynamicNull - - public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) - { - result = DynamicNull.Null; - - if (indexes.Length != 1) - return false; - - var index = indexes[0] as int?; - if (index.HasValue == false) - return false; - - if (index >= 0 && index < Items.Count) - result = Items[index.Value]; - - return true; - } - - public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) - { - //TODO: Nowhere here are we checking if args is the correct length! - - //NOTE: For many of these we could actually leave them out since we are executing custom extension methods and because - // we implement IEnumerable they will execute just fine, however, to do that will be quite a bit slower than checking here. - - var firstArg = args.FirstOrDefault(); - //this is to check for 'DocumentTypeAlias' vs 'NodeTypeAlias' for compatibility - if (firstArg != null && firstArg.ToString().InvariantStartsWith("NodeTypeAlias")) - { - firstArg = "DocumentTypeAlias" + firstArg.ToString().Substring("NodeTypeAlias".Length); - } - - var name = binder.Name; - if (name == "Single") - { - string predicate = firstArg == null ? "" : firstArg.ToString(); - var values = predicate.IsNullOrWhiteSpace() ? new object[] {} : args.Skip(1).ToArray(); - var single = Single(predicate, values); - result = new DynamicPublishedContent(single); - return true; - } - if (name == "SingleOrDefault") - { - string predicate = firstArg == null ? "" : firstArg.ToString(); - var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray(); - var single = SingleOrDefault(predicate, values); - if (single == null) - result = DynamicNull.Null; - else - result = new DynamicPublishedContent(single); - return true; - } - if (name == "First") - { - string predicate = firstArg == null ? "" : firstArg.ToString(); - var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray(); - var first = First(predicate, values); - result = new DynamicPublishedContent(first); - return true; - } - if (name == "FirstOrDefault") - { - string predicate = firstArg == null ? "" : firstArg.ToString(); - var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray(); - var first = FirstOrDefault(predicate, values); - if (first == null) - result = DynamicNull.Null; - else - result = new DynamicPublishedContent(first); - return true; - } - if (name == "Last") - { - string predicate = firstArg == null ? "" : firstArg.ToString(); - var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray(); - var last = Last(predicate, values); - result = new DynamicPublishedContent(last); - return true; - } - if (name == "LastOrDefault") - { - string predicate = firstArg == null ? "" : firstArg.ToString(); - var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray(); - var last = LastOrDefault(predicate, values); - if (last == null) - result = DynamicNull.Null; - else - result = new DynamicPublishedContent(last); - return true; - } - if (name == "Where") - { - string predicate = firstArg.ToString(); - var values = args.Skip(1).ToArray(); - //TODO: We are pre-resolving the where into a ToList() here which will have performance impacts if there where clauses - // are nested! We should somehow support an QueryableDocumentList! - result = new DynamicPublishedContentList(Where(predicate, values).ToList()); - return true; - } - if (name == "OrderBy") - { - //TODO: We are pre-resolving the where into a ToList() here which will have performance impacts if there where clauses - // are nested! We should somehow support an QueryableDocumentList! - result = new DynamicPublishedContentList(OrderBy(firstArg.ToString()).ToList()); - return true; - } - if (name == "Take") - { - result = new DynamicPublishedContentList(this.Take((int)firstArg)); - return true; - } - if (name == "Skip") - { - result = new DynamicPublishedContentList(this.Skip((int)firstArg)); - return true; - } - if (name == "InGroupsOf") - { - int groupSize; - if (int.TryParse(firstArg.ToString(), out groupSize)) - { - result = InGroupsOf(groupSize); - return true; - } - result = DynamicNull.Null; - return true; - } - if (name == "GroupedInto") - { - int groupCount; - if (int.TryParse(firstArg.ToString(), out groupCount)) - { - result = GroupedInto(groupCount); - return true; - } - result = DynamicNull.Null; - return true; - } - if (name == "GroupBy") - { - result = GroupBy(firstArg.ToString()); - return true; - } - if (name == "Average" || name == "Min" || name == "Max" || name == "Sum") - { - result = Aggregate(args, name); - return true; - } - if (name == "Union") - { - // check DynamicPublishedContentList before IEnumerable<...> because DynamicPublishedContentList - // is IEnumerable<...> so ... the check on DynamicPublishedContentList would never be reached. - - var firstArgAsDynamicPublishedContentList = firstArg as DynamicPublishedContentList; - if (firstArgAsDynamicPublishedContentList != null) - { - result = new DynamicPublishedContentList(Items.Union((firstArgAsDynamicPublishedContentList).Items)); - return true; - } - - var firstArgAsIEnumerable = firstArg as IEnumerable; - if (firstArgAsIEnumerable != null) - { - result = new DynamicPublishedContentList(Items.Union(firstArgAsIEnumerable)); - return true; - } - } - if (name == "Except") - { - if ((firstArg as IEnumerable) != null) - { - result = new DynamicPublishedContentList(Items.Except(firstArg as IEnumerable, new DynamicPublishedContentIdEqualityComparer())); - return true; - } - } - if (name == "Intersect") - { - if ((firstArg as IEnumerable) != null) - { - result = new DynamicPublishedContentList(Items.Intersect(firstArg as IEnumerable, new DynamicPublishedContentIdEqualityComparer())); - return true; - } - } - if (name == "Distinct") - { - result = new DynamicPublishedContentList(Items.Distinct(new DynamicPublishedContentIdEqualityComparer())); - return true; - } - if (name == "Pluck" || name == "Select") - { - result = Pluck(args); - return true; - } - - var runtimeCache = ApplicationContext.Current != null ? ApplicationContext.Current.ApplicationCache.RuntimeCache : new NullCacheProvider(); - - //ok, now lets try to match by member, property, extensino method - var attempt = DynamicInstanceHelper.TryInvokeMember(runtimeCache, this, binder, args, new[] - { - typeof (IEnumerable), - typeof (DynamicPublishedContentList) - }); - - if (attempt.Success) - { - result = attempt.Result.ObjectResult; - - //need to check the return type and possibly cast if result is from an extension method found - if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod) - { - //we don't need to cast if the result is already DynamicPublishedContentList - if (attempt.Result.ObjectResult != null && (!(attempt.Result.ObjectResult is DynamicPublishedContentList))) - { - if (attempt.Result.ObjectResult is IPublishedContent) - { - result = new DynamicPublishedContent((IPublishedContent)attempt.Result.ObjectResult); - } - else if (attempt.Result.ObjectResult is IEnumerable) - { - result = new DynamicPublishedContentList((IEnumerable)attempt.Result.ObjectResult); - } - else if (attempt.Result.ObjectResult is IEnumerable) - { - result = new DynamicPublishedContentList((IEnumerable)attempt.Result.ObjectResult); - } - } - } - return true; - } - - //this is the result of an extension method execution gone wrong so we return dynamic null - if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod - && attempt.Exception != null && attempt.Exception is TargetInvocationException) - { - result = DynamicNull.Null; - return true; - } - - result = null; - return false; - - } - - #endregion - - #region Linq and stuff - - private T Aggregate(IEnumerable data, string name) where T : struct - { - switch (name) - { - case "Min": - return data.Min(); - case "Max": - return data.Max(); - case "Average": - if (typeof(T) == typeof(int)) - { - return (T)Convert.ChangeType((data as List).Average(), typeof(T)); - } - if (typeof(T) == typeof(decimal)) - { - return (T)Convert.ChangeType((data as List).Average(), typeof(T)); - } - break; - case "Sum": - if (typeof(T) == typeof(int)) - { - return (T)Convert.ChangeType((data as List).Sum(), typeof(T)); - } - if (typeof(T) == typeof(decimal)) - { - return (T)Convert.ChangeType((data as List).Sum(), typeof(T)); - } - break; - } - return default(T); - } - private object Aggregate(object[] args, string name) - { - object result; - string predicate = args.First().ToString(); - var values = args.Skip(1).ToArray(); - var query = (IQueryable)this.Select(predicate, values); - object firstItem = query.FirstOrDefault(); - if (firstItem == null) - { - result = DynamicNull.Null; - } - else - { - var types = from i in query - group i by i.GetType() into g - where g.Key != typeof(DynamicNull) - orderby g.Count() descending - select new { g, Instances = g.Count() }; - var dominantType = types.First().g.Key; - //remove items that are not the dominant type - //e.g. string,string,string,string,false[DynamicNull],string - var itemsOfDominantTypeOnly = query.ToList(); - itemsOfDominantTypeOnly.RemoveAll(item => !item.GetType().IsAssignableFrom(dominantType)); - if (dominantType == typeof(string)) - { - throw new ArgumentException("Can only use aggregate methods on properties which are numeric"); - } - else if (dominantType == typeof(int)) - { - List data = (List)itemsOfDominantTypeOnly.Cast().ToList(); - return Aggregate(data, name); - } - else if (dominantType == typeof(decimal)) - { - List data = (List)itemsOfDominantTypeOnly.Cast().ToList(); - return Aggregate(data, name); - } - else if (dominantType == typeof(bool)) - { - throw new ArgumentException("Can only use aggregate methods on properties which are numeric or datetime"); - } - else if (dominantType == typeof(DateTime)) - { - if (name != "Min" || name != "Max") - { - throw new ArgumentException("Can only use aggregate min or max methods on properties which are datetime"); - } - List data = (List)itemsOfDominantTypeOnly.Cast().ToList(); - return Aggregate(data, name); - } - else - { - result = query.ToList(); - } - } - return result; - } - private object Pluck(object[] args) - { - object result; - string predicate = args.First().ToString(); - var values = args.Skip(1).ToArray(); - var query = (IQueryable)this.Select(predicate, values); - object firstItem = query.FirstOrDefault(); - if (firstItem == null) - { - result = new List(); - } - else - { - var types = from i in query - group i by i.GetType() into g - where g.Key != typeof(DynamicNull) - orderby g.Count() descending - select new { g, Instances = g.Count() }; - var dominantType = types.First().g.Key; - //remove items that are not the dominant type - //e.g. string,string,string,string,false[DynamicNull],string - var itemsOfDominantTypeOnly = query.ToList(); - itemsOfDominantTypeOnly.RemoveAll(item => !item.GetType().IsAssignableFrom(dominantType)); - if (dominantType == typeof(string)) - { - result = (List)itemsOfDominantTypeOnly.Cast().ToList(); - } - else if (dominantType == typeof(int)) - { - result = (List)itemsOfDominantTypeOnly.Cast().ToList(); - } - else if (dominantType == typeof(decimal)) - { - result = (List)itemsOfDominantTypeOnly.Cast().ToList(); - } - else if (dominantType == typeof(bool)) - { - result = (List)itemsOfDominantTypeOnly.Cast().ToList(); - } - else if (dominantType == typeof(DateTime)) - { - result = (List)itemsOfDominantTypeOnly.Cast().ToList(); - } - else - { - result = query.ToList(); - } - } - return result; - } - - public T Single(string predicate, params object[] values) - { - return predicate.IsNullOrWhiteSpace() - ? ((IQueryable) Items.AsQueryable()).Single() - : Where(predicate, values).Single(); - } - - public T SingleOrDefault(string predicate, params object[] values) - { - return predicate.IsNullOrWhiteSpace() - ? ((IQueryable)Items.AsQueryable()).SingleOrDefault() - : Where(predicate, values).SingleOrDefault(); - } - public T First(string predicate, params object[] values) - { - return predicate.IsNullOrWhiteSpace() - ? ((IQueryable)Items.AsQueryable()).First() - : Where(predicate, values).First(); - } - public T FirstOrDefault(string predicate, params object[] values) - { - return predicate.IsNullOrWhiteSpace() - ? ((IQueryable)Items.AsQueryable()).FirstOrDefault() - : Where(predicate, values).FirstOrDefault(); - } - public T Last(string predicate, params object[] values) - { - return predicate.IsNullOrWhiteSpace() - ? ((IQueryable)Items.AsQueryable()).Last() - : Where(predicate, values).Last(); - } - public T LastOrDefault(string predicate, params object[] values) - { - return predicate.IsNullOrWhiteSpace() - ? ((IQueryable)Items.AsQueryable()).LastOrDefault() - : Where(predicate, values).LastOrDefault(); - } - public IQueryable Where(string predicate, params object[] values) - { - return ((IQueryable)Items.AsQueryable()).Where(predicate, values); - } - public IQueryable OrderBy(string key) - { - return ((IQueryable)Items.AsQueryable()).OrderBy(key, () => typeof(DynamicPublishedContentListOrdering)); - } - public DynamicGrouping GroupBy(string key) - { - var group = new DynamicGrouping(this, key); - return group; - } - public DynamicGrouping GroupedInto(int groupCount) - { - var groupSize = (int)Math.Ceiling(((decimal)Items.Count() / groupCount)); - return new DynamicGrouping( - Items - .Select((node, index) => new KeyValuePair(index, node)) - .GroupBy(kv => (object)(kv.Key / groupSize)) - .Select(item => new Grouping() - { - Key = item.Key, - Elements = item.Select(inner => inner.Value) - })); - } - public DynamicGrouping InGroupsOf(int groupSize) - { - return new DynamicGrouping( - Items - .Select((node, index) => new KeyValuePair(index, node)) - .GroupBy(kv => (object)(kv.Key / groupSize)) - .Select(item => new Grouping() - { - Key = item.Key, - Elements = item.Select(inner => inner.Value) - })); - - } - - public IQueryable Select(string predicate, params object[] values) - { - return DynamicQueryable.Select(Items.AsQueryable(), predicate, values); - } - - #endregion - - #region Dynamic - - public bool IsNull() - { - return false; - } - - public bool HasValue() - { - return true; - } - - #endregion - - #region Enumerate inner IPublishedContent items - - public IEnumerator GetEnumerator() - { - return Items.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - #endregion - } -} diff --git a/src/Umbraco.Web/Models/ImageCropCoordinates.cs b/src/Umbraco.Web/Models/ImageCropCoordinates.cs index 4a480b4beb..e501bf4426 100644 --- a/src/Umbraco.Web/Models/ImageCropCoordinates.cs +++ b/src/Umbraco.Web/Models/ImageCropCoordinates.cs @@ -1,11 +1,10 @@ using System; using System.Runtime.Serialization; -using Umbraco.Core.Dynamics; namespace Umbraco.Web.Models { [DataContract(Name = "imageCropCoordinates")] - public class ImageCropCoordinates : CaseInsensitiveDynamicObject, IEquatable + public class ImageCropCoordinates : IEquatable { [DataMember(Name = "x1")] public decimal X1 { get; set; } @@ -44,7 +43,7 @@ namespace Umbraco.Web.Models { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((ImageCropCoordinates) obj); } @@ -73,7 +72,7 @@ namespace Umbraco.Web.Models public static bool operator !=(ImageCropCoordinates left, ImageCropCoordinates right) { - return !Equals(left, right); + return Equals(left, right) == false; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/ImageCropData.cs b/src/Umbraco.Web/Models/ImageCropData.cs index fb1b3c7424..7cef207bac 100644 --- a/src/Umbraco.Web/Models/ImageCropData.cs +++ b/src/Umbraco.Web/Models/ImageCropData.cs @@ -1,12 +1,10 @@ using System; using System.Runtime.Serialization; -using System.Threading.Tasks; -using Umbraco.Core.Dynamics; namespace Umbraco.Web.Models { [DataContract(Name = "imageCropData")] - public class ImageCropData : CaseInsensitiveDynamicObject, IEquatable + public class ImageCropData : IEquatable { [DataMember(Name = "alias")] public string Alias { get; set; } @@ -45,7 +43,7 @@ namespace Umbraco.Web.Models { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((ImageCropData) obj); } @@ -59,10 +57,10 @@ namespace Umbraco.Web.Models { unchecked { - var hashCode = (Alias != null ? Alias.GetHashCode() : 0); + var hashCode = Alias?.GetHashCode() ?? 0; hashCode = (hashCode*397) ^ Width; hashCode = (hashCode*397) ^ Height; - hashCode = (hashCode*397) ^ (Coordinates != null ? Coordinates.GetHashCode() : 0); + hashCode = (hashCode*397) ^ (Coordinates?.GetHashCode() ?? 0); return hashCode; } } @@ -74,7 +72,7 @@ namespace Umbraco.Web.Models public static bool operator !=(ImageCropData left, ImageCropData right) { - return !Equals(left, right); + return Equals(left, right) == false; } } diff --git a/src/Umbraco.Web/Models/ImageCropDataSet.cs b/src/Umbraco.Web/Models/ImageCropDataSet.cs index 4c5a68a6b9..a2e76f0233 100644 --- a/src/Umbraco.Web/Models/ImageCropDataSet.cs +++ b/src/Umbraco.Web/Models/ImageCropDataSet.cs @@ -1,16 +1,11 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Dynamic; using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Text; using System.Web; using Newtonsoft.Json; -using Umbraco.Core; -using Umbraco.Core.Dynamics; using Umbraco.Core.Serialization; using Umbraco.Web.PropertyEditors.ValueConverters; @@ -19,7 +14,7 @@ namespace Umbraco.Web.Models [JsonConverter(typeof(NoTypeConverterJsonConverter))] [TypeConverter(typeof(ImageCropDataSetConverter))] [DataContract(Name="imageCropDataSet")] - public class ImageCropDataSet : CaseInsensitiveDynamicObject, IHtmlString, IEquatable + public class ImageCropDataSet : IHtmlString, IEquatable { [DataMember(Name="src")] @@ -81,7 +76,7 @@ namespace Umbraco.Web.Models public string ToHtmlString() { - return this.Src; + return Src; } /// @@ -122,7 +117,7 @@ namespace Umbraco.Web.Models { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((ImageCropDataSet) obj); } @@ -136,9 +131,9 @@ namespace Umbraco.Web.Models { unchecked { - var hashCode = (Src != null ? Src.GetHashCode() : 0); - hashCode = (hashCode*397) ^ (FocalPoint != null ? FocalPoint.GetHashCode() : 0); - hashCode = (hashCode*397) ^ (Crops != null ? Crops.GetHashCode() : 0); + var hashCode = Src?.GetHashCode() ?? 0; + hashCode = (hashCode*397) ^ (FocalPoint?.GetHashCode() ?? 0); + hashCode = (hashCode*397) ^ (Crops?.GetHashCode() ?? 0); return hashCode; } } @@ -150,7 +145,7 @@ namespace Umbraco.Web.Models public static bool operator !=(ImageCropDataSet left, ImageCropDataSet right) { - return !Equals(left, right); + return Equals(left, right) == false; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/ImageCropFocalPoint.cs b/src/Umbraco.Web/Models/ImageCropFocalPoint.cs index e47bab5b7a..11d5c05488 100644 --- a/src/Umbraco.Web/Models/ImageCropFocalPoint.cs +++ b/src/Umbraco.Web/Models/ImageCropFocalPoint.cs @@ -1,11 +1,10 @@ using System; using System.Runtime.Serialization; -using Umbraco.Core.Dynamics; namespace Umbraco.Web.Models { [DataContract(Name = "imageCropFocalPoint")] - public class ImageCropFocalPoint : CaseInsensitiveDynamicObject, IEquatable + public class ImageCropFocalPoint : IEquatable { [DataMember(Name = "left")] public decimal Left { get; set; } @@ -38,7 +37,7 @@ namespace Umbraco.Web.Models { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((ImageCropFocalPoint) obj); } @@ -63,7 +62,7 @@ namespace Umbraco.Web.Models public static bool operator !=(ImageCropFocalPoint left, ImageCropFocalPoint right) { - return !Equals(left, right); + return Equals(left, right) == false; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Mvc/UmbracoTemplatePage.cs b/src/Umbraco.Web/Mvc/UmbracoTemplatePage.cs deleted file mode 100644 index b9f9f4690f..0000000000 --- a/src/Umbraco.Web/Mvc/UmbracoTemplatePage.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Umbraco.Core.Dynamics; -using Umbraco.Web.Models; - -namespace Umbraco.Web.Mvc -{ - /// - /// The View that front-end templates inherit from - /// - public abstract class UmbracoTemplatePage : UmbracoViewPage - { - private object _currentPage; - - /// - /// Returns the content as a dynamic object - /// - public dynamic CurrentPage - { - get - { - // it's invalid to create a DynamicPublishedContent around a null content anyway - // fixme - should we return null or DynamicNull.Null? - if (Model == null || Model.Content == null) return null; - return _currentPage ?? (_currentPage = Model.Content.AsDynamic()); - } - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Web/Mvc/UmbracoTemplatePageOfTContent.cs b/src/Umbraco.Web/Mvc/UmbracoTemplatePageOfTContent.cs deleted file mode 100644 index af9d9b0020..0000000000 --- a/src/Umbraco.Web/Mvc/UmbracoTemplatePageOfTContent.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Umbraco.Core.Dynamics; -using Umbraco.Core.Models; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web.Models; - -namespace Umbraco.Web.Mvc -{ - public abstract class UmbracoTemplatePage : UmbracoViewPage> - where TContent : IPublishedContent - { - private object _currentPage; - - /// - /// Returns the content as a dynamic object - /// - public dynamic CurrentPage - { - get - { - // it's invalid to create a DynamicPublishedContent around a null content anyway - // fixme - should we return null or DynamicNull.Null? - if (Model == null || Model.Content == null) return null; - return _currentPage ?? (_currentPage = Model.Content.AsDynamic()); - } - } - } -} diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs index c94e7ba1da..1f18a3075f 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs @@ -1,10 +1,7 @@ using System; using System.Globalization; -using System.Xml; -using System.Xml.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Umbraco.Core.Dynamics; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; diff --git a/src/Umbraco.Web/PublishedCache/PublishedMember.cs b/src/Umbraco.Web/PublishedCache/PublishedMember.cs index c42aeaa275..ecd6883fa0 100644 --- a/src/Umbraco.Web/PublishedCache/PublishedMember.cs +++ b/src/Umbraco.Web/PublishedCache/PublishedMember.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Core; -using Umbraco.Core.Dynamics; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.PublishedContent; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs index d4d5ffdf7d..57fa989ba8 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs @@ -10,7 +10,6 @@ using Examine.LuceneEngine.Providers; using Examine.LuceneEngine.SearchCriteria; using Examine.Providers; using Umbraco.Core; -using Umbraco.Core.Dynamics; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index fb19fb00b9..806f899c21 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -267,80 +267,6 @@ namespace Umbraco.Web #endregion - #region Dynamic Linq Extensions - - // todo - we should keep this file clean and remove dynamic linq stuff from it - - public static IQueryable OrderBy(this IEnumerable source, string predicate) - { - var dList = new DynamicPublishedContentList(source); - return dList.OrderBy(predicate); - } - - public static IQueryable Where(this IEnumerable list, string predicate) - { - // wrap in DynamicPublishedContentList so that the ContentSet is correct - // though that code is somewhat ugly. - - var dlist = new DynamicPublishedContentList(new DynamicPublishedContentList(list) - .Where(predicate)); - - return dlist.AsQueryable(); - } - - public static IEnumerable> GroupBy(this IEnumerable list, string predicate) - { - var dList = new DynamicPublishedContentList(list); - return dList.GroupBy(predicate); - } - - public static IQueryable Select(this IEnumerable list, string predicate, params object[] values) - { - var dList = new DynamicPublishedContentList(list); - return dList.Select(predicate); - } - - public static HtmlString Where(this IPublishedContent content, string predicate, string valueIfTrue) - { - if (content == null) throw new ArgumentNullException(nameof(content)); - return content.Where(predicate, valueIfTrue, string.Empty); - } - - public static HtmlString Where(this IPublishedContent content, string predicate, string valueIfTrue, string valueIfFalse) - { - if (content == null) throw new ArgumentNullException(nameof(content)); - return new HtmlString(content.Where(predicate) ? valueIfTrue : valueIfFalse); - } - - public static bool Where(this IPublishedContent content, string predicate) - { - if (content == null) throw new ArgumentNullException(nameof(content)); - var dynamicDocumentList = new DynamicPublishedContentList { content.AsDynamicOrNull() }; - var filtered = dynamicDocumentList.Where(predicate); - return filtered.Count() == 1; - } - - #endregion - - #region AsDynamic - - // it is ok to have dynamic here - - // content should NOT be null - public static dynamic AsDynamic(this IPublishedContent content) - { - if (content == null) throw new ArgumentNullException(nameof(content)); - return new DynamicPublishedContent(content); - } - - // content CAN be null - internal static DynamicPublishedContent AsDynamicOrNull(this IPublishedContent content) - { - return content == null ? null : new DynamicPublishedContent(content); - } - - #endregion - #region IsSomething: misc. /// diff --git a/src/Umbraco.Web/PublishedContentQuery.cs b/src/Umbraco.Web/PublishedContentQuery.cs index df74d3f18d..cb3ca5241d 100644 --- a/src/Umbraco.Web/PublishedContentQuery.cs +++ b/src/Umbraco.Web/PublishedContentQuery.cs @@ -3,12 +3,9 @@ using System.Collections.Generic; using System.Linq; using System.Xml.XPath; using Umbraco.Core; -using Umbraco.Core.Dynamics; -using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Plugins; using Umbraco.Core.Xml; -using Umbraco.Web.Models; using Umbraco.Web.PublishedCache; namespace Umbraco.Web @@ -16,10 +13,9 @@ namespace Umbraco.Web /// /// A class used to query for published content, media items /// - public class PublishedContentQuery : ITypedPublishedContentQuery, IDynamicPublishedContentQuery + public class PublishedContentQuery : ITypedPublishedContentQuery { private readonly ITypedPublishedContentQuery _typedContentQuery; - private readonly IDynamicPublishedContentQuery _dynamicContentQuery; private readonly IPublishedContentCache _contentCache; private readonly IPublishedMediaCache _mediaCache; @@ -37,16 +33,13 @@ namespace Umbraco.Web } /// - /// Constructor used to wrap the ITypedPublishedContentQuery and IDynamicPublishedContentQuery objects passed in + /// Constructor used to wrap the ITypedPublishedContentQuery object passed in /// /// - /// - public PublishedContentQuery(ITypedPublishedContentQuery typedContentQuery, IDynamicPublishedContentQuery dynamicContentQuery) + public PublishedContentQuery(ITypedPublishedContentQuery typedContentQuery) { if (typedContentQuery == null) throw new ArgumentNullException(nameof(typedContentQuery)); - if (dynamicContentQuery == null) throw new ArgumentNullException(nameof(dynamicContentQuery)); _typedContentQuery = typedContentQuery; - _dynamicContentQuery = dynamicContentQuery; } #region Content @@ -93,55 +86,6 @@ namespace Umbraco.Web : _typedContentQuery.TypedContentAtRoot(); } - public dynamic Content(int id) - { - return _dynamicContentQuery == null - ? DocumentById(id, _contentCache, DynamicNull.Null) - : _dynamicContentQuery.Content(id); - } - - public dynamic ContentSingleAtXPath(string xpath, params XPathVariable[] vars) - { - return _dynamicContentQuery == null - ? DocumentByXPath(xpath, vars, _contentCache, DynamicNull.Null) - : _dynamicContentQuery.ContentSingleAtXPath(xpath, vars); - } - - public dynamic ContentSingleAtXPath(XPathExpression xpath, params XPathVariable[] vars) - { - return _dynamicContentQuery == null - ? DocumentByXPath(xpath, vars, _contentCache, DynamicNull.Null) - : _dynamicContentQuery.ContentSingleAtXPath(xpath, vars); - } - - public dynamic Content(IEnumerable ids) - { - return _dynamicContentQuery == null - ? DocumentByIds(_contentCache, ids.ToArray()) - : _dynamicContentQuery.Content(ids); - } - - public dynamic ContentAtXPath(string xpath, params XPathVariable[] vars) - { - return _dynamicContentQuery == null - ? DocumentsByXPath(xpath, vars, _contentCache) - : _dynamicContentQuery.ContentAtXPath(xpath, vars); - } - - public dynamic ContentAtXPath(XPathExpression xpath, params XPathVariable[] vars) - { - return _dynamicContentQuery == null - ? DocumentsByXPath(xpath, vars, _contentCache) - : _dynamicContentQuery.ContentAtXPath(xpath, vars); - } - - public dynamic ContentAtRoot() - { - return _dynamicContentQuery == null - ? DocumentsAtRoot(_contentCache) - : _dynamicContentQuery.ContentAtRoot(); - } - #endregion #region Media @@ -167,26 +111,6 @@ namespace Umbraco.Web : _typedContentQuery.TypedMediaAtRoot(); } - public dynamic Media(int id) - { - return _dynamicContentQuery == null - ? DocumentById(id, _mediaCache, DynamicNull.Null) - : _dynamicContentQuery.Media(id); - } - - public dynamic Media(IEnumerable ids) - { - return _dynamicContentQuery == null - ? DocumentByIds(_mediaCache, ids) - : _dynamicContentQuery.Media(ids); - } - - public dynamic MediaAtRoot() - { - return _dynamicContentQuery == null - ? DocumentsAtRoot(_mediaCache) - : _dynamicContentQuery.MediaAtRoot(); - } #endregion @@ -233,96 +157,10 @@ namespace Umbraco.Web return cache.GetAtRoot(); } - private dynamic DocumentById(int id, IPublishedCache cache, object ifNotFound) - { - var doc = cache.GetById(id); - return doc == null - ? ifNotFound - : new DynamicPublishedContent(doc).AsDynamic(); - } - - private dynamic DocumentByXPath(string xpath, XPathVariable[] vars, IPublishedCache cache, object ifNotFound) - { - var doc = cache.GetSingleByXPath(xpath, vars); - return doc == null - ? ifNotFound - : new DynamicPublishedContent(doc).AsDynamic(); - } - - private dynamic DocumentByXPath(XPathExpression xpath, XPathVariable[] vars, IPublishedCache cache, object ifNotFound) - { - var doc = cache.GetSingleByXPath(xpath, vars); - return doc == null - ? ifNotFound - : new DynamicPublishedContent(doc).AsDynamic(); - } - - private dynamic DocumentByIds(IPublishedCache cache, IEnumerable ids) - { - var dNull = DynamicNull.Null; - var nodes = ids.Select(eachId => DocumentById(eachId, cache, dNull)) - .Where(x => TypeHelper.IsTypeAssignableFrom(x) == false) - .Cast(); - return new DynamicPublishedContentList(nodes); - } - - private dynamic DocumentsByXPath(string xpath, XPathVariable[] vars, IPublishedCache cache) - { - return new DynamicPublishedContentList( - cache.GetByXPath(xpath, vars) - .Select(publishedContent => new DynamicPublishedContent(publishedContent)) - ); - } - - private dynamic DocumentsByXPath(XPathExpression xpath, XPathVariable[] vars, IPublishedCache cache) - { - return new DynamicPublishedContentList( - cache.GetByXPath(xpath, vars) - .Select(publishedContent => new DynamicPublishedContent(publishedContent)) - ); - } - - private dynamic DocumentsAtRoot(IPublishedCache cache) - { - return new DynamicPublishedContentList( - cache.GetAtRoot() - .Select(publishedContent => new DynamicPublishedContent(publishedContent)) - ); - } - #endregion #region Search - /// - /// Searches content - /// - /// - /// - /// - /// - public dynamic Search(string term, bool useWildCards = true, string searchProvider = null) - { - return _dynamicContentQuery == null - ? new DynamicPublishedContentList( - TypedSearch(term, useWildCards, searchProvider)) - : _dynamicContentQuery.Search(term, useWildCards, searchProvider); - } - - /// - /// Searhes content - /// - /// - /// - /// - public dynamic Search(Examine.SearchCriteria.ISearchCriteria criteria, Examine.Providers.BaseSearchProvider searchProvider = null) - { - return _dynamicContentQuery == null - ? new DynamicPublishedContentList( - TypedSearch(criteria, searchProvider)) - : _dynamicContentQuery.Search(criteria, searchProvider); - } - /// /// Searches content /// diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index cee83a34d6..cdd62eb4e8 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -169,7 +169,6 @@ - @@ -525,7 +524,6 @@ - @@ -805,14 +803,6 @@ - - - - - - - - @@ -824,12 +814,9 @@ - - - @@ -1086,7 +1073,6 @@ - diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index e06821a0e5..280cc86ccc 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -6,8 +6,6 @@ using System.Xml.Linq; using System.Xml.XPath; using Umbraco.Core; using Umbraco.Core.Dictionary; -using Umbraco.Core.Dynamics; -using Umbraco.Core.Models; using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Xml; @@ -16,7 +14,6 @@ using Umbraco.Web.Security; using System.Collections.Generic; using System.IO; using System.Web.Mvc; -using System.Web.Routing; using Umbraco.Core.Cache; using Umbraco.Core.Models.PublishedContent; @@ -30,10 +27,9 @@ namespace Umbraco.Web private readonly UmbracoContext _umbracoContext; private readonly IPublishedContent _currentPage; private readonly ITypedPublishedContentQuery _typedQuery; - private readonly IDynamicPublishedContentQuery _dynamicQuery; private readonly HtmlStringUtilities _stringUtilities = new HtmlStringUtilities(); - private IUmbracoComponentRenderer _componentRenderer; + private IUmbracoComponentRenderer _componentRenderer; private PublishedContentQuery _query; private MembershipHelper _membershipHelper; private ITagQuery _tag; @@ -44,31 +40,17 @@ namespace Umbraco.Web /// /// Lazy instantiates the tag context /// - public ITagQuery TagQuery - { - get - { - return _tag ?? - (_tag = new TagQuery(UmbracoContext.Application.Services.TagService, - _typedQuery ?? ContentQuery)); - } - } + public ITagQuery TagQuery => _tag ?? + (_tag = new TagQuery(UmbracoContext.Application.Services.TagService, + _typedQuery ?? ContentQuery)); /// /// Lazy instantiates the query context if not specified in the constructor /// - public PublishedContentQuery ContentQuery - { - get - { - //If the content query doesn't exist it will either be created with the ITypedPublishedContentQuery, IDynamicPublishedContentQuery - // used to construct this instance or with the content caches of the UmbracoContext - return _query ?? - (_query = _typedQuery != null - ? new PublishedContentQuery(_typedQuery, _dynamicQuery) - : new PublishedContentQuery(UmbracoContext.ContentCache, UmbracoContext.MediaCache)); - } - } + public PublishedContentQuery ContentQuery => _query ?? + (_query = _typedQuery != null + ? new PublishedContentQuery(_typedQuery) + : new PublishedContentQuery(UmbracoContext.ContentCache, UmbracoContext.MediaCache)); /// /// Helper method to ensure an umbraco context is set when it is needed @@ -88,34 +70,25 @@ namespace Umbraco.Web /// /// Lazy instantiates the membership helper if not specified in the constructor /// - public MembershipHelper MembershipHelper - { - get { return _membershipHelper ?? (_membershipHelper = new MembershipHelper(UmbracoContext)); } - } + public MembershipHelper MembershipHelper => _membershipHelper ?? (_membershipHelper = new MembershipHelper(UmbracoContext)); /// /// Lazy instantiates the UrlProvider if not specified in the constructor /// - public UrlProvider UrlProvider - { - get { return _urlProvider ?? (_urlProvider = UmbracoContext.UrlProvider); } - } + public UrlProvider UrlProvider => _urlProvider ?? + (_urlProvider = UmbracoContext.UrlProvider); /// /// Lazy instantiates the IDataTypeService if not specified in the constructor /// - public IDataTypeService DataTypeService - { - get { return _dataTypeService ?? (_dataTypeService = UmbracoContext.Application.Services.DataTypeService); } - } + public IDataTypeService DataTypeService => _dataTypeService ?? + (_dataTypeService = UmbracoContext.Application.Services.DataTypeService); /// /// Lazy instantiates the IUmbracoComponentRenderer if not specified in the constructor /// - public IUmbracoComponentRenderer UmbracoComponentRenderer - { - get { return _componentRenderer ?? (_componentRenderer = new UmbracoComponentRenderer(UmbracoContext)); } - } + public IUmbracoComponentRenderer UmbracoComponentRenderer => _componentRenderer ?? + (_componentRenderer = new UmbracoComponentRenderer(UmbracoContext)); #region Constructors /// @@ -143,7 +116,6 @@ namespace Umbraco.Web /// public UmbracoHelper(UmbracoContext umbracoContext, IPublishedContent content, ITypedPublishedContentQuery typedQuery, - IDynamicPublishedContentQuery dynamicQuery, ITagQuery tagQuery, IDataTypeService dataTypeService, UrlProvider urlProvider, @@ -151,16 +123,15 @@ namespace Umbraco.Web IUmbracoComponentRenderer componentRenderer, MembershipHelper membershipHelper) { - if (umbracoContext == null) throw new ArgumentNullException("umbracoContext"); - if (content == null) throw new ArgumentNullException("content"); - if (typedQuery == null) throw new ArgumentNullException("typedQuery"); - if (dynamicQuery == null) throw new ArgumentNullException("dynamicQuery"); - if (tagQuery == null) throw new ArgumentNullException("tagQuery"); - if (dataTypeService == null) throw new ArgumentNullException("dataTypeService"); - if (urlProvider == null) throw new ArgumentNullException("urlProvider"); - if (cultureDictionary == null) throw new ArgumentNullException("cultureDictionary"); - if (componentRenderer == null) throw new ArgumentNullException("componentRenderer"); - if (membershipHelper == null) throw new ArgumentNullException("membershipHelper"); + if (umbracoContext == null) throw new ArgumentNullException(nameof(umbracoContext)); + if (content == null) throw new ArgumentNullException(nameof(content)); + if (typedQuery == null) throw new ArgumentNullException(nameof(typedQuery)); + if (tagQuery == null) throw new ArgumentNullException(nameof(tagQuery)); + if (dataTypeService == null) throw new ArgumentNullException(nameof(dataTypeService)); + if (urlProvider == null) throw new ArgumentNullException(nameof(urlProvider)); + if (cultureDictionary == null) throw new ArgumentNullException(nameof(cultureDictionary)); + if (componentRenderer == null) throw new ArgumentNullException(nameof(componentRenderer)); + if (membershipHelper == null) throw new ArgumentNullException(nameof(membershipHelper)); _umbracoContext = umbracoContext; _tag = new TagQuery(tagQuery); @@ -171,7 +142,6 @@ namespace Umbraco.Web _membershipHelper = membershipHelper; _currentPage = content; _typedQuery = typedQuery; - _dynamicQuery = dynamicQuery; } /// @@ -182,7 +152,7 @@ namespace Umbraco.Web public UmbracoHelper(UmbracoContext umbracoContext, IPublishedContent content) : this(umbracoContext) { - if (content == null) throw new ArgumentNullException("content"); + if (content == null) throw new ArgumentNullException(nameof(content)); _currentPage = content; } @@ -192,7 +162,7 @@ namespace Umbraco.Web /// public UmbracoHelper(UmbracoContext umbracoContext) { - if (umbracoContext == null) throw new ArgumentNullException("umbracoContext"); + if (umbracoContext == null) throw new ArgumentNullException(nameof(umbracoContext)); if (umbracoContext.RoutingContext == null) throw new NullReferenceException("The RoutingContext on the UmbracoContext cannot be null"); _umbracoContext = umbracoContext; @@ -210,7 +180,7 @@ namespace Umbraco.Web /// /// Note that this is the assigned IPublishedContent item to the UmbracoHelper, this is not necessarily the Current IPublishedContent item /// being rendered. This IPublishedContent object is contextual to the current UmbracoHelper instance. - /// + /// /// In some cases accessing this property will throw an exception if there is not IPublishedContent assigned to the Helper /// this will only ever happen if the Helper is constructed with an UmbracoContext and it is not a front-end request /// @@ -221,7 +191,7 @@ namespace Umbraco.Web { if (_currentPage == null) throw new InvalidOperationException("Cannot return the " + typeof(IPublishedContent).Name + " because the " + typeof(UmbracoHelper).Name + " was constructed with an " + typeof(UmbracoContext).Name + " and the current request is not a front-end request."); - + return _currentPage; } } @@ -293,15 +263,15 @@ namespace Umbraco.Web /// //// /// - public IHtmlString Field(string fieldAlias, + public IHtmlString Field(string fieldAlias, string altFieldAlias = "", string altText = "", string insertBefore = "", string insertAfter = "", bool recursive = false, bool convertLineBreaks = false, bool removeParagraphTags = false, RenderFieldCaseType casing = RenderFieldCaseType.Unchanged, - RenderFieldEncodingType encoding = RenderFieldEncodingType.Unchanged, - bool formatAsDate = false, + RenderFieldEncodingType encoding = RenderFieldEncodingType.Unchanged, + bool formatAsDate = false, bool formatAsDateWithTime = false, string formatAsDateWithTimeSeparator = "") - { + { return UmbracoComponentRenderer.Field(AssignedContentItem, fieldAlias, altFieldAlias, altText, insertBefore, insertAfter, recursive, convertLineBreaks, removeParagraphTags, casing, encoding, formatAsDate, formatAsDateWithTime, formatAsDateWithTimeSeparator); @@ -326,11 +296,11 @@ namespace Umbraco.Web /// //// /// - public IHtmlString Field(IPublishedContent currentPage, string fieldAlias, + public IHtmlString Field(IPublishedContent currentPage, string fieldAlias, string altFieldAlias = "", string altText = "", string insertBefore = "", string insertAfter = "", bool recursive = false, bool convertLineBreaks = false, bool removeParagraphTags = false, RenderFieldCaseType casing = RenderFieldCaseType.Unchanged, - RenderFieldEncodingType encoding = RenderFieldEncodingType.Unchanged, + RenderFieldEncodingType encoding = RenderFieldEncodingType.Unchanged, bool formatAsDate = false, bool formatAsDateWithTime = false, string formatAsDateWithTimeSeparator = "") @@ -402,7 +372,7 @@ namespace Umbraco.Web /// Check if the current user has access to a document /// /// The full path of the document object to check - /// True if the current user has access or if the current document isn't protected + /// True if the current user has access or if the current document isn't protected public bool MemberHasAccess(string path) { if (IsProtected(path)) @@ -433,7 +403,7 @@ namespace Umbraco.Web public bool MemberIsLoggedOn() { return MembershipHelper.IsLoggedIn(); - } + } #endregion @@ -473,7 +443,7 @@ namespace Umbraco.Web } /// - /// This method will always add the domain to the path if the hostnames are set up correctly. + /// This method will always add the domain to the path if the hostnames are set up correctly. /// /// Identifier for the node that should be returned /// String with a friendly url with full domain from a node @@ -513,27 +483,6 @@ namespace Umbraco.Web return asInt ? MembershipHelper.GetById(asInt.Result) : MembershipHelper.GetByProviderKey(id); } - public dynamic Member(object id) - { - var asInt = id.TryConvertTo(); - return asInt - ? MembershipHelper.GetById(asInt.Result).AsDynamic() - : MembershipHelper.GetByProviderKey(id).AsDynamic(); - } - - public dynamic Member(int id) - { - return MembershipHelper.GetById(id).AsDynamic(); - } - - public dynamic Member(string id) - { - var asInt = id.TryConvertTo(); - return asInt - ? MembershipHelper.GetById(asInt.Result).AsDynamic() - : MembershipHelper.GetByProviderKey(id).AsDynamic(); - } - #endregion #region Content @@ -635,114 +584,6 @@ namespace Umbraco.Web return ContentQuery.TypedContentAtRoot(); } - public dynamic Content(object id) - { - int intId; - return ConvertIdObjectToInt(id, out intId) ? ContentQuery.Content(intId) : DynamicNull.Null; - } - - public dynamic Content(int id) - { - return ContentQuery.Content(id); - } - - public dynamic Content(string id) - { - int intId; - return ConvertIdObjectToInt(id, out intId) ? ContentQuery.Content(intId) : DynamicNull.Null; - } - - public dynamic ContentSingleAtXPath(string xpath, params XPathVariable[] vars) - { - return ContentQuery.ContentSingleAtXPath(xpath, vars); - } - - public dynamic ContentSingleAtXPath(XPathExpression xpath, params XPathVariable[] vars) - { - return ContentQuery.ContentSingleAtXPath(xpath, vars); - } - - /// - /// Gets the contents corresponding to the identifiers. - /// - /// The content identifiers. - /// The existing contents corresponding to the identifiers. - /// If an identifier does not match an existing content, it will be missing in the returned value. - public dynamic Content(params object[] ids) - { - return ContentQuery.Content(ConvertIdsObjectToInts(ids)); - } - - /// - /// Gets the contents corresponding to the identifiers. - /// - /// The content identifiers. - /// The existing contents corresponding to the identifiers. - /// If an identifier does not match an existing content, it will be missing in the returned value. - public dynamic Content(params int[] ids) - { - return ContentQuery.Content(ids); - } - - /// - /// Gets the contents corresponding to the identifiers. - /// - /// The content identifiers. - /// The existing contents corresponding to the identifiers. - /// If an identifier does not match an existing content, it will be missing in the returned value. - public dynamic Content(params string[] ids) - { - return ContentQuery.Content(ConvertIdsObjectToInts(ids)); - } - - /// - /// Gets the contents corresponding to the identifiers. - /// - /// The content identifiers. - /// The existing contents corresponding to the identifiers. - /// If an identifier does not match an existing content, it will be missing in the returned value. - public dynamic Content(IEnumerable ids) - { - return ContentQuery.Content(ConvertIdsObjectToInts(ids)); - } - - /// - /// Gets the contents corresponding to the identifiers. - /// - /// The content identifiers. - /// The existing contents corresponding to the identifiers. - /// If an identifier does not match an existing content, it will be missing in the returned value. - public dynamic Content(IEnumerable ids) - { - return ContentQuery.Content(ids); - } - - /// - /// Gets the contents corresponding to the identifiers. - /// - /// The content identifiers. - /// The existing contents corresponding to the identifiers. - /// If an identifier does not match an existing content, it will be missing in the returned value. - public dynamic Content(IEnumerable ids) - { - return ContentQuery.Content(ConvertIdsObjectToInts(ids)); - } - - public dynamic ContentAtXPath(string xpath, params XPathVariable[] vars) - { - return ContentQuery.ContentAtXPath(xpath, vars); - } - - public dynamic ContentAtXPath(XPathExpression xpath, params XPathVariable[] vars) - { - return ContentQuery.ContentAtXPath(xpath, vars); - } - - public dynamic ContentAtRoot() - { - return ContentQuery.ContentAtRoot(); - } - private bool ConvertIdObjectToInt(object id, out int intId) { var s = id as string; @@ -750,7 +591,7 @@ namespace Umbraco.Web { return int.TryParse(s, out intId); } - + if (id is int) { intId = (int) id; @@ -784,7 +625,7 @@ namespace Umbraco.Web /// /// /// - /// We accept an object type because GetPropertyValue now returns an 'object', we still want to allow people to pass + /// We accept an object type because GetPropertyValue now returns an 'object', we still want to allow people to pass /// this result in to this method. /// This method will throw an exception if the value is not of type int or string. /// @@ -876,121 +717,10 @@ namespace Umbraco.Web return ContentQuery.TypedMediaAtRoot(); } - public dynamic Media(object id) - { - int intId; - return ConvertIdObjectToInt(id, out intId) ? ContentQuery.Media(intId) : DynamicNull.Null; - } - - public dynamic Media(int id) - { - return ContentQuery.Media(id); - } - - public dynamic Media(string id) - { - int intId; - return ConvertIdObjectToInt(id, out intId) ? ContentQuery.Media(intId) : DynamicNull.Null; - } - - /// - /// Gets the medias corresponding to the identifiers. - /// - /// The media identifiers. - /// The existing medias corresponding to the identifiers. - /// If an identifier does not match an existing media, it will be missing in the returned value. - public dynamic Media(params object[] ids) - { - return ContentQuery.Media(ConvertIdsObjectToInts(ids)); - } - - /// - /// Gets the medias corresponding to the identifiers. - /// - /// The media identifiers. - /// The existing medias corresponding to the identifiers. - /// If an identifier does not match an existing media, it will be missing in the returned value. - public dynamic Media(params int[] ids) - { - return ContentQuery.Media(ids); - } - - /// - /// Gets the medias corresponding to the identifiers. - /// - /// The media identifiers. - /// The existing medias corresponding to the identifiers. - /// If an identifier does not match an existing media, it will be missing in the returned value. - public dynamic Media(params string[] ids) - { - return ContentQuery.Media(ConvertIdsObjectToInts(ids)); - } - - /// - /// Gets the medias corresponding to the identifiers. - /// - /// The media identifiers. - /// The existing medias corresponding to the identifiers. - /// If an identifier does not match an existing media, it will be missing in the returned value. - public dynamic Media(IEnumerable ids) - { - return ContentQuery.Media(ConvertIdsObjectToInts(ids)); - } - - /// - /// Gets the medias corresponding to the identifiers. - /// - /// The media identifiers. - /// The existing medias corresponding to the identifiers. - /// If an identifier does not match an existing media, it will be missing in the returned value. - public dynamic Media(IEnumerable ids) - { - return ContentQuery.Media(ids); - } - - /// - /// Gets the medias corresponding to the identifiers. - /// - /// The media identifiers. - /// The existing medias corresponding to the identifiers. - /// If an identifier does not match an existing media, it will be missing in the returned value. - public dynamic Media(IEnumerable ids) - { - return ContentQuery.Media(ConvertIdsObjectToInts(ids)); - } - - public dynamic MediaAtRoot() - { - return ContentQuery.MediaAtRoot(); - } - #endregion - + #region Search - /// - /// Searches content - /// - /// - /// - /// - /// - public dynamic Search(string term, bool useWildCards = true, string searchProvider = null) - { - return ContentQuery.Search(term, useWildCards, searchProvider); - } - - /// - /// Searhes content - /// - /// - /// - /// - public dynamic Search(Examine.SearchCriteria.ISearchCriteria criteria, Examine.Providers.BaseSearchProvider searchProvider = null) - { - return ContentQuery.Search(criteria, searchProvider); - } - /// /// Searches content /// @@ -1016,27 +746,6 @@ namespace Umbraco.Web #endregion - #region Xml - - public dynamic ToDynamicXml(string xml) - { - if (string.IsNullOrWhiteSpace(xml)) return null; - var xElement = XElement.Parse(xml); - return new DynamicXml(xElement); - } - - public dynamic ToDynamicXml(XElement xElement) - { - return new DynamicXml(xElement); - } - - public dynamic ToDynamicXml(XPathNodeIterator xpni) - { - return new DynamicXml(xpni); - } - - #endregion - #region Strings /// @@ -1067,14 +776,6 @@ namespace Umbraco.Web return StripHtml(html.ToHtmlString(), tags); } - /// - /// Strips all html tags from a given string, all contents of the tags will remain. - /// - public HtmlString StripHtml(DynamicNull html, params string[] tags) - { - return new HtmlString(string.Empty); - } - /// /// Strips all html tags from a given string, all contents of the tags will remain. /// @@ -1088,7 +789,7 @@ namespace Umbraco.Web /// public string Coalesce(params object[] args) { - return _stringUtilities.Coalesce(args); + return _stringUtilities.Coalesce(args); } /// @@ -1096,15 +797,15 @@ namespace Umbraco.Web /// public string Concatenate(params object[] args) { - return _stringUtilities.Concatenate(args); + return _stringUtilities.Concatenate(args); } /// /// Joins any number of int/string/objects into one string and seperates them with the string seperator parameter. /// - public string Join(string seperator, params object[] args) + public string Join(string separator, params object[] args) { - return _stringUtilities.Join(seperator, args); + return _stringUtilities.Join(separator, args); } /// @@ -1131,30 +832,6 @@ namespace Umbraco.Web return Truncate(html.ToHtmlString(), length, addElipsis, treatTagsAsContent); } - /// - /// Truncates a string to a given length, can add a elipsis at the end (...). Method checks for open html tags, and makes sure to close them - /// - public IHtmlString Truncate(DynamicNull html, int length) - { - return new HtmlString(string.Empty); - } - - /// - /// Truncates a string to a given length, can add a elipsis at the end (...). Method checks for open html tags, and makes sure to close them - /// - public IHtmlString Truncate(DynamicNull html, int length, bool addElipsis) - { - return new HtmlString(string.Empty); - } - - /// - /// Truncates a string to a given length, can add a elipsis at the end (...). Method checks for open html tags, and makes sure to close them - /// - public IHtmlString Truncate(DynamicNull html, int length, bool addElipsis, bool treatTagsAsContent) - { - return new HtmlString(string.Empty); - } - /// /// Truncates a string to a given length, can add a elipsis at the end (...). Method checks for open html tags, and makes sure to close them /// @@ -1212,7 +889,7 @@ namespace Umbraco.Web #endregion #region canvasdesigner - + [Obsolete("Use EnableCanvasDesigner on the HtmlHelper extensions instead")] public IHtmlString EnableCanvasDesigner() { @@ -1271,12 +948,9 @@ namespace Umbraco.Web Mandate.ParameterNotNull(area, "area"); //need to create a params string as Base64 to put into our hidden field to use during the routes - var surfaceRouteParams = string.Format("c={0}&a={1}&ar={2}", - HttpUtility.UrlEncode(controllerName), - HttpUtility.UrlEncode(controllerAction), - area); + var surfaceRouteParams = $"c={HttpUtility.UrlEncode(controllerName)}&a={HttpUtility.UrlEncode(controllerAction)}&ar={area}"; - var additionalRouteValsAsQuery = additionalRouteVals != null ? additionalRouteVals.ToDictionary().ToQueryString() : null; + var additionalRouteValsAsQuery = additionalRouteVals?.ToDictionary().ToQueryString(); if (additionalRouteValsAsQuery.IsNullOrWhiteSpace() == false) surfaceRouteParams += "&" + additionalRouteValsAsQuery;