From 3bf1041041487d56dbd2b4fb24ef719d44efaa19 Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 18 Apr 2014 20:16:00 +0200 Subject: [PATCH 1/3] U4-3787 - Ensure we republish published descendants when republishing --- .../Persistence/Repositories/ContentRepository.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 517c004e0f..98c17b74e4 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -488,11 +488,16 @@ namespace Umbraco.Core.Persistence.Repositories public IEnumerable GetByPublishedVersion(IQuery query) { + // we WANT to return contents in top-down order, ie parents should come before children + // ideal would be pure xml "document order" which can be achieved with: + // ORDER BY substring(path, 1, len(path) - charindex(',', reverse(path))), sortOrder + // but that's probably an overkill - sorting by level,sortOrder should be enough + var sqlClause = GetBaseQuery(false); var translator = new SqlTranslator(sqlClause, query); var sql = translator.Translate() .Where(x => x.Published) - .OrderByDescending(x => x.VersionDate) + .OrderBy(x => x.Level) .OrderBy(x => x.SortOrder); //NOTE: This doesn't allow properties to be part of the query @@ -610,4 +615,4 @@ namespace Umbraco.Core.Persistence.Repositories return currentName; } } -} \ No newline at end of file +} From 536b8ee921ed7d626a2cbb3de81df5bd13c93ebf Mon Sep 17 00:00:00 2001 From: Stephan Date: Sat, 19 Apr 2014 16:44:33 +0200 Subject: [PATCH 2/3] U4-3425 - TypeHelper referenced assemblies issue --- src/Umbraco.Core/AssemblyExtensions.cs | 28 ++++++++++++++++++++++++++ src/Umbraco.Core/TypeHelper.cs | 12 ++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/AssemblyExtensions.cs b/src/Umbraco.Core/AssemblyExtensions.cs index 666dce18fc..fff444c34a 100644 --- a/src/Umbraco.Core/AssemblyExtensions.cs +++ b/src/Umbraco.Core/AssemblyExtensions.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; namespace Umbraco.Core @@ -66,5 +68,31 @@ namespace Umbraco.Core return new FileInfo(path); } + /// + /// Gets the objects for all the assemblies recursively referenced by a specified assembly. + /// + /// The assembly. + /// The objects for all the assemblies recursively referenced by the specified assembly. + public static IEnumerable GetDeepReferencedAssemblies(this Assembly assembly) + { + var allAssemblies = TypeFinder.GetAllAssemblies(); + var visiting = new Stack(); + var visited = new HashSet(); + + visiting.Push(assembly); + visited.Add(assembly); + while (visiting.Count > 0) + { + var visAsm = visiting.Pop(); + foreach (var refAsm in visAsm.GetReferencedAssemblies() + .Select(refAsmName => allAssemblies.SingleOrDefault(x => string.Equals(x.GetName().Name, refAsmName.Name, StringComparison.Ordinal))) + .Where(x => x != null && visited.Contains(x) == false)) + { + yield return refAsm.GetName(); + visiting.Push(refAsm); + visited.Add(refAsm); + } + } + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/TypeHelper.cs b/src/Umbraco.Core/TypeHelper.cs index efb525e575..5cb82b3863 100644 --- a/src/Umbraco.Core/TypeHelper.cs +++ b/src/Umbraco.Core/TypeHelper.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -62,8 +63,17 @@ namespace Umbraco.Core /// private static bool HasReferenceToAssemblyWithName(Assembly assembly, string expectedAssemblyName) { + // The following code was not recursive ie if assembly.1 -> assembly.2 -> assembly.3, and expected is assembly.3, + // it would not consider that assembly.1 has a reference to assembly.3. Can cause issues eg when assembly.3 + // contains an attribute, assembly.2 defines a new attribute that inherit from that attribute, and assembly.1 + // uses the attribute in assembly.2. When looking for assemblies that have a chance to use the attribute, we + // look for assemblies that reference assembly.3, and we would fail to consider assembly.1. + // + // Better get deep-referenced assemblies. Has an impact on perfs obviously but only when the app starts. + return assembly - .GetReferencedAssemblies() + //.GetReferencedAssemblies() + .GetDeepReferencedAssemblies() .Select(a => a.Name) .Contains(expectedAssemblyName, StringComparer.Ordinal); } From a88cb3f72458932f7015b23445c50c9a133f5d4d Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 22 Apr 2014 11:59:21 +1000 Subject: [PATCH 3/3] Fixes: U4-3425 App_Code XSLT Extensions aren't recognized --- src/Umbraco.Core/AssemblyExtensions.cs | 26 --------- src/Umbraco.Core/TypeFinder.cs | 75 ++++++++++++++++++++++---- src/Umbraco.Core/TypeHelper.cs | 26 ++++----- 3 files changed, 74 insertions(+), 53 deletions(-) diff --git a/src/Umbraco.Core/AssemblyExtensions.cs b/src/Umbraco.Core/AssemblyExtensions.cs index fff444c34a..b9e1f4d812 100644 --- a/src/Umbraco.Core/AssemblyExtensions.cs +++ b/src/Umbraco.Core/AssemblyExtensions.cs @@ -68,31 +68,5 @@ namespace Umbraco.Core return new FileInfo(path); } - /// - /// Gets the objects for all the assemblies recursively referenced by a specified assembly. - /// - /// The assembly. - /// The objects for all the assemblies recursively referenced by the specified assembly. - public static IEnumerable GetDeepReferencedAssemblies(this Assembly assembly) - { - var allAssemblies = TypeFinder.GetAllAssemblies(); - var visiting = new Stack(); - var visited = new HashSet(); - - visiting.Push(assembly); - visited.Add(assembly); - while (visiting.Count > 0) - { - var visAsm = visiting.Pop(); - foreach (var refAsm in visAsm.GetReferencedAssemblies() - .Select(refAsmName => allAssemblies.SingleOrDefault(x => string.Equals(x.GetName().Name, refAsmName.Name, StringComparison.Ordinal))) - .Where(x => x != null && visited.Contains(x) == false)) - { - yield return refAsm.GetName(); - visiting.Push(refAsm); - visited.Add(refAsm); - } - } - } } } \ No newline at end of file diff --git a/src/Umbraco.Core/TypeFinder.cs b/src/Umbraco.Core/TypeFinder.cs index 14795e146d..15bee5d720 100644 --- a/src/Umbraco.Core/TypeFinder.cs +++ b/src/Umbraco.Core/TypeFinder.cs @@ -428,7 +428,7 @@ namespace Umbraco.Core if (TypeHelper.IsTypeAssignableFrom(attributeType) == false) throw new ArgumentException("The type specified: " + attributeType + " is not an Attribute type"); - var foundAssignableTypes = new HashSet(); + var foundAttributedTypes = new HashSet(); var assemblyList = assemblies.ToArray(); @@ -437,23 +437,78 @@ namespace Umbraco.Core //contain a class that has this attribute. var referencedAssemblies = TypeHelper.GetReferencedAssemblies(attributeType, assemblyList); + //get a list of non-referenced assemblies (we'll use this when we recurse below) + var otherAssemblies = assemblyList.Where(x => referencedAssemblies.Contains(x) == false).ToArray(); + + //loop through the referenced assemblies foreach (var a in referencedAssemblies) { - //get all types in the assembly that are sub types of the current type - var allTypes = GetTypesWithFormattedException(a).ToArray(); + //get all types in this assembly + var allTypes = GetTypesWithFormattedException(a) + .ToArray(); - var types = allTypes.Where(t => TypeHelper.IsNonStaticClass(t) - && (onlyConcreteClasses == false || t.IsAbstract == false) - //the type must have this attribute - && t.GetCustomAttributes(attributeType, false).Any()); + //now filter the types based on the onlyConcreteClasses flag, not interfaces, not static classes but have + //the specified attribute + var attributedTypes = allTypes + .Where(t => (TypeHelper.IsNonStaticClass(t) + && (onlyConcreteClasses == false || t.IsAbstract == false)) + //the type must have this attribute + && t.GetCustomAttributes(attributeType, false).Any()) + .ToArray(); - foreach (var t in types) + //add the types to our list to return + foreach (var t in attributedTypes) { - foundAssignableTypes.Add(t); + foundAttributedTypes.Add(t); + } + + //get all attributes of the type being searched for + var allAttributeTypes = allTypes.Where(attributeType.IsAssignableFrom); + + //now we need to include types that may be inheriting from sub classes of the attribute type being searched for + //so we will search in assemblies that reference those types too. + foreach (var subTypesInAssembly in allAttributeTypes.GroupBy(x => x.Assembly)){ + + //So that we are not scanning too much, we need to group the sub types: + // * if there is more than 1 sub type in the same assembly then we should only search on the 'lowest base' type. + // * We should also not search for sub types if the type is sealed since you cannot inherit from a sealed class + // * We should not search for sub types if the type is static since you cannot inherit from them. + var subTypeList = subTypesInAssembly + .Where(t => t.IsSealed == false && TypeHelper.IsStaticClass(t) == false) + .ToArray(); + + var baseClassAttempt = TypeHelper.GetLowestBaseType(subTypeList); + + //if there's a base class amongst the types then we'll only search for that type. + //otherwise we'll have to search for all of them. + var subTypesToSearch = new HashSet(); + if (baseClassAttempt.Success) + { + subTypesToSearch.Add(baseClassAttempt.Result); + } + else + { + foreach (var t in subTypeList) + { + subTypesToSearch.Add(t); + } + } + + foreach (var typeToSearch in subTypesToSearch) + { + //recursively find the types inheriting from this sub type in the other non-scanned assemblies. + var foundTypes = FindClassesWithAttribute(typeToSearch, otherAssemblies, onlyConcreteClasses); + + foreach (var f in foundTypes) + { + foundAttributedTypes.Add(f); + } + } + } } - return foundAssignableTypes; + return foundAttributedTypes; } diff --git a/src/Umbraco.Core/TypeHelper.cs b/src/Umbraco.Core/TypeHelper.cs index 5cb82b3863..3a1501f436 100644 --- a/src/Umbraco.Core/TypeHelper.cs +++ b/src/Umbraco.Core/TypeHelper.cs @@ -51,29 +51,21 @@ namespace Umbraco.Core //contain sub type's of the one we're currently looking for return assemblies .Where(assembly => - assembly == assignTypeFrom.Assembly || HasReferenceToAssemblyWithName(assembly, assignTypeFrom.Assembly.GetName().Name)) + assembly == assignTypeFrom.Assembly + || HasReferenceToAssemblyWithName(assembly, assignTypeFrom.Assembly.GetName().Name)) .ToArray(); } - /// - /// checks if the assembly has a reference with the same name as the expected assembly name. - /// - /// - /// - /// + /// + /// checks if the assembly has a reference with the same name as the expected assembly name. + /// + /// + /// + /// private static bool HasReferenceToAssemblyWithName(Assembly assembly, string expectedAssemblyName) { - // The following code was not recursive ie if assembly.1 -> assembly.2 -> assembly.3, and expected is assembly.3, - // it would not consider that assembly.1 has a reference to assembly.3. Can cause issues eg when assembly.3 - // contains an attribute, assembly.2 defines a new attribute that inherit from that attribute, and assembly.1 - // uses the attribute in assembly.2. When looking for assemblies that have a chance to use the attribute, we - // look for assemblies that reference assembly.3, and we would fail to consider assembly.1. - // - // Better get deep-referenced assemblies. Has an impact on perfs obviously but only when the app starts. - return assembly - //.GetReferencedAssemblies() - .GetDeepReferencedAssemblies() + .GetReferencedAssemblies() .Select(a => a.Name) .Contains(expectedAssemblyName, StringComparer.Ordinal); }