Merge branch '6.2.0' of https://github.com/umbraco/Umbraco-CMS into 6.2.0
This commit is contained in:
@@ -81,3 +81,6 @@ build/_BuildOutput/
|
||||
tools/NDepend/
|
||||
src/*.vspx
|
||||
src/*.psess
|
||||
NDependOut/*
|
||||
*.ndproj
|
||||
QueryResult.htm
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Umbraco.Core.Models
|
||||
//This seems to fail during testing
|
||||
//SD: With the new null checks below, this shouldn't fail anymore.
|
||||
var dt = property.PropertyType.DataType(property.Id, dataTypeService);
|
||||
if (dt != null && dt.Data != null)
|
||||
if (dt != null && dt.Data != null && dt.Data.Value != null)
|
||||
{
|
||||
//We've already got the value for the property so we're going to give it to the
|
||||
// data type's data property so it doesn't go re-look up the value from the db again.
|
||||
|
||||
@@ -146,7 +146,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
|
||||
private void CreateUmbracoUserTypeData()
|
||||
{
|
||||
_database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 1, Alias = "admin", Name = "Administrators", DefaultPermissions = "CADMOSKTPIURZ:5F" });
|
||||
_database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 1, Alias = "admin", Name = "Administrators", DefaultPermissions = "CADMOSKTPIURZ:5F7" });
|
||||
_database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 2, Alias = "writer", Name = "Writer", DefaultPermissions = "CAH:F" });
|
||||
_database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 3, Alias = "editor", Name = "Editors", DefaultPermissions = "CADMOSKTPUZ:5F" });
|
||||
_database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 4, Alias = "translator", Name = "Translator", DefaultPermissions = "AF" });
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
@@ -35,7 +36,7 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
internal static Func<string, string, Guid> GetDataTypeCallback = null;
|
||||
|
||||
private static readonly ConcurrentDictionary<Tuple<string, string>, Guid> PropertyTypeCache = new ConcurrentDictionary<Tuple<string, string>, Guid>();
|
||||
private static readonly ConcurrentDictionary<Tuple<string, string, PublishedItemType>, Guid> PropertyTypeCache = new ConcurrentDictionary<Tuple<string, string, PublishedItemType>, Guid>();
|
||||
|
||||
/// <summary>
|
||||
/// Return the GUID Id for the data type assigned to the document type with the property alias
|
||||
@@ -43,16 +44,29 @@ namespace Umbraco.Core
|
||||
/// <param name="applicationContext"></param>
|
||||
/// <param name="docTypeAlias"></param>
|
||||
/// <param name="propertyAlias"></param>
|
||||
/// <param name="itemType"></param>
|
||||
/// <returns></returns>
|
||||
internal static Guid GetDataType(ApplicationContext applicationContext, string docTypeAlias, string propertyAlias)
|
||||
internal static Guid GetDataType(ApplicationContext applicationContext, string docTypeAlias, string propertyAlias, PublishedItemType itemType)
|
||||
{
|
||||
if (GetDataTypeCallback != null)
|
||||
return GetDataTypeCallback(docTypeAlias, propertyAlias);
|
||||
|
||||
var key = new Tuple<string, string>(docTypeAlias, propertyAlias);
|
||||
var key = new Tuple<string, string, PublishedItemType>(docTypeAlias, propertyAlias, itemType);
|
||||
return PropertyTypeCache.GetOrAdd(key, tuple =>
|
||||
{
|
||||
var result = applicationContext.Services.ContentTypeService.GetContentType(docTypeAlias);
|
||||
IContentTypeComposition result = null;
|
||||
switch (itemType)
|
||||
{
|
||||
case PublishedItemType.Content:
|
||||
result = applicationContext.Services.ContentTypeService.GetContentType(docTypeAlias);
|
||||
break;
|
||||
case PublishedItemType.Media:
|
||||
result = applicationContext.Services.ContentTypeService.GetMediaType(docTypeAlias);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("itemType");
|
||||
}
|
||||
|
||||
if (result == null) return Guid.Empty;
|
||||
|
||||
//SD: we need to check for 'any' here because the collection is backed by KeyValuePair which is a struct
|
||||
|
||||
+367
-342
@@ -19,54 +19,56 @@ using Umbraco.Core.IO;
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// A utility class to find all classes of a certain type by reflection in the current bin folder
|
||||
/// of the web application.
|
||||
/// </summary>
|
||||
public static class TypeFinder
|
||||
{
|
||||
|
||||
private static readonly ConcurrentBag<Assembly> LocalFilteredAssemblyCache = new ConcurrentBag<Assembly>();
|
||||
private static readonly ReaderWriterLockSlim LocalFilteredAssemblyCacheLocker = new ReaderWriterLockSlim();
|
||||
private static ReadOnlyCollection<Assembly> _allAssemblies = null;
|
||||
private static ReadOnlyCollection<Assembly> _binFolderAssemblies = null;
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
|
||||
/// <summary>
|
||||
/// A utility class to find all classes of a certain type by reflection in the current bin folder
|
||||
/// of the web application.
|
||||
/// </summary>
|
||||
public static class TypeFinder
|
||||
{
|
||||
private static readonly HashSet<Assembly> LocalFilteredAssemblyCache = new HashSet<Assembly>();
|
||||
private static readonly ReaderWriterLockSlim LocalFilteredAssemblyCacheLocker = new ReaderWriterLockSlim();
|
||||
private static HashSet<Assembly> _allAssemblies = null;
|
||||
private static HashSet<Assembly> _binFolderAssemblies = null;
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// lazily load a reference to all assemblies and only local assemblies.
|
||||
/// This is a modified version of: http://www.dominicpettifer.co.uk/Blog/44/how-to-get-a-reference-to-all-assemblies-in-the--bin-folder
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been
|
||||
/// loaded in the CLR, not all assemblies.
|
||||
/// See these threads:
|
||||
/// http://issues.umbraco.org/issue/U5-198
|
||||
/// http://stackoverflow.com/questions/3552223/asp-net-appdomain-currentdomain-getassemblies-assemblies-missing-after-app
|
||||
/// http://stackoverflow.com/questions/2477787/difference-between-appdomain-getassemblies-and-buildmanager-getreferencedassembl
|
||||
/// </remarks>
|
||||
internal static IEnumerable<Assembly> GetAllAssemblies()
|
||||
{
|
||||
if (_allAssemblies == null)
|
||||
{
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
List<Assembly> assemblies = null;
|
||||
try
|
||||
{
|
||||
var isHosted = HttpContext.Current != null;
|
||||
/// <summary>
|
||||
/// lazily load a reference to all assemblies and only local assemblies.
|
||||
/// This is a modified version of: http://www.dominicpettifer.co.uk/Blog/44/how-to-get-a-reference-to-all-assemblies-in-the--bin-folder
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been
|
||||
/// loaded in the CLR, not all assemblies.
|
||||
/// See these threads:
|
||||
/// http://issues.umbraco.org/issue/U5-198
|
||||
/// http://stackoverflow.com/questions/3552223/asp-net-appdomain-currentdomain-getassemblies-assemblies-missing-after-app
|
||||
/// http://stackoverflow.com/questions/2477787/difference-between-appdomain-getassemblies-and-buildmanager-getreferencedassembl
|
||||
/// </remarks>
|
||||
internal static HashSet<Assembly> GetAllAssemblies()
|
||||
{
|
||||
using (var lck = new UpgradeableReadLock(Locker))
|
||||
{
|
||||
if (_allAssemblies == null)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
if (isHosted)
|
||||
{
|
||||
assemblies = new List<Assembly>(BuildManager.GetReferencedAssemblies().Cast<Assembly>());
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (!(e.InnerException is SecurityException))
|
||||
throw;
|
||||
}
|
||||
lck.UpgradeToWriteLock();
|
||||
|
||||
HashSet<Assembly> assemblies = null;
|
||||
try
|
||||
{
|
||||
var isHosted = HttpContext.Current != null;
|
||||
|
||||
try
|
||||
{
|
||||
if (isHosted)
|
||||
{
|
||||
assemblies = new HashSet<Assembly>(BuildManager.GetReferencedAssemblies().Cast<Assembly>());
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (!(e.InnerException is SecurityException))
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
if (assemblies == null)
|
||||
@@ -77,7 +79,7 @@ namespace Umbraco.Core
|
||||
var binAssemblyFiles = Directory.GetFiles(binFolder, "*.dll", SearchOption.TopDirectoryOnly).ToList();
|
||||
//var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
|
||||
//var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
|
||||
assemblies = new List<Assembly>();
|
||||
assemblies = new HashSet<Assembly>();
|
||||
foreach (var a in binAssemblyFiles)
|
||||
{
|
||||
try
|
||||
@@ -99,151 +101,161 @@ namespace Umbraco.Core
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//if for some reason they are still no assemblies, then use the AppDomain to load in already loaded assemblies.
|
||||
if (!assemblies.Any())
|
||||
{
|
||||
assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies().ToList());
|
||||
}
|
||||
if (!assemblies.Any())
|
||||
{
|
||||
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
assemblies.Add(a);
|
||||
}
|
||||
}
|
||||
|
||||
//here we are trying to get the App_Code assembly
|
||||
var fileExtensions = new[] {".cs", ".vb"}; //only vb and cs files are supported
|
||||
var appCodeFolder = new DirectoryInfo(IOHelper.MapPath(IOHelper.ResolveUrl("~/App_code")));
|
||||
//check if the folder exists and if there are any files in it with the supported file extensions
|
||||
if (appCodeFolder.Exists && (fileExtensions.Any(x => appCodeFolder.GetFiles("*" + x).Any())))
|
||||
{
|
||||
var appCodeAssembly = Assembly.Load("App_Code");
|
||||
if (!assemblies.Contains(appCodeAssembly)) // BuildManager will find App_Code already
|
||||
assemblies.Add(appCodeAssembly);
|
||||
}
|
||||
//here we are trying to get the App_Code assembly
|
||||
var fileExtensions = new[] { ".cs", ".vb" }; //only vb and cs files are supported
|
||||
var appCodeFolder = new DirectoryInfo(IOHelper.MapPath(IOHelper.ResolveUrl("~/App_code")));
|
||||
//check if the folder exists and if there are any files in it with the supported file extensions
|
||||
if (appCodeFolder.Exists && (fileExtensions.Any(x => appCodeFolder.GetFiles("*" + x).Any())))
|
||||
{
|
||||
var appCodeAssembly = Assembly.Load("App_Code");
|
||||
if (!assemblies.Contains(appCodeAssembly)) // BuildManager will find App_Code already
|
||||
assemblies.Add(appCodeAssembly);
|
||||
}
|
||||
|
||||
//now set the _allAssemblies
|
||||
_allAssemblies = new ReadOnlyCollection<Assembly>(assemblies);
|
||||
//now set the _allAssemblies
|
||||
_allAssemblies = new HashSet<Assembly>(assemblies);
|
||||
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (!(e.InnerException is SecurityException))
|
||||
throw;
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (!(e.InnerException is SecurityException))
|
||||
throw;
|
||||
|
||||
_binFolderAssemblies = _allAssemblies;
|
||||
}
|
||||
}
|
||||
}
|
||||
_binFolderAssemblies = _allAssemblies;
|
||||
}
|
||||
}
|
||||
|
||||
return _allAssemblies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns only assemblies found in the bin folder that have been loaded into the app domain.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This will be used if we implement App_Plugins from Umbraco v5 but currently it is not used.
|
||||
/// </remarks>
|
||||
internal static IEnumerable<Assembly> GetBinAssemblies()
|
||||
{
|
||||
return _allAssemblies;
|
||||
}
|
||||
}
|
||||
|
||||
if (_binFolderAssemblies == null)
|
||||
{
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var assemblies = GetAssembliesWithKnownExclusions().ToArray();
|
||||
var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
|
||||
var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
|
||||
var domainAssemblyNames = binAssemblyFiles.Select(AssemblyName.GetAssemblyName);
|
||||
var safeDomainAssemblies = new List<Assembly>();
|
||||
var binFolderAssemblies = new List<Assembly>();
|
||||
/// <summary>
|
||||
/// Returns only assemblies found in the bin folder that have been loaded into the app domain.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This will be used if we implement App_Plugins from Umbraco v5 but currently it is not used.
|
||||
/// </remarks>
|
||||
internal static HashSet<Assembly> GetBinAssemblies()
|
||||
{
|
||||
|
||||
foreach (var a in assemblies)
|
||||
{
|
||||
try
|
||||
{
|
||||
//do a test to see if its queryable in med trust
|
||||
var assemblyFile = a.GetAssemblyFile();
|
||||
safeDomainAssemblies.Add(a);
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
//we will just ignore this because this will fail
|
||||
//in medium trust for system assemblies, we get an exception but we just want to continue until we get to
|
||||
//an assembly that is ok.
|
||||
}
|
||||
}
|
||||
if (_binFolderAssemblies == null)
|
||||
{
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var assemblies = GetAssembliesWithKnownExclusions().ToArray();
|
||||
var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
|
||||
var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
|
||||
var domainAssemblyNames = binAssemblyFiles.Select(AssemblyName.GetAssemblyName);
|
||||
var safeDomainAssemblies = new HashSet<Assembly>();
|
||||
var binFolderAssemblies = new HashSet<Assembly>();
|
||||
|
||||
foreach (var assemblyName in domainAssemblyNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
var foundAssembly =
|
||||
safeDomainAssemblies.FirstOrDefault(a => a.GetAssemblyFile() == assemblyName.GetAssemblyFile());
|
||||
if (foundAssembly != null)
|
||||
{
|
||||
binFolderAssemblies.Add(foundAssembly);
|
||||
}
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
//we will just ignore this because if we are trying to do a call to:
|
||||
// AssemblyName.ReferenceMatchesDefinition(a.GetName(), assemblyName)))
|
||||
//in medium trust for system assemblies, we get an exception but we just want to continue until we get to
|
||||
//an assembly that is ok.
|
||||
}
|
||||
}
|
||||
foreach (var a in assemblies)
|
||||
{
|
||||
try
|
||||
{
|
||||
//do a test to see if its queryable in med trust
|
||||
var assemblyFile = a.GetAssemblyFile();
|
||||
safeDomainAssemblies.Add(a);
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
//we will just ignore this because this will fail
|
||||
//in medium trust for system assemblies, we get an exception but we just want to continue until we get to
|
||||
//an assembly that is ok.
|
||||
}
|
||||
}
|
||||
|
||||
_binFolderAssemblies = new ReadOnlyCollection<Assembly>(binFolderAssemblies);
|
||||
}
|
||||
}
|
||||
return _binFolderAssemblies;
|
||||
}
|
||||
foreach (var assemblyName in domainAssemblyNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
var foundAssembly =
|
||||
safeDomainAssemblies.FirstOrDefault(a => a.GetAssemblyFile() == assemblyName.GetAssemblyFile());
|
||||
if (foundAssembly != null)
|
||||
{
|
||||
binFolderAssemblies.Add(foundAssembly);
|
||||
}
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
//we will just ignore this because if we are trying to do a call to:
|
||||
// AssemblyName.ReferenceMatchesDefinition(a.GetName(), assemblyName)))
|
||||
//in medium trust for system assemblies, we get an exception but we just want to continue until we get to
|
||||
//an assembly that is ok.
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
|
||||
/// and exluding the ones passed in and excluding the exclusion list filter, the results of this are
|
||||
/// cached for perforance reasons.
|
||||
/// </summary>
|
||||
/// <param name="excludeFromResults"></param>
|
||||
/// <returns></returns>
|
||||
internal static IEnumerable<Assembly> GetAssembliesWithKnownExclusions(
|
||||
IEnumerable<Assembly> excludeFromResults = null)
|
||||
{
|
||||
if (LocalFilteredAssemblyCache.Any()) return LocalFilteredAssemblyCache;
|
||||
using (new WriteLock(LocalFilteredAssemblyCacheLocker))
|
||||
{
|
||||
var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
|
||||
assemblies.ForEach(LocalFilteredAssemblyCache.Add);
|
||||
}
|
||||
return LocalFilteredAssemblyCache;
|
||||
}
|
||||
_binFolderAssemblies = new HashSet<Assembly>(binFolderAssemblies);
|
||||
}
|
||||
}
|
||||
return _binFolderAssemblies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of found local Assemblies and exluding the ones passed in and excluding the exclusion list filter
|
||||
/// </summary>
|
||||
/// <param name="excludeFromResults"></param>
|
||||
/// <param name="exclusionFilter"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<Assembly> GetFilteredAssemblies(
|
||||
IEnumerable<Assembly> excludeFromResults = null,
|
||||
string[] exclusionFilter = null)
|
||||
{
|
||||
if (excludeFromResults == null)
|
||||
excludeFromResults = new List<Assembly>();
|
||||
if (exclusionFilter == null)
|
||||
exclusionFilter = new string[] { };
|
||||
/// <summary>
|
||||
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
|
||||
/// and exluding the ones passed in and excluding the exclusion list filter, the results of this are
|
||||
/// cached for perforance reasons.
|
||||
/// </summary>
|
||||
/// <param name="excludeFromResults"></param>
|
||||
/// <returns></returns>
|
||||
internal static HashSet<Assembly> GetAssembliesWithKnownExclusions(
|
||||
IEnumerable<Assembly> excludeFromResults = null)
|
||||
{
|
||||
using (var lck = new UpgradeableReadLock(LocalFilteredAssemblyCacheLocker))
|
||||
{
|
||||
if (LocalFilteredAssemblyCache.Any()) return LocalFilteredAssemblyCache;
|
||||
|
||||
return GetAllAssemblies()
|
||||
.Where(x => !excludeFromResults.Contains(x)
|
||||
&& !x.GlobalAssemblyCache
|
||||
&& !exclusionFilter.Any(f => x.FullName.StartsWith(f)));
|
||||
}
|
||||
lck.UpgradeToWriteLock();
|
||||
|
||||
/// <summary>
|
||||
/// this is our assembly filter to filter out known types that def dont contain types we'd like to find or plugins
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE the comma vs period... comma delimits the name in an Assembly FullName property so if it ends with comma then its an exact name match
|
||||
/// </remarks>
|
||||
internal static readonly string[] KnownAssemblyExclusionFilter = new[]
|
||||
var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
|
||||
foreach (var a in assemblies)
|
||||
{
|
||||
LocalFilteredAssemblyCache.Add(a);
|
||||
}
|
||||
|
||||
return LocalFilteredAssemblyCache;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a distinct list of found local Assemblies and exluding the ones passed in and excluding the exclusion list filter
|
||||
/// </summary>
|
||||
/// <param name="excludeFromResults"></param>
|
||||
/// <param name="exclusionFilter"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<Assembly> GetFilteredAssemblies(
|
||||
IEnumerable<Assembly> excludeFromResults = null,
|
||||
string[] exclusionFilter = null)
|
||||
{
|
||||
if (excludeFromResults == null)
|
||||
excludeFromResults = new HashSet<Assembly>();
|
||||
if (exclusionFilter == null)
|
||||
exclusionFilter = new string[] { };
|
||||
|
||||
return GetAllAssemblies()
|
||||
.Where(x => !excludeFromResults.Contains(x)
|
||||
&& !x.GlobalAssemblyCache
|
||||
&& !exclusionFilter.Any(f => x.FullName.StartsWith(f)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// this is our assembly filter to filter out known types that def dont contain types we'd like to find or plugins
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE the comma vs period... comma delimits the name in an Assembly FullName property so if it ends with comma then its an exact name match
|
||||
/// </remarks>
|
||||
internal static readonly string[] KnownAssemblyExclusionFilter = new[]
|
||||
{
|
||||
"mscorlib,",
|
||||
"System.",
|
||||
@@ -287,11 +299,11 @@ namespace Umbraco.Core
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>()
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<T, TAttribute>(GetAssembliesWithKnownExclusions(), true);
|
||||
}
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>()
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<T, TAttribute>(GetAssembliesWithKnownExclusions(), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the type T that contain the attribute TAttribute
|
||||
@@ -300,11 +312,11 @@ namespace Umbraco.Core
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(IEnumerable<Assembly> assemblies)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<T, TAttribute>(assemblies, true);
|
||||
}
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(IEnumerable<Assembly> assemblies)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<T, TAttribute>(assemblies, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the type T that contain the attribute TAttribute
|
||||
@@ -314,13 +326,13 @@ namespace Umbraco.Core
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<TAttribute>(typeof (T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<TAttribute>(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the assignTypeFrom Type that contain the attribute TAttribute
|
||||
@@ -330,85 +342,85 @@ namespace Umbraco.Core
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<TAttribute>(
|
||||
Type assignTypeFrom,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<TAttribute>(
|
||||
Type assignTypeFrom,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
return GetClasses(assignTypeFrom, assemblies, onlyConcreteClasses,
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
return GetClasses(assignTypeFrom, assemblies, onlyConcreteClasses,
|
||||
//the additional filter will ensure that any found types also have the attribute applied.
|
||||
t => t.GetCustomAttributes<TAttribute>(false).Any());
|
||||
}
|
||||
t => t.GetCustomAttributes<TAttribute>(false).Any());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches all filtered local assemblies specified for classes of the type passed in.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>()
|
||||
{
|
||||
return FindClassesOfType<T>(GetAssembliesWithKnownExclusions(), true);
|
||||
}
|
||||
/// <summary>
|
||||
/// Searches all filtered local assemblies specified for classes of the type passed in.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>()
|
||||
{
|
||||
return FindClassesOfType<T>(GetAssembliesWithKnownExclusions(), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
return GetClasses(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
return FindClassesOfType<T>(assemblies, true);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
return FindClassesOfType<T>(assemblies, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes with the attribute.
|
||||
/// </summary>
|
||||
/// <param name="attributeType">The attribute type </param>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute(
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
/// <summary>
|
||||
/// Finds any classes with the attribute.
|
||||
/// </summary>
|
||||
/// <param name="attributeType">The attribute type </param>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute(
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
if (TypeHelper.IsTypeAssignableFrom<Attribute>(attributeType) == false)
|
||||
throw new ArgumentException("The type specified: " + attributeType + " is not an Attribute type");
|
||||
if (TypeHelper.IsTypeAssignableFrom<Attribute>(attributeType) == false)
|
||||
throw new ArgumentException("The type specified: " + attributeType + " is not an Attribute type");
|
||||
|
||||
var foundAssignableTypes = new List<Type>();
|
||||
var foundAssignableTypes = new HashSet<Type>();
|
||||
|
||||
var assemblyList = assemblies.ToArray();
|
||||
|
||||
@@ -418,71 +430,74 @@ namespace Umbraco.Core
|
||||
var referencedAssemblies = TypeHelper.GetReferencedAssemblies(attributeType, assemblyList);
|
||||
|
||||
foreach (var a in referencedAssemblies)
|
||||
{
|
||||
{
|
||||
//get all types in the assembly that are sub types of the current type
|
||||
var allTypes = GetTypesWithFormattedException(a).ToArray();
|
||||
|
||||
var types = allTypes.Where(t => TypeHelper.IsNonStaticClass(t)
|
||||
&& (onlyConcreteClasses == false || t.IsAbstract == false)
|
||||
//the type must have this attribute
|
||||
|
||||
var types = allTypes.Where(t => TypeHelper.IsNonStaticClass(t)
|
||||
&& (onlyConcreteClasses == false || t.IsAbstract == false)
|
||||
//the type must have this attribute
|
||||
&& t.GetCustomAttributes(attributeType, false).Any());
|
||||
|
||||
foundAssignableTypes.AddRange(types);
|
||||
}
|
||||
foreach (var t in types)
|
||||
{
|
||||
foundAssignableTypes.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
return foundAssignableTypes;
|
||||
}
|
||||
return foundAssignableTypes;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies)
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute<T>(assemblies, true);
|
||||
}
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies)
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute<T>(assemblies, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute in filtered local assemblies
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>()
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute<T>(GetAssembliesWithKnownExclusions());
|
||||
}
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute in filtered local assemblies
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>()
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute<T>(GetAssembliesWithKnownExclusions());
|
||||
}
|
||||
|
||||
|
||||
#region Private methods
|
||||
|
||||
/// <summary>
|
||||
/// Finds types that are assignable from the assignTypeFrom parameter and will scan for these types in the assembly
|
||||
/// list passed in, however we will only scan assemblies that have a reference to the assignTypeFrom Type or any type
|
||||
/// deriving from the base type.
|
||||
/// </summary>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <param name="additionalFilter">An additional filter to apply for what types will actually be included in the return value</param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<Type> GetClasses(
|
||||
Type assignTypeFrom,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
#region Private methods
|
||||
|
||||
/// <summary>
|
||||
/// Finds types that are assignable from the assignTypeFrom parameter and will scan for these types in the assembly
|
||||
/// list passed in, however we will only scan assemblies that have a reference to the assignTypeFrom Type or any type
|
||||
/// deriving from the base type.
|
||||
/// </summary>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <param name="additionalFilter">An additional filter to apply for what types will actually be included in the return value</param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<Type> GetClasses(
|
||||
Type assignTypeFrom,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses,
|
||||
Func<Type, bool> additionalFilter = null)
|
||||
{
|
||||
{
|
||||
//the default filter will always return true.
|
||||
if (additionalFilter == null)
|
||||
{
|
||||
additionalFilter = type => true;
|
||||
}
|
||||
|
||||
var foundAssignableTypes = new List<Type>();
|
||||
var foundAssignableTypes = new HashSet<Type>();
|
||||
|
||||
var assemblyList = assemblies.ToArray();
|
||||
|
||||
@@ -510,8 +525,11 @@ namespace Umbraco.Core
|
||||
.ToArray();
|
||||
|
||||
//add the types to our list to return
|
||||
foundAssignableTypes.AddRange(filteredTypes);
|
||||
|
||||
foreach (var t in filteredTypes)
|
||||
{
|
||||
foundAssignableTypes.Add(t);
|
||||
}
|
||||
|
||||
//now we need to include types that may be inheriting from sub classes of the type being searched for
|
||||
//so we will search in assemblies that reference those types too.
|
||||
foreach (var subTypesInAssembly in allSubTypes.GroupBy(x => x.Assembly))
|
||||
@@ -529,54 +547,61 @@ namespace Umbraco.Core
|
||||
|
||||
//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 List<Type>();
|
||||
var subTypesToSearch = new HashSet<Type>();
|
||||
if (baseClassAttempt.Success)
|
||||
{
|
||||
subTypesToSearch.Add(baseClassAttempt.Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
subTypesToSearch.AddRange(subTypeList);
|
||||
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 = GetClasses(typeToSearch, otherAssemblies, onlyConcreteClasses, additionalFilter);
|
||||
foundAssignableTypes.AddRange(foundTypes);
|
||||
|
||||
foreach (var f in foundTypes)
|
||||
{
|
||||
foundAssignableTypes.Add(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return foundAssignableTypes;
|
||||
}
|
||||
}
|
||||
return foundAssignableTypes;
|
||||
}
|
||||
|
||||
private static IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
|
||||
{
|
||||
//if the assembly is dynamic, do not try to scan it
|
||||
if (a.IsDynamic)
|
||||
return Enumerable.Empty<Type>();
|
||||
private static IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
|
||||
{
|
||||
//if the assembly is dynamic, do not try to scan it
|
||||
if (a.IsDynamic)
|
||||
return Enumerable.Empty<Type>();
|
||||
|
||||
try
|
||||
{
|
||||
return a.GetExportedTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Could not load types from assembly " + a.FullName + ", errors:");
|
||||
foreach (var loaderException in ex.LoaderExceptions.WhereNotNull())
|
||||
{
|
||||
sb.AppendLine("Exception: " + loaderException);
|
||||
}
|
||||
throw new ReflectionTypeLoadException(ex.Types, ex.LoaderExceptions, sb.ToString());
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
return a.GetExportedTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Could not load types from assembly " + a.FullName + ", errors:");
|
||||
foreach (var loaderException in ex.LoaderExceptions.WhereNotNull())
|
||||
{
|
||||
sb.AppendLine("Exception: " + loaderException);
|
||||
}
|
||||
throw new ReflectionTypeLoadException(ex.Types, ex.LoaderExceptions, sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.XPath;
|
||||
using Examine;
|
||||
@@ -16,6 +17,7 @@ using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using Umbraco.Tests.UmbracoExamine;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
@@ -68,6 +70,38 @@ namespace Umbraco.Tests.PublishedContent
|
||||
return GetNode(id, GetUmbracoContext("/test", 1234));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Property_Value_Uses_Converter()
|
||||
{
|
||||
var mType = MockedContentTypes.CreateImageMediaType();
|
||||
//lets add an RTE to this
|
||||
mType.PropertyGroups.First().PropertyTypes.Add(
|
||||
new PropertyType(new Guid(), DataTypeDatabaseType.Nvarchar)
|
||||
{
|
||||
Alias = "content",
|
||||
Name = "Rich Text",
|
||||
DataTypeDefinitionId = -87 //tiny mce
|
||||
});
|
||||
ServiceContext.ContentTypeService.Save(mType);
|
||||
var media = MockedMedia.CreateMediaImage(mType, -1);
|
||||
media.Properties["content"].Value = "<div>This is some content</div>";
|
||||
ServiceContext.MediaService.Save(media);
|
||||
|
||||
var publishedMedia = GetNode(media.Id);
|
||||
|
||||
var propVal = publishedMedia.GetPropertyValue("content");
|
||||
Assert.IsTrue(TypeHelper.IsTypeAssignableFrom<IHtmlString>(propVal.GetType()));
|
||||
Assert.AreEqual("<div>This is some content</div>", propVal.ToString());
|
||||
|
||||
var propVal2 = publishedMedia.GetPropertyValue<IHtmlString>("content");
|
||||
Assert.IsTrue(TypeHelper.IsTypeAssignableFrom<IHtmlString>(propVal2.GetType()));
|
||||
Assert.AreEqual("<div>This is some content</div>", propVal2.ToString());
|
||||
|
||||
var propVal3 = publishedMedia.GetPropertyValue("Content");
|
||||
Assert.IsTrue(TypeHelper.IsTypeAssignableFrom<IHtmlString>(propVal3.GetType()));
|
||||
Assert.AreEqual("<div>This is some content</div>", propVal3.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ensure_Children_Sorted_With_Examine()
|
||||
{
|
||||
@@ -339,7 +373,6 @@ namespace Umbraco.Tests.PublishedContent
|
||||
Assert.AreEqual(mChild1.Id, publishedSubChild1.Parent.Id);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Ancestors_Without_Examine()
|
||||
{
|
||||
|
||||
@@ -2138,6 +2138,7 @@
|
||||
<Content Include="Umbraco\PartialViews\Templates\EmptyTemplate.cshtml" />
|
||||
<Content Include="Umbraco\PartialViews\Templates\RegisterMember.cshtml" />
|
||||
<Content Include="Umbraco\PartialViews\Templates\LoginStatus.cshtml" />
|
||||
<Content Include="Umbraco\PartialViews\Templates\EditProfile.cshtml" />
|
||||
<None Include="Umbraco_client\CodeMirror\js\mode\coffeescript\LICENSE" />
|
||||
<None Include="Umbraco_client\CodeMirror\js\mode\pascal\LICENSE" />
|
||||
<None Include="Umbraco_client\CodeMirror\js\mode\perl\LICENSE" />
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
@inherits Umbraco.Web.Macros.PartialViewMacroPage
|
||||
|
||||
@using System.Web.Mvc.Html
|
||||
@using ClientDependency.Core.Mvc
|
||||
@using umbraco.cms.businesslogic.member
|
||||
@using Umbraco.Web
|
||||
@using Umbraco.Web.Models
|
||||
@using Umbraco.Web.Controllers
|
||||
|
||||
@{
|
||||
var profileModel = new ProfileModel();
|
||||
|
||||
Html.EnableClientValidation();
|
||||
Html.EnableUnobtrusiveJavaScript();
|
||||
Html.RequiresJs("/umbraco_client/ui/jquery.js");
|
||||
Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.min.js");
|
||||
Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js");
|
||||
}
|
||||
|
||||
@if (Member.IsLoggedOn())
|
||||
{
|
||||
@Html.RenderJsHere()
|
||||
|
||||
using (Html.BeginUmbracoForm<ProfileController>("HandleUpdateProfile"))
|
||||
{
|
||||
<fieldset>
|
||||
<legend>Edit profile</legend>
|
||||
|
||||
@Html.LabelFor(m => profileModel.Name)
|
||||
@Html.TextBoxFor(m => profileModel.Name)
|
||||
@Html.ValidationMessageFor(m => profileModel.Name)
|
||||
<br />
|
||||
|
||||
@Html.LabelFor(m => profileModel.Email)
|
||||
@Html.TextBoxFor(m => profileModel.Email)
|
||||
@Html.ValidationMessageFor(m => profileModel.Email)
|
||||
<br />
|
||||
|
||||
@for (var i = 0; i < profileModel.MemberProperties.Count; i++)
|
||||
{
|
||||
@Html.LabelFor(m => profileModel.MemberProperties[i].Value, profileModel.MemberProperties[i].Name)
|
||||
@Html.EditorFor(m => profileModel.MemberProperties[i].Value)
|
||||
@Html.HiddenFor(m => profileModel.MemberProperties[i].Alias)
|
||||
<br />
|
||||
}
|
||||
|
||||
@Html.HiddenFor(m => profileModel.MemberTypeAlias)
|
||||
|
||||
<button>Save</button>
|
||||
</fieldset>
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
@using System.Web.Mvc.Html
|
||||
@using ClientDependency.Core.Mvc
|
||||
@using Umbraco.Web
|
||||
@using Umbraco.Web.Models
|
||||
@using Umbraco.Web.Controllers
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@inherits Umbraco.Web.Macros.PartialViewMacroPage
|
||||
@using ClientDependency.Core.Mvc
|
||||
@using Umbraco.Web
|
||||
@using Umbraco.Web.Models
|
||||
@using Umbraco.Web.Controllers
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
@using System.Web.Mvc.Html
|
||||
@using ClientDependency.Core.Mvc
|
||||
@using Umbraco.Web
|
||||
@using Umbraco.Web.Models
|
||||
@using Umbraco.Web.Controllers
|
||||
|
||||
@{
|
||||
var registerModel = new RegisterModel();
|
||||
registerModel.FillModel(registerModel, Model.MacroParameters);
|
||||
|
||||
|
||||
Html.EnableClientValidation();
|
||||
Html.EnableUnobtrusiveJavaScript();
|
||||
Html.RequiresJs("/umbraco_client/ui/jquery.js");
|
||||
@@ -23,6 +23,11 @@
|
||||
<fieldset>
|
||||
<legend>Register Member</legend>
|
||||
|
||||
@Html.LabelFor(m => registerModel.Name)
|
||||
@Html.TextBoxFor(m => registerModel.Name)
|
||||
@Html.ValidationMessageFor(m => registerModel.Name)
|
||||
<br />
|
||||
|
||||
@Html.LabelFor(m => registerModel.Email)
|
||||
@Html.TextBoxFor(m => registerModel.Email)
|
||||
@Html.ValidationMessageFor(m => registerModel.Email)
|
||||
@@ -33,14 +38,16 @@
|
||||
@Html.ValidationMessageFor(m => registerModel.Password)
|
||||
<br />
|
||||
|
||||
@for (var i = 0; i < registerModel.MemberProperties.Count; i++)
|
||||
{
|
||||
@Html.LabelFor(m => registerModel.MemberProperties[i].Value, registerModel.MemberProperties[i].Name)
|
||||
@Html.EditorFor(m => registerModel.MemberProperties[i].Value)
|
||||
@Html.HiddenFor(m => registerModel.MemberProperties[i].Alias)
|
||||
<br />
|
||||
@if (registerModel.MemberProperties != null) {
|
||||
for (var i = 0; i < registerModel.MemberProperties.Count; i++)
|
||||
{
|
||||
@Html.LabelFor(m => registerModel.MemberProperties[i].Value, registerModel.MemberProperties[i].Name)
|
||||
@Html.EditorFor(m => registerModel.MemberProperties[i].Value)
|
||||
@Html.HiddenFor(m => registerModel.MemberProperties[i].Alias)
|
||||
<br />
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Html.HiddenFor(m => registerModel.MemberTypeAlias)
|
||||
|
||||
<button>Register</button>
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
<notFound assembly="umbraco" type="SearchForAlias" />
|
||||
<notFound assembly="umbraco" type="SearchForTemplate"/>
|
||||
<notFound assembly="umbraco" type="SearchForProfile"/>
|
||||
<notFound assembly="umbraco" type="handle404"/>
|
||||
<notFound assembly="umbraco" type="handle404" last="true"/>
|
||||
</NotFoundHandlers>
|
||||
@@ -3,5 +3,5 @@
|
||||
<notFound assembly="umbraco" type="SearchForAlias" />
|
||||
<notFound assembly="umbraco" type="SearchForTemplate"/>
|
||||
<notFound assembly="umbraco" type="SearchForProfile"/>
|
||||
<notFound assembly="umbraco" type="handle404"/>
|
||||
<notFound assembly="umbraco" type="handle404" last="true"/>
|
||||
</NotFoundHandlers>
|
||||
@@ -10,7 +10,7 @@ NOTES:
|
||||
* Compression/Combination/Minification is not enabled unless debug="false" is specified on the 'compiliation' element in the web.config
|
||||
* A new version will invalidate both client and server cache and create new persisted files
|
||||
-->
|
||||
<clientDependency version="8" fileDependencyExtensions=".js,.css" loggerType="Umbraco.Web.UI.CdfLogger, umbraco">
|
||||
<clientDependency version="9" fileDependencyExtensions=".js,.css" loggerType="Umbraco.Web.UI.CdfLogger, umbraco">
|
||||
|
||||
<!--
|
||||
This section is used for Web Forms only, the enableCompositeFiles="true" is optional and by default is set to true.
|
||||
|
||||
@@ -16,9 +16,13 @@ namespace Umbraco.Web.Controllers
|
||||
{
|
||||
if (Member.IsLoggedOn())
|
||||
{
|
||||
var memberId = Member.CurrentMemberId();
|
||||
Member.RemoveMemberFromCache(memberId);
|
||||
Member.ClearMemberFromClient(memberId);
|
||||
var member = Member.GetCurrentMember();
|
||||
if (member != null)
|
||||
{
|
||||
var memberId = member.Id;
|
||||
Member.RemoveMemberFromCache(memberId);
|
||||
Member.ClearMemberFromClient(memberId);
|
||||
}
|
||||
}
|
||||
|
||||
return Redirect("/");
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using System.Xml;
|
||||
using umbraco.cms.businesslogic.member;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Mvc;
|
||||
|
||||
namespace Umbraco.Web.Controllers
|
||||
{
|
||||
public class ProfileController : SurfaceController
|
||||
{
|
||||
[HttpPost]
|
||||
public ActionResult HandleUpdateProfile([Bind(Prefix="profileModel")]ProfileModel model)
|
||||
{
|
||||
//TODO: Use new Member API
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var member = Member.GetCurrentMember();
|
||||
if (member != null)
|
||||
{
|
||||
if (model.Name != null)
|
||||
{
|
||||
member.Text = model.Name;
|
||||
}
|
||||
|
||||
member.Email = model.Email;
|
||||
member.LoginName = model.Email;
|
||||
|
||||
if (model.MemberProperties != null)
|
||||
{
|
||||
foreach (var property in model.MemberProperties.Where(p => p.Value != null))
|
||||
{
|
||||
member.getProperty(property.Alias).Value = property.Value;
|
||||
}
|
||||
}
|
||||
|
||||
member.Save();
|
||||
|
||||
member.XmlGenerate(new XmlDocument());
|
||||
|
||||
Member.AddMemberToCache(member);
|
||||
|
||||
Response.Redirect("/");
|
||||
}
|
||||
}
|
||||
|
||||
return CurrentUmbracoPage();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,13 +21,22 @@ namespace Umbraco.Web.Controllers
|
||||
var mt = MemberType.GetByAlias(model.MemberTypeAlias) ?? MemberType.MakeNew(user, model.MemberTypeAlias);
|
||||
|
||||
var member = Member.MakeNew(model.Email, mt, user);
|
||||
|
||||
if (model.Name != null)
|
||||
{
|
||||
member.Text = model.Name;
|
||||
}
|
||||
|
||||
member.Email = model.Email;
|
||||
member.LoginName = model.Email;
|
||||
member.Password = model.Password;
|
||||
|
||||
foreach (var property in model.MemberProperties)
|
||||
if (model.MemberProperties != null)
|
||||
{
|
||||
member.getProperty(property.Alias).Value = property.Value;
|
||||
foreach (var property in model.MemberProperties.Where(p => p.Value != null))
|
||||
{
|
||||
member.getProperty(property.Alias).Value = property.Value;
|
||||
}
|
||||
}
|
||||
|
||||
member.Save();
|
||||
|
||||
@@ -236,10 +236,11 @@ namespace Umbraco.Web.Models
|
||||
}
|
||||
|
||||
//get the data type id for the current property
|
||||
var dataType = Umbraco.Core.PublishedContentHelper.GetDataType(
|
||||
var dataType = PublishedContentHelper.GetDataType(
|
||||
ApplicationContext.Current,
|
||||
userProperty.DocumentTypeAlias,
|
||||
userProperty.Alias);
|
||||
userProperty.Alias,
|
||||
ItemType);
|
||||
|
||||
//convert the string value to a known type
|
||||
var converted = Umbraco.Core.PublishedContentHelper.ConvertPropertyValue(result, dataType, userProperty.DocumentTypeAlias, userProperty.Alias);
|
||||
|
||||
@@ -9,10 +9,14 @@ namespace Umbraco.Web.Models
|
||||
//TODO Use new Member API
|
||||
if (Member.IsLoggedOn())
|
||||
{
|
||||
this.Name = Member.GetCurrentMember().Text;
|
||||
this.Username = Member.GetCurrentMember().LoginName;
|
||||
this.Email = Member.GetCurrentMember().Email;
|
||||
this.IsLoggedIn = true;
|
||||
var member = Member.GetCurrentMember();
|
||||
if (member != null)
|
||||
{
|
||||
this.Name = member.Text;
|
||||
this.Username = member.LoginName;
|
||||
this.Email = member.Email;
|
||||
this.IsLoggedIn = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using umbraco.cms.businesslogic.member;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
public class ProfileModel
|
||||
{
|
||||
public ProfileModel()
|
||||
{
|
||||
if (Member.IsLoggedOn())
|
||||
{
|
||||
//TODO Use new Member API
|
||||
var member = Member.GetCurrentMember();
|
||||
if (member != null)
|
||||
{
|
||||
this.Name = member.Text;
|
||||
|
||||
this.Email = member.Email;
|
||||
|
||||
this.MemberProperties = new List<UmbracoProperty>();
|
||||
|
||||
var memberType = MemberType.GetByAlias(member.ContentType.Alias);
|
||||
var memberTypeProperties = memberType.PropertyTypes.ToList();
|
||||
|
||||
if (memberTypeProperties.Where(memberType.MemberCanEdit).Any())
|
||||
{
|
||||
memberTypeProperties = memberTypeProperties.Where(memberType.MemberCanEdit).ToList();
|
||||
}
|
||||
|
||||
foreach (var prop in memberTypeProperties)
|
||||
{
|
||||
|
||||
var value = string.Empty;
|
||||
var propValue = member.getProperty(prop.Alias);
|
||||
if (propValue != null)
|
||||
{
|
||||
value = propValue.Value.ToString();
|
||||
}
|
||||
|
||||
this.MemberProperties.Add(new UmbracoProperty
|
||||
{
|
||||
Alias = prop.Alias,
|
||||
Name = prop.Name,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Required]
|
||||
[RegularExpression(@"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
|
||||
ErrorMessage = "Please enter a valid e-mail address")]
|
||||
public string Email { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string MemberTypeAlias { get; set; }
|
||||
|
||||
public List<UmbracoProperty> MemberProperties { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,40 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using umbraco.cms.businesslogic.member;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
public class RegisterModel
|
||||
{
|
||||
public RegisterModel()
|
||||
{
|
||||
this.MemberTypeAlias = "UmbracoMember";
|
||||
|
||||
var memberType = MemberType.GetByAlias(this.MemberTypeAlias);
|
||||
|
||||
if (memberType != null)
|
||||
{
|
||||
this.MemberProperties = new List<UmbracoProperty>();
|
||||
|
||||
var memberTypeProperties = memberType.PropertyTypes.ToList();
|
||||
|
||||
if (memberTypeProperties.Where(memberType.MemberCanEdit).Any())
|
||||
{
|
||||
memberTypeProperties = memberTypeProperties.Where(memberType.MemberCanEdit).ToList();
|
||||
}
|
||||
|
||||
foreach (var prop in memberTypeProperties)
|
||||
{
|
||||
this.MemberProperties.Add(new UmbracoProperty
|
||||
{
|
||||
Alias = prop.Alias,
|
||||
Name = prop.Name,
|
||||
Value = string.Empty
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Required]
|
||||
[RegularExpression(@"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
|
||||
ErrorMessage = "Please enter a valid e-mail address")]
|
||||
@@ -16,36 +44,10 @@ namespace Umbraco.Web.Models
|
||||
[Required]
|
||||
public string Password { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string MemberTypeAlias { get; set; }
|
||||
|
||||
public List<UmbracoProperty> MemberProperties { get; set; }
|
||||
|
||||
public void FillModel(RegisterModel registerModel, IDictionary<string, object> macroParameters)
|
||||
{
|
||||
registerModel.MemberTypeAlias = macroParameters.GetValueAsString("memberTypeAlias", "UmbracoMember");
|
||||
|
||||
registerModel.MemberProperties = new List<UmbracoProperty>();
|
||||
|
||||
var memberType = MemberType.GetByAlias(registerModel.MemberTypeAlias);
|
||||
|
||||
var memberTypeProperties = memberType.PropertyTypes.ToList();
|
||||
|
||||
if (memberTypeProperties.Where(memberType.MemberCanEdit).Any())
|
||||
{
|
||||
memberTypeProperties = memberTypeProperties.Where(memberType.MemberCanEdit).ToList();
|
||||
}
|
||||
|
||||
foreach (var prop in memberTypeProperties)
|
||||
{
|
||||
registerModel.MemberProperties.Add(new UmbracoProperty { Alias = prop.Alias, Name = prop.Name, Value = string.Empty });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class UmbracoProperty
|
||||
{
|
||||
public string Alias { get; set; }
|
||||
public string Value { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,13 @@ namespace Umbraco.Web.Mvc
|
||||
//ensure TempData and ViewData is copied across
|
||||
foreach (var d in context.Controller.ViewData)
|
||||
routeDef.Controller.ViewData[d.Key] = d.Value;
|
||||
routeDef.Controller.TempData = context.Controller.TempData;
|
||||
|
||||
//We cannot simply merge the temp data because during controller execution it will attempt to 'load' temp data
|
||||
// but since it has not been saved, there will be nothing to load and it will revert to nothing, so the trick is
|
||||
// to Save the state of the temp data first then it will automatically be picked up.
|
||||
// http://issues.umbraco.org/issue/U4-1339
|
||||
context.Controller.TempData.Save(context, ((Controller)context.Controller).TempDataProvider);
|
||||
|
||||
using (DisposableTimer.TraceDuration<UmbracoPageResult>("Executing Umbraco RouteDefinition controller", "Finished"))
|
||||
{
|
||||
try
|
||||
|
||||
@@ -153,7 +153,10 @@ namespace Umbraco.Web
|
||||
|
||||
//Here we need to put the value through the IPropertyEditorValueConverter's
|
||||
//get the data type id for the current property
|
||||
var dataType = PublishedContentHelper.GetDataType(ApplicationContext.Current, doc.DocumentTypeAlias, alias);
|
||||
var dataType = PublishedContentHelper.GetDataType(
|
||||
ApplicationContext.Current, doc.DocumentTypeAlias, alias,
|
||||
doc.ItemType);
|
||||
|
||||
//convert the string value to a known type
|
||||
var converted = PublishedContentHelper.ConvertPropertyValue(p.Value, dataType, doc.DocumentTypeAlias, alias);
|
||||
return converted.Success
|
||||
@@ -188,7 +191,7 @@ namespace Umbraco.Web
|
||||
//before we try to convert it manually, lets see if the PropertyEditorValueConverter does this for us
|
||||
//Here we need to put the value through the IPropertyEditorValueConverter's
|
||||
//get the data type id for the current property
|
||||
var dataType = PublishedContentHelper.GetDataType(ApplicationContext.Current, prop.DocumentTypeAlias, alias);
|
||||
var dataType = PublishedContentHelper.GetDataType(ApplicationContext.Current, prop.DocumentTypeAlias, alias, prop.ItemType);
|
||||
//convert the value to a known type
|
||||
var converted = PublishedContentHelper.ConvertPropertyValue(p.Value, dataType, prop.DocumentTypeAlias, alias);
|
||||
object parsedLinksVal;
|
||||
|
||||
@@ -88,14 +88,25 @@ namespace Umbraco.Web.Routing
|
||||
|
||||
#region Utilities
|
||||
|
||||
private bool FindByUrlAliasEnabled
|
||||
private static bool FindByUrlAliasEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
var hasFinder = ContentFinderResolver.Current.ContainsType<ContentFinderByUrlAlias>();
|
||||
var hasHandler = ContentFinderResolver.Current.ContainsType<ContentFinderByNotFoundHandlers>()
|
||||
&& NotFoundHandlerHelper.CustomHandlerTypes.Contains(typeof(global::umbraco.SearchForAlias));
|
||||
return hasFinder || hasHandler;
|
||||
// finder
|
||||
if (ContentFinderResolver.Current.ContainsType<ContentFinderByUrlAlias>())
|
||||
return true;
|
||||
|
||||
// handler wrapped into a finder
|
||||
if (ContentFinderResolver.Current.ContainsType<ContentFinderByNotFoundHandler<global::umbraco.SearchForAlias>>())
|
||||
return true;
|
||||
|
||||
// handler wrapped into special finder
|
||||
if (ContentFinderResolver.Current.ContainsType<ContentFinderByNotFoundHandlers>()
|
||||
&& NotFoundHandlerHelper.IsNotFoundHandlerEnabled<global::umbraco.SearchForAlias>())
|
||||
return true;
|
||||
|
||||
// anything else, we can't detect
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,115 +29,77 @@ namespace Umbraco.Web.Routing
|
||||
|
||||
#region Copied over and adapted from presentation.requestHandler
|
||||
|
||||
void HandlePageNotFound(PublishedContentRequest docRequest)
|
||||
private static void HandlePageNotFound(PublishedContentRequest docRequest)
|
||||
{
|
||||
var url = NotFoundHandlerHelper.GetLegacyUrlForNotFoundHandlers();
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Running for legacy url='{0}'.", () => url);
|
||||
|
||||
foreach (var handler in GetNotFoundHandlers())
|
||||
foreach (var handler in NotFoundHandlerHelper.GetNotFoundHandlers())
|
||||
{
|
||||
IContentFinder finder = null;
|
||||
var handlerName = handler.GetType().FullName;
|
||||
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}'.", () => handlerName);
|
||||
|
||||
// replace with our own implementation
|
||||
if (handler is global::umbraco.SearchForAlias)
|
||||
finder = new ContentFinderByUrlAlias();
|
||||
else if (handler is global::umbraco.SearchForProfile)
|
||||
finder = new ContentFinderByProfile();
|
||||
else if (handler is global::umbraco.SearchForTemplate)
|
||||
finder = new ContentFinderByNiceUrlAndTemplate();
|
||||
else if (handler is global::umbraco.handle404)
|
||||
finder = new ContentFinderByLegacy404();
|
||||
|
||||
var finder = NotFoundHandlerHelper.SubsituteFinder(handler);
|
||||
if (finder != null)
|
||||
{
|
||||
var finderName = finder.GetType().FullName;
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Replace handler '{0}' by new finder '{1}'.", () => handlerName, () => finderName);
|
||||
if (finder.TryFindContent(docRequest))
|
||||
{
|
||||
// do NOT set docRequest.PublishedContent again here as
|
||||
// it would clear any template that the finder might have set
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Finder '{0}' found node with id={1}.", () => finderName, () => docRequest.PublishedContent.Id);
|
||||
if (docRequest.Is404)
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Finder '{0}' set status to 404.", () => finderName);
|
||||
|
||||
// if we found a document, break, don't look at more handler -- we're done
|
||||
break;
|
||||
}
|
||||
// can't find a document => continue with other handlers
|
||||
if (finder.TryFindContent(docRequest) == false)
|
||||
continue;
|
||||
|
||||
// if we did not find a document, continue, look at other handlers
|
||||
continue;
|
||||
}
|
||||
// found a document => break, don't run other handlers, we're done
|
||||
|
||||
// else it's a legacy handler, run
|
||||
// in theory an IContentFinder can return true yet set no document
|
||||
// but none of the substitued finders (see SubstituteFinder) do it.
|
||||
|
||||
if (handler.Execute(url) && handler.redirectID > 0)
|
||||
{
|
||||
var redirectId = handler.redirectID;
|
||||
docRequest.PublishedContent = docRequest.RoutingContext.UmbracoContext.ContentCache.GetById(redirectId);
|
||||
// do NOT set docRequest.PublishedContent again here
|
||||
// as it would clear any template that the finder might have set
|
||||
|
||||
if (!docRequest.HasPublishedContent)
|
||||
{
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' found node with id={1} which is not valid.", () => handlerName, () => redirectId);
|
||||
break;
|
||||
}
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Finder '{0}' found node with id={1}.", () => finderName, () => docRequest.PublishedContent.Id);
|
||||
if (docRequest.Is404)
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Finder '{0}' set status to 404.", () => finderName);
|
||||
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' found valid node with id={1}.", () => handlerName, () => redirectId);
|
||||
|
||||
if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404)
|
||||
{
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' set status code to 404.", () => handlerName);
|
||||
docRequest.Is404 = true;
|
||||
}
|
||||
|
||||
//// check for caching
|
||||
//if (handler.CacheUrl)
|
||||
//{
|
||||
// if (url.StartsWith("/"))
|
||||
// url = "/" + url;
|
||||
|
||||
// var cacheKey = (currentDomain == null ? "" : currentDomain.Name) + url;
|
||||
// var culture = currentDomain == null ? null : currentDomain.Language.CultureAlias;
|
||||
// SetCache(cacheKey, new CacheEntry(handler.redirectID.ToString(), culture));
|
||||
|
||||
// HttpContext.Current.Trace.Write("NotFoundHandler",
|
||||
// string.Format("Added to cache '{0}', {1}.", url, handler.redirectID));
|
||||
//}
|
||||
|
||||
// if we found a document, break, don't look at more handler -- we're done
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' found valid node with id={1}.", () => handlerName, () => docRequest.PublishedContent.Id);
|
||||
break;
|
||||
}
|
||||
|
||||
// if we did not find a document, continue, look at other handlers
|
||||
// else it's a legacy handler: run
|
||||
|
||||
// can't find a document => continue with other handlers
|
||||
if (handler.Execute(url) == false || handler.redirectID <= 0)
|
||||
continue;
|
||||
|
||||
// found a document ID => ensure it's a valid document
|
||||
var redirectId = handler.redirectID;
|
||||
docRequest.PublishedContent = docRequest.RoutingContext.UmbracoContext.ContentCache.GetById(redirectId);
|
||||
|
||||
if (docRequest.HasPublishedContent == false)
|
||||
{
|
||||
// the handler said it could handle the url, and returned a content ID
|
||||
// yet that content ID is invalid... should we run the other handlers?
|
||||
// I don't think so, not here, let the "last chance" finder take care.
|
||||
// so, break.
|
||||
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' found node with id={1} which is not valid.", () => handlerName, () => redirectId);
|
||||
break;
|
||||
}
|
||||
|
||||
// found a valid document => break, don't run other handlers, we're done
|
||||
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' found valid node with id={1}.", () => handlerName, () => redirectId);
|
||||
|
||||
if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404)
|
||||
{
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' set status code to 404.", () => handlerName);
|
||||
docRequest.Is404 = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<INotFoundHandler> GetNotFoundHandlers()
|
||||
{
|
||||
// instanciate new handlers
|
||||
// using definition cache
|
||||
|
||||
var handlers = new List<INotFoundHandler>();
|
||||
|
||||
foreach (var type in NotFoundHandlerHelper.CustomHandlerTypes)
|
||||
{
|
||||
try
|
||||
{
|
||||
var handler = Activator.CreateInstance(type) as INotFoundHandler;
|
||||
if (handler != null)
|
||||
handlers.Add(handler);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error<ContentFinderByNotFoundHandlers>(string.Format("Error instanciating handler {0}, ignoring.", type.FullName), e);
|
||||
}
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="IContentFinder"/> that runs legacy <c>INotFoundHandler</c> in "last chance" situation.
|
||||
/// </summary>
|
||||
public class ContentLastChanceFinderByNotFoundHandlers : IContentFinder
|
||||
{
|
||||
// notes
|
||||
//
|
||||
// at the moment we load the legacy INotFoundHandler
|
||||
// excluding those that have been replaced by proper finders,
|
||||
// and run them.
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find and assign an Umbraco document to a <c>PublishedContentRequest</c>.
|
||||
/// </summary>
|
||||
/// <param name="docRequest">The <c>PublishedContentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
public bool TryFindContent(PublishedContentRequest docRequest)
|
||||
{
|
||||
HandlePageNotFound(docRequest);
|
||||
return docRequest.HasPublishedContent;
|
||||
}
|
||||
|
||||
#region Copied over and adapted from presentation.requestHandler
|
||||
|
||||
private static void HandlePageNotFound(PublishedContentRequest docRequest)
|
||||
{
|
||||
var url = NotFoundHandlerHelper.GetLegacyUrlForNotFoundHandlers();
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Running for legacy url='{0}'.", () => url);
|
||||
|
||||
var handler = NotFoundHandlerHelper.GetNotFoundLastChanceHandler();
|
||||
var handlerName = handler.GetType().FullName;
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Handler '{0}'.", () => handlerName);
|
||||
|
||||
var finder = NotFoundHandlerHelper.SubsituteFinder(handler);
|
||||
if (finder != null)
|
||||
{
|
||||
var finderName = finder.GetType().FullName;
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Replace handler '{0}' by new finder '{1}'.", () => handlerName, () => finderName);
|
||||
|
||||
// can't find a document => exit
|
||||
if (finder.TryFindContent(docRequest) == false)
|
||||
return;
|
||||
|
||||
// found a document => we're done
|
||||
|
||||
// in theory an IContentFinder can return true yet set no document
|
||||
// but none of the substitued finders (see SubstituteFinder) do it.
|
||||
|
||||
// do NOT set docRequest.PublishedContent again here
|
||||
// as it would clear any template that the finder might have set
|
||||
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Finder '{0}' found node with id={1}.", () => finderName, () => docRequest.PublishedContent.Id);
|
||||
if (docRequest.Is404)
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Finder '{0}' set status to 404.", () => finderName);
|
||||
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Handler '{0}' found valid node with id={1}.", () => handlerName, () => docRequest.PublishedContent.Id);
|
||||
return;
|
||||
}
|
||||
|
||||
// else it's a legacy handler, run
|
||||
|
||||
// can't find a document => exit
|
||||
if (handler.Execute(url) == false || handler.redirectID <= 0)
|
||||
return;
|
||||
|
||||
// found a document ID => ensure it's a valid document
|
||||
var redirectId = handler.redirectID;
|
||||
docRequest.PublishedContent = docRequest.RoutingContext.UmbracoContext.ContentCache.GetById(redirectId);
|
||||
|
||||
if (docRequest.HasPublishedContent == false)
|
||||
{
|
||||
// the handler said it could handle the url, and returned a content ID
|
||||
// yet that content ID is invalid... exit.
|
||||
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Handler '{0}' found node with id={1} which is not valid.", () => handlerName, () => redirectId);
|
||||
return;
|
||||
}
|
||||
|
||||
// found a valid document => return
|
||||
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Handler '{0}' found valid node with id={1}.", () => handlerName, () => redirectId);
|
||||
|
||||
if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404)
|
||||
{
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Handler '{0}' set status code to 404.", () => handlerName);
|
||||
docRequest.Is404 = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
@@ -36,14 +39,14 @@ namespace Umbraco.Web.Routing
|
||||
return url;
|
||||
|
||||
// code from requestModule.UmbracoRewrite
|
||||
string tmp = httpContext.Request.Path.ToLower();
|
||||
var tmp = httpContext.Request.Path.ToLower();
|
||||
|
||||
// note: requestModule.UmbracoRewrite also did some stripping of &umbPage
|
||||
// from the querystring... that was in v3.x to fix some issues with pre-forms
|
||||
// auth. Paul Sterling confirmed in jan. 2013 that we can get rid of it.
|
||||
|
||||
// code from requestHandler.cleanUrl
|
||||
string root = Core.IO.SystemDirectories.Root.ToLower();
|
||||
var root = Core.IO.SystemDirectories.Root.ToLower();
|
||||
if (!string.IsNullOrEmpty(root) && tmp.StartsWith(root))
|
||||
tmp = tmp.Substring(root.Length);
|
||||
tmp = tmp.TrimEnd('/');
|
||||
@@ -55,7 +58,7 @@ namespace Umbraco.Web.Routing
|
||||
// code from UmbracoDefault.Page_PreInit
|
||||
if (tmp != "" && httpContext.Request["umbPageID"] == null)
|
||||
{
|
||||
string tryIntParse = tmp.Replace("/", "").Replace(".aspx", string.Empty);
|
||||
var tryIntParse = tmp.Replace("/", "").Replace(".aspx", string.Empty);
|
||||
int result;
|
||||
if (int.TryParse(tryIntParse, out result))
|
||||
tmp = tmp.Replace(".aspx", string.Empty);
|
||||
@@ -77,7 +80,8 @@ namespace Umbraco.Web.Routing
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static IEnumerable<Type> _customHandlerTypes;
|
||||
private static IEnumerable<Type> _customHandlerTypes;
|
||||
private static Type _customLastChanceHandlerType;
|
||||
|
||||
static void InitializeNotFoundHandlers()
|
||||
{
|
||||
@@ -87,6 +91,8 @@ namespace Umbraco.Web.Routing
|
||||
LogHelper.Debug<NotFoundHandlerHelper>("Registering custom handlers.");
|
||||
|
||||
var customHandlerTypes = new List<Type>();
|
||||
Type customLastChanceHandlerType = null;
|
||||
var hasLast = false;
|
||||
|
||||
var customHandlers = new XmlDocument();
|
||||
customHandlers.Load(Core.IO.IOHelper.MapPath(Core.IO.SystemFiles.NotFoundhandlersConfig));
|
||||
@@ -96,12 +102,23 @@ namespace Umbraco.Web.Routing
|
||||
var assemblyName = n.Attributes.GetNamedItem("assembly").Value;
|
||||
var typeName = n.Attributes.GetNamedItem("type").Value;
|
||||
|
||||
string ns = assemblyName;
|
||||
var ns = assemblyName;
|
||||
var nsAttr = n.Attributes.GetNamedItem("namespace");
|
||||
if (nsAttr != null && !string.IsNullOrWhiteSpace(nsAttr.Value))
|
||||
if (nsAttr != null && string.IsNullOrWhiteSpace(nsAttr.Value) == false)
|
||||
ns = nsAttr.Value;
|
||||
|
||||
LogHelper.Debug<NotFoundHandlerHelper>("Registering '{0}.{1},{2}'.", () => ns, () => typeName, () => assemblyName);
|
||||
var lcAttr = n.Attributes.GetNamedItem("last");
|
||||
var last = lcAttr != null && lcAttr.Value != null && lcAttr.Value.InvariantEquals("true");
|
||||
|
||||
if (last) // there can only be one last chance handler in the config file
|
||||
{
|
||||
if (hasLast)
|
||||
throw new Exception();
|
||||
hasLast = true;
|
||||
}
|
||||
|
||||
LogHelper.Debug<NotFoundHandlerHelper>("Registering '{0}.{1},{2}'{3}", () => ns, () => typeName, () => assemblyName,
|
||||
() => last ? " (last)." : ".");
|
||||
|
||||
Type type = null;
|
||||
try
|
||||
@@ -114,19 +131,79 @@ namespace Umbraco.Web.Routing
|
||||
LogHelper.Error<NotFoundHandlerHelper>("Error registering handler, ignoring.", e);
|
||||
}
|
||||
|
||||
if (type != null)
|
||||
if (type == null) continue;
|
||||
|
||||
if (last)
|
||||
_customLastChanceHandlerType = type;
|
||||
else
|
||||
customHandlerTypes.Add(type);
|
||||
}
|
||||
|
||||
_customHandlerTypes = customHandlerTypes;
|
||||
_customHandlerTypes = customHandlerTypes.ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> CustomHandlerTypes
|
||||
public static IEnumerable<INotFoundHandler> GetNotFoundHandlers()
|
||||
{
|
||||
get
|
||||
// instanciate new handlers
|
||||
// using definition cache
|
||||
|
||||
var handlers = new List<INotFoundHandler>();
|
||||
|
||||
foreach (var type in _customHandlerTypes)
|
||||
{
|
||||
return _customHandlerTypes;
|
||||
try
|
||||
{
|
||||
var handler = Activator.CreateInstance(type) as INotFoundHandler;
|
||||
if (handler != null)
|
||||
handlers.Add(handler);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error<ContentFinderByNotFoundHandlers>(string.Format("Error instanciating handler {0}, ignoring.", type.FullName), e);
|
||||
}
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static bool IsNotFoundHandlerEnabled<T>()
|
||||
{
|
||||
return _customHandlerTypes.Contains(typeof (T));
|
||||
}
|
||||
|
||||
public static INotFoundHandler GetNotFoundLastChanceHandler()
|
||||
{
|
||||
if (_customLastChanceHandlerType == null) return null;
|
||||
|
||||
try
|
||||
{
|
||||
var handler = Activator.CreateInstance(_customLastChanceHandlerType) as INotFoundHandler;
|
||||
if (handler != null)
|
||||
return handler;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error<ContentFinderByNotFoundHandlers>(string.Format("Error instanciating handler {0}, ignoring.", _customLastChanceHandlerType.FullName), e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IContentFinder SubsituteFinder(INotFoundHandler handler)
|
||||
{
|
||||
IContentFinder finder = null;
|
||||
|
||||
if (handler is global::umbraco.SearchForAlias)
|
||||
finder = new ContentFinderByUrlAlias();
|
||||
else if (handler is global::umbraco.SearchForProfile)
|
||||
finder = new ContentFinderByProfile();
|
||||
else if (handler is global::umbraco.SearchForTemplate)
|
||||
finder = new ContentFinderByNiceUrlAndTemplate();
|
||||
else if (handler is global::umbraco.handle404)
|
||||
finder = new ContentFinderByLegacy404();
|
||||
|
||||
return finder;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,11 +291,14 @@
|
||||
<Compile Include="Cache\UserPermissionsCacheRefresher.cs" />
|
||||
<Compile Include="Cache\UserTypeCacheRefresher.cs" />
|
||||
<Compile Include="Configuration\WebRouting.cs" />
|
||||
<Compile Include="Controllers\ProfileController.cs" />
|
||||
<Compile Include="Controllers\LoginStatusController.cs" />
|
||||
<Compile Include="Editors\MediaController.cs" />
|
||||
<Compile Include="Models\ContentEditing\ContentSortOrder.cs" />
|
||||
<Compile Include="Controllers\RegisterController.cs" />
|
||||
<Compile Include="Models\ProfileModel.cs" />
|
||||
<Compile Include="Models\LoginStatusModel.cs" />
|
||||
<Compile Include="Routing\ContentLastChanceFinderByNotFoundHandlers.cs" />
|
||||
<Compile Include="Models\RegisterModel.cs" />
|
||||
<Compile Include="Models\LoginModel.cs" />
|
||||
<Compile Include="Security\Providers\MembersMembershipProvider.cs" />
|
||||
@@ -398,6 +401,7 @@
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controllers\LoginController.cs" />
|
||||
<Compile Include="UmbracoProperty.cs" />
|
||||
<Compile Include="UrlHelperExtensions.cs" />
|
||||
<Compile Include="WebApi\MemberAuthorizeAttribute.cs" />
|
||||
<Compile Include="WebApi\UmbracoApiController.cs" />
|
||||
|
||||
@@ -370,8 +370,14 @@ namespace Umbraco.Web
|
||||
_umbracoContext = null;
|
||||
//ensure not to dispose this!
|
||||
Application = null;
|
||||
ContentCache = null;
|
||||
MediaCache = null;
|
||||
|
||||
//Before we set these to null but in fact these are application lifespan singletons so
|
||||
//there's no reason we need to set them to null and this also caused a problem with packages
|
||||
//trying to access the cache properties on RequestEnd.
|
||||
//http://issues.umbraco.org/issue/U4-2734
|
||||
//http://our.umbraco.org/projects/developer-tools/301-url-tracker/version-2/44327-Issues-with-URL-Tracker-in-614
|
||||
//ContentCache = null;
|
||||
//MediaCache = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
public class UmbracoProperty
|
||||
{
|
||||
public string Alias { get; set; }
|
||||
public string Value { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -302,23 +302,31 @@ namespace Umbraco.Web
|
||||
typeof(DefaultUrlProvider)
|
||||
);
|
||||
|
||||
// the legacy 404 will run from within ContentFinderByNotFoundHandlers below
|
||||
// so for the time being there is no last chance finder
|
||||
ContentLastChanceFinderResolver.Current = new ContentLastChanceFinderResolver();
|
||||
ContentLastChanceFinderResolver.Current = new ContentLastChanceFinderResolver(
|
||||
// handled by ContentLastChanceFinderByNotFoundHandlers for the time being
|
||||
// soon as we get rid of INotFoundHandler support, we must enable this
|
||||
//new ContentFinderByLegacy404()
|
||||
|
||||
// implement INotFoundHandler support... remove once we get rid of it
|
||||
new ContentLastChanceFinderByNotFoundHandlers());
|
||||
|
||||
ContentFinderResolver.Current = new ContentFinderResolver(
|
||||
// add all known resolvers in the correct order, devs can then modify this list
|
||||
// on application startup either by binding to events or in their own global.asax
|
||||
typeof (ContentFinderByPageIdQuery),
|
||||
typeof (ContentFinderByNiceUrl),
|
||||
typeof (ContentFinderByIdPath),
|
||||
// these will be handled by ContentFinderByNotFoundHandlers
|
||||
// so they can be enabled/disabled even though resolvers are not public yet
|
||||
//typeof (ContentFinderByNiceUrlAndTemplate),
|
||||
//typeof (ContentFinderByProfile),
|
||||
//typeof (ContentFinderByUrlAlias),
|
||||
typeof (ContentFinderByNotFoundHandlers)
|
||||
);
|
||||
// all built-in finders in the correct order, devs can then modify this list
|
||||
// on application startup via an application event handler.
|
||||
typeof (ContentFinderByPageIdQuery),
|
||||
typeof (ContentFinderByNiceUrl),
|
||||
typeof (ContentFinderByIdPath),
|
||||
|
||||
// these will be handled by ContentFinderByNotFoundHandlers so they can be enabled/disabled
|
||||
// via the config file... soon as we get rid of INotFoundHandler support, we must enable
|
||||
// them here.
|
||||
//typeof (ContentFinderByNiceUrlAndTemplate),
|
||||
//typeof (ContentFinderByProfile),
|
||||
//typeof (ContentFinderByUrlAlias),
|
||||
|
||||
// implement INotFoundHandler support... remove once we get rid of it
|
||||
typeof (ContentFinderByNotFoundHandlers)
|
||||
);
|
||||
|
||||
SiteDomainHelperResolver.Current = new SiteDomainHelperResolver(new SiteDomainHelper());
|
||||
|
||||
|
||||
@@ -8,14 +8,14 @@ namespace umbraco.editorControls.imagecropper
|
||||
|
||||
public override XmlNode ToXMl(XmlDocument data)
|
||||
{
|
||||
if (Value.ToString() != "") {
|
||||
XmlDocument xd = new XmlDocument();
|
||||
if (Value != null && Value.ToString() != "")
|
||||
{
|
||||
var xd = new XmlDocument();
|
||||
xd.LoadXml(Value.ToString());
|
||||
return data.ImportNode(xd.DocumentElement, true);
|
||||
} else {
|
||||
return base.ToXMl(data);
|
||||
}
|
||||
|
||||
return base.ToXMl(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user