diff --git a/src/Umbraco.Core/Cache/DictionaryCacheProvider.cs b/src/Umbraco.Core/Cache/DictionaryCacheProvider.cs
index 22f9209acc..98dceb80b0 100644
--- a/src/Umbraco.Core/Cache/DictionaryCacheProvider.cs
+++ b/src/Umbraco.Core/Cache/DictionaryCacheProvider.cs
@@ -140,7 +140,8 @@ namespace Umbraco.Core.Cache
// in order NOT to cache exceptions
_items.TryRemove(cacheKey, out result);
- throw eh.Exception; // throw once!
+ eh.Exception.Throw(); // throw once!
+ return null; // never reached
}
}
}
diff --git a/src/Umbraco.Core/Cache/DictionaryCacheProviderBase.cs b/src/Umbraco.Core/Cache/DictionaryCacheProviderBase.cs
index cc62fbac8d..6baa2cf0ed 100644
--- a/src/Umbraco.Core/Cache/DictionaryCacheProviderBase.cs
+++ b/src/Umbraco.Core/Cache/DictionaryCacheProviderBase.cs
@@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
+using System.Runtime.ExceptionServices;
using System.Text.RegularExpressions;
using Umbraco.Core.Composing;
@@ -45,7 +46,7 @@ namespace Umbraco.Core.Cache
}
catch (Exception e)
{
- return new ExceptionHolder(e);
+ return new ExceptionHolder(ExceptionDispatchInfo.Capture(e));
}
});
}
@@ -75,12 +76,12 @@ namespace Umbraco.Core.Cache
internal class ExceptionHolder
{
- public ExceptionHolder(Exception e)
+ public ExceptionHolder(ExceptionDispatchInfo e)
{
Exception = e;
}
- public Exception Exception { get; private set; }
+ public ExceptionDispatchInfo Exception { get; }
}
#region Clear
diff --git a/src/Umbraco.Core/Cache/HttpRequestCacheProvider.cs b/src/Umbraco.Core/Cache/HttpRequestCacheProvider.cs
index 5f5a599135..4a43dd154f 100644
--- a/src/Umbraco.Core/Cache/HttpRequestCacheProvider.cs
+++ b/src/Umbraco.Core/Cache/HttpRequestCacheProvider.cs
@@ -136,8 +136,7 @@ namespace Umbraco.Core.Cache
//return result.Value;
var value = result.Value; // will not throw (safe lazy)
- var eh = value as ExceptionHolder;
- if (eh != null) throw eh.Exception; // throw once!
+ if (value is ExceptionHolder eh) eh.Exception.Throw(); // throw once!
return value;
}
diff --git a/src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs
index 6368eef78c..ad46201c0c 100644
--- a/src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs
+++ b/src/Umbraco.Core/Cache/HttpRuntimeCacheProvider.cs
@@ -153,8 +153,7 @@ namespace Umbraco.Core.Cache
//return result.Value;
value = result.Value; // will not throw (safe lazy)
- var eh = value as ExceptionHolder;
- if (eh != null) throw new Exception("Exception while creating a value.", eh.Exception); // throw once!
+ if (value is ExceptionHolder eh) eh.Exception.Throw(); // throw once!
return value;
}
diff --git a/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs
index 76a3d1c558..70e37addb8 100644
--- a/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs
+++ b/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs
@@ -225,8 +225,7 @@ namespace Umbraco.Core.Cache
//return result.Value;
var value = result.Value; // will not throw (safe lazy)
- var eh = value as DictionaryCacheProviderBase.ExceptionHolder;
- if (eh != null) throw eh.Exception; // throw once!
+ if (value is DictionaryCacheProviderBase.ExceptionHolder eh) eh.Exception.Throw(); // throw once!
return value;
}
diff --git a/src/Umbraco.Core/Composing/LightInjectExtensions.cs b/src/Umbraco.Core/Composing/LightInjectExtensions.cs
index 952dcd5f48..74a2c331e9 100644
--- a/src/Umbraco.Core/Composing/LightInjectExtensions.cs
+++ b/src/Umbraco.Core/Composing/LightInjectExtensions.cs
@@ -307,6 +307,10 @@ namespace Umbraco.Core.Composing
if (factory == null)
throw new ArgumentNullException(nameof(factory));
+ // fixme temp - STOP doing this, it confuses LightInject and then we get ugly exception traces
+ // we HAVE to let LightInject throw - and catch at THE OUTERMOST if InvalidOperationException in LightInject.Anything!
+
+ return factory.GetInstance(tService, serviceName, args);
try
{
return factory.GetInstance(tService, serviceName, args);
diff --git a/src/Umbraco.Core/Constants-Conventions.cs b/src/Umbraco.Core/Constants-Conventions.cs
index 1cc9b40454..8ca4daddb3 100644
--- a/src/Umbraco.Core/Constants-Conventions.cs
+++ b/src/Umbraco.Core/Constants-Conventions.cs
@@ -274,14 +274,14 @@ namespace Umbraco.Core
},
{
PasswordAnswer,
- new PropertyType(PropertyEditors.Aliases.NoEdit, ValueStorageType.NVarChar, true, PasswordAnswer)
+ new PropertyType(PropertyEditors.Aliases.NoEdit, ValueStorageType.Nvarchar, true, PasswordAnswer)
{
Name = PasswordAnswerLabel
}
},
{
PasswordQuestion,
- new PropertyType(PropertyEditors.Aliases.NoEdit, ValueStorageType.NVarChar, true, PasswordQuestion)
+ new PropertyType(PropertyEditors.Aliases.NoEdit, ValueStorageType.Nvarchar, true, PasswordQuestion)
{
Name = PasswordQuestionLabel
}
diff --git a/src/Umbraco.Core/Deploy/IPreValueConnector.cs b/src/Umbraco.Core/Deploy/IPreValueConnector.cs
index 3f97b324fc..15f9a9e619 100644
--- a/src/Umbraco.Core/Deploy/IPreValueConnector.cs
+++ b/src/Umbraco.Core/Deploy/IPreValueConnector.cs
@@ -7,7 +7,7 @@ namespace Umbraco.Core.Deploy
///
/// PreValues may contain values such as content identifiers, that would be local
/// to one environment, and need to be converted in order to be deployed.
- public interface IPreValueConnector
+ public interface IPreValueConnector // fixme this needs to change really
{
///
/// Gets the property editor aliases that the value converter supports by default.
diff --git a/src/Umbraco.Core/Enum.cs b/src/Umbraco.Core/Enum.cs
index d7a9e60818..5bc70c637d 100644
--- a/src/Umbraco.Core/Enum.cs
+++ b/src/Umbraco.Core/Enum.cs
@@ -1,105 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
namespace Umbraco.Core
{
///
- /// A very useful class for parsing, enumerating and querying Enum objects
+ /// Provides utility methods for handling enumerations.
///
- ///
///
/// Taken from http://damieng.com/blog/2010/10/17/enums-better-syntax-improved-performance-and-tryparse-in-net-3-5
///
- public static class Enum where T : struct
+ public static class Enum
+ where T : struct
{
- private static readonly IEnumerable All = Enum.GetValues(typeof(T)).Cast();
- private static readonly Dictionary InsensitiveNames = All.ToDictionary(k => Enum.GetName(typeof(T), k).ToLowerInvariant());
- private static readonly Dictionary SensitiveNames = All.ToDictionary(k => Enum.GetName(typeof(T), k));
- private static readonly Dictionary Values = All.ToDictionary(k => Convert.ToInt32(k));
- private static readonly Dictionary Names = All.ToDictionary(k => k, v => v.ToString());
+ private static readonly List Values;
+ private static readonly Dictionary InsensitiveNameToValue;
+ private static readonly Dictionary SensitiveNameToValue;
+ private static readonly Dictionary IntToValue;
+ private static readonly Dictionary ValueToName;
+
+ static Enum()
+ {
+ Values = Enum.GetValues(typeof(T)).Cast().ToList();
+
+ IntToValue = new Dictionary();
+ ValueToName = new Dictionary();
+ SensitiveNameToValue = new Dictionary();
+ InsensitiveNameToValue = new Dictionary();
+
+ foreach (var value in Values)
+ {
+ var name = value.ToString();
+
+ IntToValue[Convert.ToInt32(value)] = value;
+ ValueToName[value] = name;
+ SensitiveNameToValue[name] = value;
+ InsensitiveNameToValue[name.ToLowerInvariant()] = value;
+ }
+ }
public static bool IsDefined(T value)
{
- return Names.Keys.Contains(value);
+ return ValueToName.Keys.Contains(value);
}
public static bool IsDefined(string value)
{
- return SensitiveNames.Keys.Contains(value);
+ return SensitiveNameToValue.Keys.Contains(value);
}
public static bool IsDefined(int value)
{
- return Values.Keys.Contains(value);
+ return IntToValue.Keys.Contains(value);
}
public static IEnumerable GetValues()
{
- return All;
+ return Values;
}
public static string[] GetNames()
{
- return Names.Values.ToArray();
+ return ValueToName.Values.ToArray();
}
public static string GetName(T value)
{
- string name;
- Names.TryGetValue(value, out name);
- return name;
+ return ValueToName.TryGetValue(value, out var name) ? name : null;
}
- public static T Parse(string value)
+ public static T Parse(string value, bool ignoreCase = false)
{
- T parsed = default(T);
- if (!SensitiveNames.TryGetValue(value, out parsed))
- throw new ArgumentException("Value is not one of the named constants defined for the enumeration", "value");
- return parsed;
+ var names = ignoreCase ? InsensitiveNameToValue : SensitiveNameToValue;
+ if (ignoreCase) value = value.ToLowerInvariant();
+
+ if (names.TryGetValue(value, out var parsed))
+ return parsed;
+
+ throw new ArgumentException($"Value \"{value}\"is not a valid {typeof(T).Name} enumeration value.", nameof(value));
}
- public static T Parse(string value, bool ignoreCase)
+ public static bool TryParse(string value, out T returnValue, bool ignoreCase = false)
{
- if (!ignoreCase)
- return Parse(value);
-
- T parsed = default(T);
- if (!InsensitiveNames.TryGetValue(value.ToLowerInvariant(), out parsed))
- throw new ArgumentException("Value is not one of the named constants defined for the enumeration", "value");
- return parsed;
- }
-
- public static bool TryParse(string value, out T returnValue)
- {
- return SensitiveNames.TryGetValue(value, out returnValue);
- }
-
- public static bool TryParse(string value, bool ignoreCase, out T returnValue)
- {
- if (!ignoreCase)
- return TryParse(value, out returnValue);
-
- return InsensitiveNames.TryGetValue(value.ToLowerInvariant(), out returnValue);
+ var names = ignoreCase ? InsensitiveNameToValue : SensitiveNameToValue;
+ if (ignoreCase) value = value.ToLowerInvariant();
+ return names.TryGetValue(value, out returnValue);
}
public static T? ParseOrNull(string value)
{
- if (String.IsNullOrEmpty(value))
+ if (string.IsNullOrWhiteSpace(value))
return null;
- T foundValue;
- if (InsensitiveNames.TryGetValue(value.ToLowerInvariant(), out foundValue))
- return foundValue;
+ if (InsensitiveNameToValue.TryGetValue(value.ToLowerInvariant(), out var parsed))
+ return parsed;
return null;
}
public static T? CastOrNull(int value)
{
- T foundValue;
- if (Values.TryGetValue(value, out foundValue))
+ if (IntToValue.TryGetValue(value, out var foundValue))
return foundValue;
return null;
diff --git a/src/Umbraco.Core/Manifest/ManifestParser.cs b/src/Umbraco.Core/Manifest/ManifestParser.cs
index 5b7cd67914..2fd3a5f6ad 100644
--- a/src/Umbraco.Core/Manifest/ManifestParser.cs
+++ b/src/Umbraco.Core/Manifest/ManifestParser.cs
@@ -17,32 +17,39 @@ namespace Umbraco.Core.Manifest
///
public class ManifestParser
{
+ private static readonly string Utf8Preamble = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
+
private readonly IRuntimeCacheProvider _cache;
- private readonly string _path;
private readonly ILogger _logger;
private readonly ManifestValidatorCollection _validators;
- private static readonly string Utf8Preamble = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
+ private string _path;
///
/// Initializes a new instance of the class.
///
- public ManifestParser(IRuntimeCacheProvider cache, ManifestValidatorCollection validators, ILogger logger) // fixme is LightInject going to pick that one?
+ public ManifestParser(IRuntimeCacheProvider cache, ManifestValidatorCollection validators, ILogger logger)
: this(cache, validators, "~/App_Plugins", logger)
{ }
///
/// Initializes a new instance of the class.
///
- public ManifestParser(IRuntimeCacheProvider cache, ManifestValidatorCollection validators, string path, ILogger logger)
+ private ManifestParser(IRuntimeCacheProvider cache, ManifestValidatorCollection validators, string path, ILogger logger)
{
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
_validators = validators ?? throw new ArgumentNullException(nameof(validators));
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullOrEmptyException(nameof(path));
- _path = path.StartsWith("~/") ? IOHelper.MapPath(path) : path;
+ Path = path;
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
+ public string Path
+ {
+ get => _path;
+ set => _path = value.StartsWith("~/") ? IOHelper.MapPath(value) : value;
+ }
+
///
/// Gets all manifests, merged into a single manifest object.
///
diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs
index 52c1c9d06e..659f3818ce 100644
--- a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs
+++ b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs
@@ -38,7 +38,7 @@ namespace Umbraco.Core.Migrations.Install
{5, typeof (DocumentDto)},
{6, typeof (ContentTypeTemplateDto)},
{7, typeof (DataTypeDto)},
- {8, typeof (DataTypePreValueDto)},
+ //removed: {8, typeof (DataTypePreValueDto)},
{9, typeof (DictionaryDto)},
{10, typeof (LanguageDto)},
diff --git a/src/Umbraco.Core/Migrations/MigrationBase_Extra.cs b/src/Umbraco.Core/Migrations/MigrationBase_Extra.cs
index 9e0ca99b5c..821e6da5a4 100644
--- a/src/Umbraco.Core/Migrations/MigrationBase_Extra.cs
+++ b/src/Umbraco.Core/Migrations/MigrationBase_Extra.cs
@@ -13,8 +13,13 @@ namespace Umbraco.Core.Migrations
protected void AddColumn(string tableName, string columnName)
{
- AddColumn(tableName, columnName, out var sqls);
- foreach (var sql in sqls) Database.Execute(sql);
+ //if (ColumnExists(tableName, columnName))
+ // throw new InvalidOperationException($"Column {tableName}.{columnName} already exists.");
+
+ var table = DefinitionFactory.GetTableDefinition(typeof(T), SqlSyntax);
+ var column = table.Columns.First(x => x.Name == columnName);
+ var createSql = SqlSyntax.Format(column);
+ Database.Execute(string.Format(SqlSyntax.AddColumn, SqlSyntax.GetQuotedTableName(tableName), createSql));
}
protected void AddColumn(string tableName, string columnName, out IEnumerable sqls)
diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs
index 8fdd00a203..d20ced57cd 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs
@@ -83,7 +83,7 @@ namespace Umbraco.Core.Migrations.Upgrade
.Chain("{CBFF58A2-7B50-4F75-8E98-249920DB0F37}")
.Chain("{3D18920C-E84D-405C-A06A-B7CEE52FE5DD}")
.Chain("{FB0A5429-587E-4BD0-8A67-20F0E7E62FF7}")
- .Chain("{E3388F73-89FA-45FE-A539-C7FACC8D63DD}")
+ .Chain("{F0C42457-6A3B-4912-A7EA-F27ED85A2092}")
.Chain("{82C4BA1D-7720-46B1-BBD7-07F3F73800E6}");
// 7.8.1 = same as 7.8.0
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RefactorDataType.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RefactorDataType.cs
index aaa4929ec6..b93b68b27d 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RefactorDataType.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RefactorDataType.cs
@@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using NPoco;
+using Umbraco.Core.Migrations.Install;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Dtos;
@@ -19,22 +20,27 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
- // drop all keys and indexes
- Delete.KeysAndIndexes("cmsDataType").Do();
+ // delete *all* keys and indexes - because of FKs
+ Delete.KeysAndIndexes().Do();
// drop and create columns
Delete.Column("pk").FromTable("cmsDataType").Do();
- AddColumn("cmsDataType", "config");
// rename the table
- Rename.Table("cmsDataType").To(Constants.DatabaseSchema.Tables.Document).Do();
+ Rename.Table("cmsDataType").To(Constants.DatabaseSchema.Tables.DataType).Do();
- // recreate all keys and indexes
- Create.KeysAndIndexes().Do();
+ // create column
+ // fixme it is annoying that these are NOT written out to the log?!
+ AddColumn(Constants.DatabaseSchema.Tables.DataType, "config");
+ Database.Execute(Sql().Update(u => u.Set(x => x.Configuration, string.Empty)));
+
+ // re-create *all* keys and indexes
+ foreach (var x in DatabaseSchemaCreator.OrderedTables)
+ Create.KeysAndIndexes(x.Value).Do();
var sql = Sql()
.Select()
- .AndSelect()
+ .AndSelect(x => x.Alias, x => x.SortOrder, x => x.Value)
.From()
.InnerJoin().On((left, right) => left.NodeId == right.NodeId)
.OrderBy(x => x.NodeId)
@@ -71,7 +77,8 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
}
// drop preValues table
- Delete.Table("cmsDataTypePreValues");
+ // FIXME keep it around for now
+ //Delete.Table("cmsDataTypePreValues");
}
[TableName("cmsDataTypePreValues")]
diff --git a/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs b/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs
index 6a71ff0979..ef55f0d469 100644
--- a/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs
+++ b/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs
@@ -11,9 +11,9 @@ namespace Umbraco.Core.Models
{
var type = contentType.GetType();
var itemType = PublishedItemType.Unknown;
- if (type == typeof(IContentType)) itemType = PublishedItemType.Content;
- else if (type == typeof(IMediaType)) itemType = PublishedItemType.Media;
- else if (type == typeof(IMemberType)) itemType = PublishedItemType.Member;
+ if (typeof(IContentType).IsAssignableFrom(type)) itemType = PublishedItemType.Content;
+ else if (typeof(IMediaType).IsAssignableFrom(type)) itemType = PublishedItemType.Media;
+ else if (typeof(IMemberType).IsAssignableFrom(type)) itemType = PublishedItemType.Member;
return itemType;
}
}
diff --git a/src/Umbraco.Core/Models/PreValue.cs b/src/Umbraco.Core/Models/PreValue.cs
deleted file mode 100644
index 05572ee4d7..0000000000
--- a/src/Umbraco.Core/Models/PreValue.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-namespace Umbraco.Core.Models
-{
- ///
- /// Represents a stored pre-value field value
- ///
- public class PreValue : IDeepCloneable
- {
- public PreValue(int id, string value, int sortOrder)
- {
- Id = id;
- Value = value;
- SortOrder = sortOrder;
- }
-
- public PreValue(int id, string value)
- {
- Id = id;
- Value = value;
- }
-
- public PreValue(string value)
- {
- Value = value;
- }
-
- ///
- /// The value stored for the pre-value field
- ///
- public string Value { get; set; }
-
- ///
- /// The database id for the pre-value field value
- ///
- public int Id { get; private set; }
-
- ///
- /// The sort order stored for the pre-value field value
- ///
- public int SortOrder { get; private set; }
-
- public virtual object DeepClone()
- {
- //Memberwise clone on PreValue will work since it doesn't have any deep elements
- var clone = (PreValue)MemberwiseClone();
- return clone;
- }
- }
-}
diff --git a/src/Umbraco.Core/Models/PreValueCollection.cs b/src/Umbraco.Core/Models/PreValueCollection.cs
deleted file mode 100644
index f505892dca..0000000000
--- a/src/Umbraco.Core/Models/PreValueCollection.cs
+++ /dev/null
@@ -1,90 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Umbraco.Core.Models
-{
- ///
- /// Represents the preValues for a data type.
- ///
- ///
- /// Due to the legacy nature of the data that can be stored for pre-values, we have this class which encapsulates the 2 different
- /// ways that pre-values are stored: A string array or a Dictionary.
- ///
- /// Most legacy property editors won't support the dictionary format but new property editors should always use the dictionary format.
- /// In order to get overrideable pre-values working we need a dictionary since we'll have to reference a pre-value by a key.
- ///
- public class PreValueCollection : IDeepCloneable
- {
- private IDictionary _preValuesAsDictionary;
- private PreValue[] _preValuesAsArray;
-
- ///
- /// Gets the collection as an array.
- ///
- public IEnumerable PreValuesAsArray
- {
- get => _preValuesAsArray
- ?? throw new InvalidOperationException("The current preValue collection is dictionary based, use the PreValuesAsDictionary property instead.");
- set => _preValuesAsArray = value.ToArray();
- }
-
- ///
- /// Gets the collection as a dictionary.
- ///
- public IDictionary PreValuesAsDictionary
- {
- get => _preValuesAsDictionary
- ?? throw new InvalidOperationException("The current preValue collection is array based, use the PreValuesAsArray property instead.");
- set => _preValuesAsDictionary = value;
- }
-
- ///
- /// Gets a value indicating whether the collection is dictionary-based.
- ///
- public bool IsDictionaryBased => _preValuesAsDictionary != null;
-
- ///
- /// Initializes a new array-based instance of the class.
- ///
- public PreValueCollection(IEnumerable preVals)
- {
- _preValuesAsArray = preVals.ToArray();
- }
-
- ///
- /// Initializes a new dictionary-based instance of the class.
- ///
- public PreValueCollection(IDictionary preVals)
- {
- _preValuesAsDictionary = preVals;
- }
-
- ///
- /// Gets the collection as a dictionary, even if it is array-based.
- ///
- public IDictionary FormatAsDictionary()
- {
- if (IsDictionaryBased)
- return PreValuesAsDictionary;
-
- var dictionary = new Dictionary();
- for (var i = 0; i < _preValuesAsArray.Length; i++)
- dictionary[i.ToInvariantString()] = _preValuesAsArray[i];
- return dictionary;
- }
-
- public object DeepClone()
- {
- var clone = (PreValueCollection) MemberwiseClone();
-
- if (_preValuesAsArray != null)
- clone._preValuesAsArray = _preValuesAsArray.Select(x => (PreValue) x.DeepClone()).ToArray();
-
- if (_preValuesAsDictionary != null)
- clone._preValuesAsDictionary = _preValuesAsDictionary.ToDictionary(x => x.Key, x => (PreValue) x.Value.DeepClone());
-
- return clone;
- }
- }
-}
diff --git a/src/Umbraco.Core/Models/Property.cs b/src/Umbraco.Core/Models/Property.cs
index 2f07167af2..54ac950bfc 100644
--- a/src/Umbraco.Core/Models/Property.cs
+++ b/src/Umbraco.Core/Models/Property.cs
@@ -353,7 +353,7 @@ namespace Umbraco.Core.Models
switch (PropertyType.ValueStorageType)
{
- case ValueStorageType.NVarChar:
+ case ValueStorageType.Nvarchar:
case ValueStorageType.Ntext:
return s;
diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs
index b6537e25ba..900bad834e 100644
--- a/src/Umbraco.Core/Models/PropertyType.cs
+++ b/src/Umbraco.Core/Models/PropertyType.cs
@@ -322,7 +322,7 @@ namespace Umbraco.Core.Models
return valueType == typeof(decimal);
case ValueStorageType.Date:
return valueType == typeof(DateTime);
- case ValueStorageType.NVarChar:
+ case ValueStorageType.Nvarchar:
return valueType == typeof(string);
case ValueStorageType.Ntext:
return valueType == typeof(string);
diff --git a/src/Umbraco.Core/Models/ValueStorageType.cs b/src/Umbraco.Core/Models/ValueStorageType.cs
index 77b1f7108e..abbae60dc7 100644
--- a/src/Umbraco.Core/Models/ValueStorageType.cs
+++ b/src/Umbraco.Core/Models/ValueStorageType.cs
@@ -10,6 +10,10 @@ namespace Umbraco.Core.Models
[DataContract]
public enum ValueStorageType
{
+ // note: these values are written out in the database in some places,
+ // and then parsed back in a case-sensitive way - think about it before
+ // changing the casing of values.
+
///
/// Store property value as NText.
///
@@ -20,7 +24,7 @@ namespace Umbraco.Core.Models
/// Store property value as NVarChar.
///
[EnumMember]
- NVarChar,
+ Nvarchar,
///
/// Store property value as Integer.
diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs
index e6ae1092f1..c814461f36 100644
--- a/src/Umbraco.Core/ObjectExtensions.cs
+++ b/src/Umbraco.Core/ObjectExtensions.cs
@@ -7,6 +7,8 @@ using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Xml;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
using Umbraco.Core.Composing;
namespace Umbraco.Core
@@ -501,26 +503,37 @@ namespace Umbraco.Core
return new Dictionary();
}
- private static readonly ConcurrentDictionary>> ToObjectTypes
- = new ConcurrentDictionary>>();
+ private static readonly ConcurrentDictionary> ToObjectTypes
+ = new ConcurrentDictionary>();
///
/// Converts an object's properties into a dictionary.
///
/// The object to convert.
/// A dictionary containing each properties.
- public static Dictionary ToObjectDictionary(object obj)
+ public static Dictionary ToObjectDictionary(T obj)
{
+ // fixme refactor this!
+ var d = new Dictionary();
+ if (obj == null) return d;
+ foreach (var p in obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy))
+ {
+ var jsonProperty = p.GetCustomAttribute();
+ var name = jsonProperty != null ? jsonProperty.PropertyName : p.Name;
+ d[name] = p.GetValue(obj);
+ }
+ return d;
+
var t = obj.GetType();
if (!ToObjectTypes.TryGetValue(t, out var properties))
{
ToObjectTypes[t] = properties = t
.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy)
- .ToDictionary(x => x.Name, ReflectionUtilities.EmitPropertyGetter
internal class DataTypeRepository : NPocoRepositoryBase, IDataTypeRepository
{
- private readonly PropertyEditorCollection _editors;
+ private readonly Lazy _editors;
- public DataTypeRepository(IScopeAccessor scopeAccessor, CacheHelper cache, PropertyEditorCollection editors, ILogger logger)
+ // fixme temp fixing circular dependencies with LAZY but is this the right place?
+ public DataTypeRepository(IScopeAccessor scopeAccessor, CacheHelper cache, Lazy editors, ILogger logger)
: base(scopeAccessor, cache, logger)
{
_editors = editors;
@@ -53,7 +54,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
}
var dtos = Database.Fetch(dataTypeSql);
- return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors[x.EditorAlias])).ToArray();
+ return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors.Value[x.EditorAlias])).ToArray();
}
protected override IEnumerable PerformGetByQuery(IQuery query)
@@ -64,7 +65,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
var dtos = Database.Fetch(sql);
- return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors[x.EditorAlias])).ToArray();
+ return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors.Value[x.EditorAlias])).ToArray();
}
#endregion
@@ -112,10 +113,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
//TODO: should the below be removed?
//Cannot add a duplicate data type
- var exists = Database.ExecuteScalar(@"SELECT COUNT(*) FROM cmsDataType
-INNER JOIN umbracoNode ON cmsDataType.nodeId = umbracoNode.id
-WHERE umbracoNode." + SqlSyntax.GetQuotedColumnName("text") + "= @name", new { name = entity.Name });
- if (exists > 0)
+ var existsSql = Sql()
+ .SelectCount()
+ .From()
+ .InnerJoin().On((left, right) => left.NodeId == right.NodeId)
+ .Where(x => x.Text == entity.Name);
+ var exists = Database.ExecuteScalar(existsSql) > 0;
+ if (exists)
{
throw new DuplicateNameException("A data type with the name " + entity.Name + " already exists");
}
@@ -158,12 +162,13 @@ WHERE umbracoNode." + SqlSyntax.GetQuotedColumnName("text") + "= @name", new { n
entity.Name = EnsureUniqueNodeName(entity.Name, entity.Id);
//Cannot change to a duplicate alias
- var exists = Database.ExecuteScalar(@"SELECT COUNT(*) FROM cmsDataType
-INNER JOIN umbracoNode ON cmsDataType.nodeId = umbracoNode.id
-WHERE umbracoNode." + SqlSyntax.GetQuotedColumnName("text") + @"= @name
-AND umbracoNode.id <> @id",
- new { id = entity.Id, name = entity.Name });
- if (exists > 0)
+ var existsSql = Sql()
+ .SelectCount()
+ .From()
+ .InnerJoin().On((left, right) => left.NodeId == right.NodeId)
+ .Where(x => x.Text == entity.Name && x.NodeId != entity.Id);
+ var exists = Database.ExecuteScalar(existsSql) > 0;
+ if (exists)
{
throw new DuplicateNameException("A data type with the name " + entity.Name + " already exists");
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs
index 3c431567ee..6fef47679b 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs
@@ -148,7 +148,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
"cmsPropertyType.Name", "cmsPropertyType.Description", "cmsPropertyType.mandatory", "cmsPropertyType.UniqueID",
"cmsPropertyType.validationRegExp", "cmsPropertyType.dataTypeId", "cmsPropertyType.sortOrder AS PropertyTypeSortOrder",
"cmsPropertyType.propertyTypeGroupId AS PropertyTypesGroupId", "cmsMemberType.memberCanEdit", "cmsMemberType.viewOnProfile",
- "cmsDataType.propertyEditorAlias", "cmsDataType.dbType", "cmsPropertyTypeGroup.id AS PropertyTypeGroupId",
+ "uDataType.propertyEditorAlias", "uDataType.dbType", "cmsPropertyTypeGroup.id AS PropertyTypeGroupId",
"cmsPropertyTypeGroup.text AS PropertyGroupName", "cmsPropertyTypeGroup.uniqueID AS PropertyGroupUniqueID",
"cmsPropertyTypeGroup.sortorder AS PropertyGroupSortOrder", "cmsPropertyTypeGroup.contenttypeNodeId")
.From()
diff --git a/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs
index e3fd496775..339cbdaf06 100644
--- a/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs
@@ -45,7 +45,7 @@ namespace Umbraco.Core.PropertyEditors
/// Parses the configuration.
///
/// Used to create the actual configuration dictionary from the database value.
- public object ParseConfiguration(string configurationJson)
+ public virtual object ParseConfiguration(string configurationJson)
=> JsonConvert.DeserializeObject>(configurationJson);
public static TConfiguration ConfigurationAs(object obj)
@@ -83,8 +83,15 @@ namespace Umbraco.Core.PropertyEditors
// configuration with their current configuration
// make sure we have dictionaries
+ if (defaultConfiguration == null)
+ defaultConfiguration = new Dictionary();
+
if (!(defaultConfiguration is IDictionary d))
throw new ArgumentException($"Expecting a {typeof(Dictionary).Name} instance but got {defaultConfiguration.GetType().Name}.", nameof(defaultConfiguration));
+
+ if (configuration == null)
+ configuration = new Dictionary();
+
if (!(configuration is IDictionary c))
throw new ArgumentException($"Expecting a {typeof(Dictionary).Name} instance but got {configuration.GetType().Name}.", nameof(configuration));
diff --git a/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
index 8ff4944893..6a5bfd4040 100644
--- a/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
+++ b/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
@@ -91,13 +91,17 @@ namespace Umbraco.Core.PropertyEditors
return fields;
}
- ///
- /// Parses the configuration.
- ///
- /// Used to create the actual configuration object from the database value.
- public new virtual TConfiguration ParseConfiguration(string configuration)
+ ///
+ public override object ParseConfiguration(string configuration)
{
- return JsonConvert.DeserializeObject(configuration);
+ try
+ {
+ return JsonConvert.DeserializeObject(configuration);
+ }
+ catch (Exception e)
+ {
+ throw new Exception($"Failed to parse configuration \"{configuration}\" as \"{typeof(TConfiguration).Name}\" (see inner exception).", e);
+ }
}
///
@@ -119,7 +123,7 @@ namespace Umbraco.Core.PropertyEditors
///
public sealed override Dictionary ToEditor(object defaultConfiguration, object configuration)
{
- return ToEditor((TConfiguration) defaultConfiguration, (TConfiguration) configuration);
+ return ToEditor((TConfiguration) configuration);
}
///
@@ -127,7 +131,7 @@ namespace Umbraco.Core.PropertyEditors
///
/// The default configuration.
/// The configuration.
- public virtual Dictionary ToEditor(TConfiguration defaultConfiguration, TConfiguration configuration)
+ public virtual Dictionary ToEditor(TConfiguration configuration)
{
// fixme - how shall we merge? does defaultConfiguration makes any sense here?
var dictionary = ObjectExtensions.ToObjectDictionary(configuration);
@@ -149,8 +153,11 @@ namespace Umbraco.Core.PropertyEditors
where T : new()
{
// fixme cache! see also ToObject in ObjectExtensions
+ // this is probably very bad, must REAFACTOR! the property setter of course cannot work like this!
+ //var properties = TypeHelper.CachedDiscoverableProperties(typeof(T))
+ // .ToDictionary(x => x.Name, x => (Type: x.PropertyType, Set: ReflectionUtilities.EmitPropertySetter