Merge remote-tracking branch 'origin/dev-v7' into dev-v7.7
# Conflicts: # src/Umbraco.Core/UdiEntityType.cs
This commit is contained in:
@@ -32,7 +32,11 @@ namespace Umbraco.Core
|
||||
public GuidUdi(Uri uriValue)
|
||||
: base(uriValue)
|
||||
{
|
||||
Guid = Guid.Parse(uriValue.AbsolutePath.TrimStart('/'));
|
||||
Guid guid;
|
||||
if (Guid.TryParse(uriValue.AbsolutePath.TrimStart('/'), out guid) == false)
|
||||
throw new FormatException("Url \"" + uriValue + "\" is not a guid entity id.");
|
||||
|
||||
Guid = guid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -43,16 +47,17 @@ namespace Umbraco.Core
|
||||
public new static GuidUdi Parse(string s)
|
||||
{
|
||||
var udi = Udi.Parse(s);
|
||||
if (!(udi is GuidUdi))
|
||||
if (udi is GuidUdi == false)
|
||||
throw new FormatException("String \"" + s + "\" is not a guid entity id.");
|
||||
return (GuidUdi)udi;
|
||||
|
||||
return (GuidUdi) udi;
|
||||
}
|
||||
|
||||
public static bool TryParse(string s, out GuidUdi udi)
|
||||
{
|
||||
Udi tmp;
|
||||
udi = null;
|
||||
if (!TryParse(s, out tmp)) return false;
|
||||
if (TryParse(s, out tmp) == false) return false;
|
||||
udi = tmp as GuidUdi;
|
||||
return udi != null;
|
||||
}
|
||||
@@ -75,10 +80,9 @@ namespace Umbraco.Core
|
||||
get { return Guid == Guid.Empty; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public GuidUdi EnsureClosed()
|
||||
{
|
||||
base.EnsureNotRoot();
|
||||
EnsureNotRoot();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
26
src/Umbraco.Core/Serialization/KnownTypeUdiJsonConverter.cs
Normal file
26
src/Umbraco.Core/Serialization/KnownTypeUdiJsonConverter.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Umbraco.Core.Serialization
|
||||
{
|
||||
public class KnownTypeUdiJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return typeof(Udi).IsAssignableFrom(objectType);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteValue(value.ToString());
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var jo = JToken.ReadFrom(reader);
|
||||
var val = jo.ToObject<string>();
|
||||
return val == null ? null : Udi.Parse(val, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,11 @@ using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Umbraco.Core.Serialization
|
||||
{
|
||||
|
||||
public class UdiJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return typeof(Udi).IsAssignableFrom(objectType);
|
||||
return typeof (Udi).IsAssignableFrom(objectType);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
|
||||
@@ -57,17 +57,18 @@ namespace Umbraco.Core
|
||||
public new static StringUdi Parse(string s)
|
||||
{
|
||||
var udi = Udi.Parse(s);
|
||||
if (!(udi is StringUdi))
|
||||
if (udi is StringUdi == false)
|
||||
throw new FormatException("String \"" + s + "\" is not a string entity id.");
|
||||
return (StringUdi)udi;
|
||||
|
||||
return (StringUdi) udi;
|
||||
}
|
||||
|
||||
public static bool TryParse(string s, out StringUdi udi)
|
||||
{
|
||||
udi = null;
|
||||
Udi tmp;
|
||||
if (!TryParse(s, out tmp) || !(tmp is StringUdi)) return false;
|
||||
udi = (StringUdi)tmp;
|
||||
if (TryParse(s, out tmp) == false || tmp is StringUdi == false) return false;
|
||||
udi = (StringUdi) tmp;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -77,10 +78,9 @@ namespace Umbraco.Core
|
||||
get { return Id == string.Empty; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public StringUdi EnsureClosed()
|
||||
{
|
||||
base.EnsureNotRoot();
|
||||
EnsureNotRoot();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Deploy;
|
||||
|
||||
namespace Umbraco.Core
|
||||
@@ -15,7 +14,15 @@ namespace Umbraco.Core
|
||||
[TypeConverter(typeof(UdiTypeConverter))]
|
||||
public abstract class Udi : IComparable<Udi>
|
||||
{
|
||||
private static readonly Lazy<Dictionary<string, UdiType>> UdiTypes;
|
||||
// notes - see U4-10409
|
||||
// if this class is used during application pre-start it cannot scans the assemblies,
|
||||
// this is addressed by lazily-scanning, with the following caveats:
|
||||
// - parsing a root udi still requires a scan and therefore still breaks
|
||||
// - parsing an invalid udi ("umb://should-be-guid/<not-a-guid>") corrupts KnowUdiTypes
|
||||
|
||||
private static volatile bool _scanned;
|
||||
private static readonly object ScanLocker = new object();
|
||||
private static ConcurrentDictionary<string, UdiType> _udiTypes;
|
||||
private static readonly ConcurrentDictionary<string, Udi> RootUdis = new ConcurrentDictionary<string, Udi>();
|
||||
internal readonly Uri UriValue; // internal for UdiRange
|
||||
|
||||
@@ -42,50 +49,16 @@ namespace Umbraco.Core
|
||||
|
||||
static Udi()
|
||||
{
|
||||
UdiTypes = new Lazy<Dictionary<string, UdiType>>(() =>
|
||||
{
|
||||
var result = new Dictionary<string, UdiType>();
|
||||
|
||||
// known types:
|
||||
foreach (var fi in typeof(Constants.UdiEntityType).GetFields(BindingFlags.Public | BindingFlags.Static))
|
||||
{
|
||||
// IsLiteral determines if its value is written at
|
||||
// compile time and not changeable
|
||||
// IsInitOnly determine if the field can be set
|
||||
// in the body of the constructor
|
||||
// for C# a field which is readonly keyword would have both true
|
||||
// but a const field would have only IsLiteral equal to true
|
||||
if (fi.IsLiteral && fi.IsInitOnly == false)
|
||||
{
|
||||
var udiType = fi.GetCustomAttribute<Constants.UdiTypeAttribute>();
|
||||
// initialize with known (built-in) Udi types
|
||||
// we will add scanned types later on
|
||||
_udiTypes = new ConcurrentDictionary<string, UdiType>(Constants.UdiEntityType.GetTypes());
|
||||
}
|
||||
|
||||
if (udiType == null)
|
||||
throw new InvalidOperationException("All Constants listed in UdiEntityType must be attributed with " + typeof(Constants.UdiTypeAttribute));
|
||||
result[fi.GetValue(null).ToString()] = udiType.UdiType;
|
||||
}
|
||||
}
|
||||
|
||||
// Scan for unknown UDI types
|
||||
// there is no way we can get the "registered" service connectors, as registration
|
||||
// happens in Deploy, not in Core, and the Udi class belongs to Core - therefore, we
|
||||
// just pick every service connectors - just making sure that not two of them
|
||||
// would register the same entity type, with different udi types (would not make
|
||||
// much sense anyways).
|
||||
var connectors = PluginManager.Current.ResolveTypes<IServiceConnector>();
|
||||
foreach (var connector in connectors)
|
||||
{
|
||||
var attrs = connector.GetCustomAttributes<UdiDefinitionAttribute>(false);
|
||||
foreach (var attr in attrs)
|
||||
{
|
||||
UdiType udiType;
|
||||
if (result.TryGetValue(attr.EntityType, out udiType) && udiType != attr.UdiType)
|
||||
throw new Exception(string.Format("Entity type \"{0}\" is declared by more than one IServiceConnector, with different UdiTypes.", attr.EntityType));
|
||||
result[attr.EntityType] = attr.UdiType;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
// for tests, totally unsafe
|
||||
internal static void ResetUdiTypes()
|
||||
{
|
||||
_udiTypes = new ConcurrentDictionary<string, UdiType>(Constants.UdiEntityType.GetTypes());
|
||||
_scanned = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -113,17 +86,65 @@ namespace Umbraco.Core
|
||||
public static Udi Parse(string s)
|
||||
{
|
||||
Udi udi;
|
||||
ParseInternal(s, false, out udi);
|
||||
ParseInternal(s, false, false, out udi);
|
||||
return udi;
|
||||
}
|
||||
|
||||
public static bool TryParse(string s, out Udi udi)
|
||||
/// <summary>
|
||||
/// Converts the string representation of an entity identifier into the equivalent Udi instance.
|
||||
/// </summary>
|
||||
/// <param name="s">The string to convert.</param>
|
||||
/// <param name="knownTypes">A value indicating whether to only deal with known types.</param>
|
||||
/// <returns>An Udi instance that contains the value that was parsed.</returns>
|
||||
/// <remarks>
|
||||
/// <para>If <paramref name="knownTypes"/> is <c>true</c>, and the string could not be parsed because
|
||||
/// the entity type was not known, the method succeeds but sets <c>udi</c>to an
|
||||
/// <see cref="UnknownTypeUdi"/> value.</para>
|
||||
/// <para>If <paramref name="knownTypes"/> is <c>true</c>, assemblies are not scanned for types,
|
||||
/// and therefore only builtin types may be known. Unless scanning already took place.</para>
|
||||
/// </remarks>
|
||||
public static Udi Parse(string s, bool knownTypes)
|
||||
{
|
||||
return ParseInternal(s, true, out udi);
|
||||
Udi udi;
|
||||
ParseInternal(s, false, knownTypes, out udi);
|
||||
return udi;
|
||||
}
|
||||
|
||||
private static bool ParseInternal(string s, bool tryParse, out Udi udi)
|
||||
/// <summary>
|
||||
/// Converts the string representation of an entity identifier into the equivalent Udi instance.
|
||||
/// </summary>
|
||||
/// <param name="s">The string to convert.</param>
|
||||
/// <param name="udi">An Udi instance that contains the value that was parsed.</param>
|
||||
/// <returns>A boolean value indicating whether the string could be parsed.</returns>
|
||||
public static bool TryParse(string s, out Udi udi)
|
||||
{
|
||||
return ParseInternal(s, true, false, out udi);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the string representation of an entity identifier into the equivalent Udi instance.
|
||||
/// </summary>
|
||||
/// <param name="s">The string to convert.</param>
|
||||
/// <param name="knownTypes">A value indicating whether to only deal with known types.</param>
|
||||
/// <param name="udi">An Udi instance that contains the value that was parsed.</param>
|
||||
/// <returns>A boolean value indicating whether the string could be parsed.</returns>
|
||||
/// <remarks>
|
||||
/// <para>If <paramref name="knownTypes"/> is <c>true</c>, and the string could not be parsed because
|
||||
/// the entity type was not known, the method returns <c>false</c> but still sets <c>udi</c>
|
||||
/// to an <see cref="UnknownTypeUdi"/> value.</para>
|
||||
/// <para>If <paramref name="knownTypes"/> is <c>true</c>, assemblies are not scanned for types,
|
||||
/// and therefore only builtin types may be known. Unless scanning already took place.</para>
|
||||
/// </remarks>
|
||||
public static bool TryParse(string s, bool knownTypes, out Udi udi)
|
||||
{
|
||||
return ParseInternal(s, true, knownTypes, out udi);
|
||||
}
|
||||
|
||||
private static bool ParseInternal(string s, bool tryParse, bool knownTypes, out Udi udi)
|
||||
{
|
||||
if (knownTypes == false)
|
||||
EnsureScanForUdiTypes();
|
||||
|
||||
udi = null;
|
||||
Uri uri;
|
||||
|
||||
@@ -136,12 +157,21 @@ namespace Umbraco.Core
|
||||
|
||||
var entityType = uri.Host;
|
||||
UdiType udiType;
|
||||
if (UdiTypes.Value.TryGetValue(entityType, out udiType) == false)
|
||||
if (_udiTypes.TryGetValue(entityType, out udiType) == false)
|
||||
{
|
||||
if (knownTypes)
|
||||
{
|
||||
// not knowing the type is not an error
|
||||
// just return the unknown type udi
|
||||
udi = UnknownTypeUdi.Instance;
|
||||
return false;
|
||||
}
|
||||
if (tryParse) return false;
|
||||
throw new FormatException(string.Format("Unknown entity type \"{0}\".", entityType));
|
||||
}
|
||||
|
||||
var path = uri.AbsolutePath.TrimStart('/');
|
||||
|
||||
if (udiType == UdiType.GuidUdi)
|
||||
{
|
||||
if (path == string.Empty)
|
||||
@@ -158,21 +188,25 @@ namespace Umbraco.Core
|
||||
udi = new GuidUdi(uri.Host, guid);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (udiType == UdiType.StringUdi)
|
||||
{
|
||||
udi = path == string.Empty ? GetRootUdi(uri.Host) : new StringUdi(uri.Host, Uri.UnescapeDataString(path));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tryParse) return false;
|
||||
throw new InvalidOperationException("Internal error.");
|
||||
throw new InvalidOperationException(string.Format("Invalid udi type \"{0}\".", udiType));
|
||||
}
|
||||
|
||||
private static Udi GetRootUdi(string entityType)
|
||||
{
|
||||
EnsureScanForUdiTypes();
|
||||
|
||||
return RootUdis.GetOrAdd(entityType, x =>
|
||||
{
|
||||
UdiType udiType;
|
||||
if (UdiTypes.Value.TryGetValue(x, out udiType) == false)
|
||||
if (_udiTypes.TryGetValue(x, out udiType) == false)
|
||||
throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType));
|
||||
return udiType == UdiType.StringUdi
|
||||
? (Udi)new StringUdi(entityType, string.Empty)
|
||||
@@ -180,6 +214,46 @@ namespace Umbraco.Core
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When required scan assemblies for known UDI types based on <see cref="IServiceConnector"/> instances
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is only required when needing to resolve root udis
|
||||
/// </remarks>
|
||||
private static void EnsureScanForUdiTypes()
|
||||
{
|
||||
if (_scanned) return;
|
||||
|
||||
lock (ScanLocker)
|
||||
{
|
||||
// Scan for unknown UDI types
|
||||
// there is no way we can get the "registered" service connectors, as registration
|
||||
// happens in Deploy, not in Core, and the Udi class belongs to Core - therefore, we
|
||||
// just pick every service connectors - just making sure that not two of them
|
||||
// would register the same entity type, with different udi types (would not make
|
||||
// much sense anyways).
|
||||
var connectors = PluginManager.Current.ResolveTypes<IServiceConnector>();
|
||||
var result = new Dictionary<string, UdiType>();
|
||||
foreach (var connector in connectors)
|
||||
{
|
||||
var attrs = connector.GetCustomAttributes<UdiDefinitionAttribute>(false);
|
||||
foreach (var attr in attrs)
|
||||
{
|
||||
UdiType udiType;
|
||||
if (result.TryGetValue(attr.EntityType, out udiType) && udiType != attr.UdiType)
|
||||
throw new Exception(string.Format("Entity type \"{0}\" is declared by more than one IServiceConnector, with different UdiTypes.", attr.EntityType));
|
||||
result[attr.EntityType] = attr.UdiType;
|
||||
}
|
||||
}
|
||||
|
||||
// merge these into the known list
|
||||
foreach (var item in result)
|
||||
_udiTypes.TryAdd(item.Key, item.Value);
|
||||
|
||||
_scanned = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a root Udi for an entity type.
|
||||
/// </summary>
|
||||
@@ -199,13 +273,14 @@ namespace Umbraco.Core
|
||||
public static Udi Create(string entityType, string id)
|
||||
{
|
||||
UdiType udiType;
|
||||
if (UdiTypes.Value.TryGetValue(entityType, out udiType) == false)
|
||||
if (_udiTypes.TryGetValue(entityType, out udiType) == false)
|
||||
throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType), "entityType");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
throw new ArgumentException("Value cannot be null or whitespace.", "id");
|
||||
if (udiType != UdiType.StringUdi)
|
||||
throw new InvalidOperationException(string.Format("Entity type \"{0}\" does not have string udis.", entityType));
|
||||
|
||||
|
||||
return new StringUdi(entityType, id);
|
||||
}
|
||||
|
||||
@@ -218,24 +293,31 @@ namespace Umbraco.Core
|
||||
public static Udi Create(string entityType, Guid id)
|
||||
{
|
||||
UdiType udiType;
|
||||
if (UdiTypes.Value.TryGetValue(entityType, out udiType) == false)
|
||||
if (_udiTypes.TryGetValue(entityType, out udiType) == false)
|
||||
throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType), "entityType");
|
||||
|
||||
if (udiType != UdiType.GuidUdi)
|
||||
throw new InvalidOperationException(string.Format("Entity type \"{0}\" does not have guid udis.", entityType));
|
||||
throw new InvalidOperationException(string.Format("Entity type \"{0}\" does not have guid udis.", entityType));
|
||||
if (id == default(Guid))
|
||||
throw new ArgumentException("Cannot be an empty guid.", "id");
|
||||
|
||||
return new GuidUdi(entityType, id);
|
||||
}
|
||||
|
||||
internal static Udi Create(Uri uri)
|
||||
{
|
||||
// if it's a know type go fast and use ctors
|
||||
// else fallback to parsing the string (and guess the type)
|
||||
|
||||
UdiType udiType;
|
||||
if (UdiTypes.Value.TryGetValue(uri.Host, out udiType) == false)
|
||||
if (_udiTypes.TryGetValue(uri.Host, out udiType) == false)
|
||||
throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", uri.Host), "uri");
|
||||
|
||||
if (udiType == UdiType.GuidUdi)
|
||||
return new GuidUdi(uri);
|
||||
if (udiType == UdiType.GuidUdi)
|
||||
return new StringUdi(uri);
|
||||
|
||||
throw new ArgumentException(string.Format("Uri \"{0}\" is not a valid udi.", uri));
|
||||
}
|
||||
|
||||
@@ -284,6 +366,19 @@ namespace Umbraco.Core
|
||||
{
|
||||
return (udi1 == udi2) == false;
|
||||
}
|
||||
}
|
||||
|
||||
private class UnknownTypeUdi : Udi
|
||||
{
|
||||
private UnknownTypeUdi()
|
||||
: base("unknown", "umb://unknown/")
|
||||
{ }
|
||||
|
||||
public static readonly UnknownTypeUdi Instance = new UnknownTypeUdi();
|
||||
|
||||
public override bool IsRoot
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
|
||||
public static partial class Constants
|
||||
{
|
||||
/// <summary>
|
||||
@@ -13,87 +13,100 @@ namespace Umbraco.Core
|
||||
/// but entity types are strings and so can be extended beyond what is defined here.</remarks>
|
||||
public static class UdiEntityType
|
||||
{
|
||||
[UdiType(UdiType.Unknown)]
|
||||
// note: const fields in this class MUST be consistent with what GetTypes returns
|
||||
// this is validated by UdiTests.ValidateUdiEntityType
|
||||
|
||||
internal static Dictionary<string, UdiType> GetTypes()
|
||||
{
|
||||
return new Dictionary<string,UdiType>
|
||||
{
|
||||
{ Unknown, UdiType.Unknown },
|
||||
|
||||
{ AnyGuid, UdiType.GuidUdi },
|
||||
{ Document, UdiType.GuidUdi },
|
||||
{ DocumentBluePrint, UdiType.GuidUdi },
|
||||
{ Media, UdiType.GuidUdi },
|
||||
{ Member, UdiType.GuidUdi },
|
||||
{ DictionaryItem, UdiType.GuidUdi },
|
||||
{ Macro, UdiType.GuidUdi },
|
||||
{ Template, UdiType.GuidUdi },
|
||||
{ DocumentType, UdiType.GuidUdi },
|
||||
{ DocumentTypeContainer, UdiType.GuidUdi },
|
||||
{ DocumentTypeBluePrints, UdiType.GuidUdi },
|
||||
{ MediaType, UdiType.GuidUdi },
|
||||
{ MediaTypeContainer, UdiType.GuidUdi },
|
||||
{ DataType, UdiType.GuidUdi },
|
||||
{ DataTypeContainer, UdiType.GuidUdi },
|
||||
{ MemberType, UdiType.GuidUdi },
|
||||
{ MemberGroup, UdiType.GuidUdi },
|
||||
{ RelationType, UdiType.GuidUdi },
|
||||
{ FormsForm, UdiType.GuidUdi },
|
||||
{ FormsPreValue, UdiType.GuidUdi },
|
||||
{ FormsDataSource, UdiType.GuidUdi },
|
||||
|
||||
{ AnyString, UdiType.StringUdi},
|
||||
{ Language, UdiType.StringUdi},
|
||||
{ MacroScript, UdiType.StringUdi},
|
||||
{ MediaFile, UdiType.StringUdi},
|
||||
{ TemplateFile, UdiType.StringUdi},
|
||||
{ Script, UdiType.StringUdi},
|
||||
{ PartialView, UdiType.StringUdi},
|
||||
{ PartialViewMacro, UdiType.StringUdi},
|
||||
{ Stylesheet, UdiType.StringUdi},
|
||||
{ UserControl, UdiType.StringUdi},
|
||||
{ Xslt, UdiType.StringUdi},
|
||||
};
|
||||
}
|
||||
|
||||
public const string Unknown = "unknown";
|
||||
|
||||
// guid entity types
|
||||
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string AnyGuid = "any-guid"; // that one is for tests
|
||||
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string Document = "document";
|
||||
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string DocumentBluePrint = "document-blueprint";
|
||||
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string Media = "media";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string Member = "member";
|
||||
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string DictionaryItem = "dictionary-item";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string Macro = "macro";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string Template = "template";
|
||||
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string DocumentType = "document-type";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string DocumentTypeContainer = "document-type-container";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
|
||||
public const string DocumentTypeBluePrints = "document-type-blueprints";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string MediaType = "media-type";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string MediaTypeContainer = "media-type-container";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string DataType = "data-type";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string DataTypeContainer = "data-type-container";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string MemberType = "member-type";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string MemberGroup = "member-group";
|
||||
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string RelationType = "relation-type";
|
||||
|
||||
// forms
|
||||
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string FormsForm = "forms-form";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string FormsPreValue = "forms-prevalue";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string FormsDataSource = "forms-datasource";
|
||||
|
||||
// string entity types
|
||||
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string AnyString = "any-string"; // that one is for tests
|
||||
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string Language = "language";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string MacroScript = "macroscript";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string MediaFile = "media-file";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string TemplateFile = "template-file";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string Script = "script";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string Stylesheet = "stylesheet";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string PartialView = "partial-view";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string PartialViewMacro = "partial-view-macro";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string UserControl = "usercontrol";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string Xslt = "xslt";
|
||||
|
||||
public static string FromUmbracoObjectType(UmbracoObjectTypes umbracoObjectType)
|
||||
@@ -185,16 +198,5 @@ namespace Umbraco.Core
|
||||
string.Format("EntityType \"{0}\" does not have a matching UmbracoObjectType.", entityType));
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
internal class UdiTypeAttribute : Attribute
|
||||
{
|
||||
public UdiType UdiType { get; private set; }
|
||||
|
||||
public UdiTypeAttribute(UdiType udiType)
|
||||
{
|
||||
UdiType = udiType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,8 +62,8 @@ namespace Umbraco.Core
|
||||
{
|
||||
Uri uri;
|
||||
|
||||
if (!Uri.IsWellFormedUriString(s, UriKind.Absolute)
|
||||
|| !Uri.TryCreate(s, UriKind.Absolute, out uri))
|
||||
if (Uri.IsWellFormedUriString(s, UriKind.Absolute) == false
|
||||
|| Uri.TryCreate(s, UriKind.Absolute, out uri) == false)
|
||||
{
|
||||
//if (tryParse) return false;
|
||||
throw new FormatException(string.Format("String \"{0}\" is not a valid udi range.", s));
|
||||
|
||||
@@ -700,6 +700,7 @@
|
||||
<Compile Include="Security\UmbracoEmailMessage.cs" />
|
||||
<Compile Include="Security\UserAwareMembershipProviderPasswordHasher.cs" />
|
||||
<Compile Include="SemVersionExtensions.cs" />
|
||||
<Compile Include="Serialization\KnownTypeUdiJsonConverter.cs" />
|
||||
<Compile Include="Serialization\NoTypeConverterJsonConverter.cs" />
|
||||
<Compile Include="Serialization\StreamResultExtensions.cs" />
|
||||
<Compile Include="Serialization\UdiJsonConverter.cs" />
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Deploy;
|
||||
using Umbraco.Core.Serialization;
|
||||
|
||||
namespace Umbraco.Tests
|
||||
@@ -11,7 +14,7 @@ namespace Umbraco.Tests
|
||||
public class UdiTests
|
||||
{
|
||||
[Test]
|
||||
public void StringEntityCtorTest()
|
||||
public void StringUdiCtorTest()
|
||||
{
|
||||
var udi = new StringUdi(Constants.UdiEntityType.AnyString, "test-id");
|
||||
Assert.AreEqual(Constants.UdiEntityType.AnyString, udi.EntityType);
|
||||
@@ -20,7 +23,7 @@ namespace Umbraco.Tests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StringEntityParseTest()
|
||||
public void StringUdiParseTest()
|
||||
{
|
||||
var udi = Udi.Parse("umb://" + Constants.UdiEntityType.AnyString + "/test-id");
|
||||
Assert.AreEqual(Constants.UdiEntityType.AnyString, udi.EntityType);
|
||||
@@ -29,6 +32,9 @@ namespace Umbraco.Tests
|
||||
Assert.IsNotNull(stringEntityId);
|
||||
Assert.AreEqual("test-id", stringEntityId.Id);
|
||||
Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyString + "/test-id", udi.ToString());
|
||||
|
||||
udi = Udi.Parse("umb://" + Constants.UdiEntityType.AnyString + "/DA845952BE474EE9BD6F6194272AC750");
|
||||
Assert.IsInstanceOf<StringUdi>(udi);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -83,7 +89,7 @@ namespace Umbraco.Tests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GuidEntityCtorTest()
|
||||
public void GuidUdiCtorTest()
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
var udi = new GuidUdi(Constants.UdiEntityType.AnyGuid, guid);
|
||||
@@ -93,7 +99,7 @@ namespace Umbraco.Tests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GuidEntityParseTest()
|
||||
public void GuidUdiParseTest()
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
var s = "umb://" + Constants.UdiEntityType.AnyGuid + "/" + guid.ToString("N");
|
||||
@@ -148,9 +154,32 @@ namespace Umbraco.Tests
|
||||
Assert.AreEqual(Constants.UdiEntityType.AnyGuid, udi.EntityType);
|
||||
Assert.AreEqual(guid, ((GuidUdi)udi).Guid);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => Udi.Create(Constants.UdiEntityType.AnyString, guid));
|
||||
Assert.Throws<InvalidOperationException>(() => Udi.Create(Constants.UdiEntityType.AnyGuid, "foo"));
|
||||
Assert.Throws<ArgumentException>(() => Udi.Create("barf", "foo"));
|
||||
// *not* testing whether Udi.Create(type, invalidValue) throws
|
||||
// because we don't throw anymore - see U4-10409
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RootUdiTest()
|
||||
{
|
||||
var stringUdi = new StringUdi(Constants.UdiEntityType.AnyString, string.Empty);
|
||||
Assert.IsTrue(stringUdi.IsRoot);
|
||||
Assert.AreEqual("umb://any-string/", stringUdi.ToString());
|
||||
|
||||
var guidUdi = new GuidUdi(Constants.UdiEntityType.AnyGuid, Guid.Empty);
|
||||
Assert.IsTrue(guidUdi.IsRoot);
|
||||
Assert.AreEqual("umb://any-guid/00000000000000000000000000000000", guidUdi.ToString());
|
||||
|
||||
var udi = Udi.Parse("umb://any-string/");
|
||||
Assert.IsTrue(udi.IsRoot);
|
||||
Assert.IsInstanceOf<StringUdi>(udi);
|
||||
|
||||
udi = Udi.Parse("umb://any-guid/00000000000000000000000000000000");
|
||||
Assert.IsTrue(udi.IsRoot);
|
||||
Assert.IsInstanceOf<GuidUdi>(udi);
|
||||
|
||||
udi = Udi.Parse("umb://any-guid/");
|
||||
Assert.IsTrue(udi.IsRoot);
|
||||
Assert.IsInstanceOf<GuidUdi>(udi);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -202,5 +231,112 @@ namespace Umbraco.Tests
|
||||
Assert.AreEqual(string.Format("umb://any-guid/{0:N}", guid), drange.Udi.UriValue.ToString());
|
||||
Assert.AreEqual(Constants.DeploySelector.ChildrenOfThis, drange.Selector);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ValidateUdiEntityType()
|
||||
{
|
||||
var types = Constants.UdiEntityType.GetTypes();
|
||||
|
||||
foreach (var fi in typeof (Constants.UdiEntityType).GetFields(BindingFlags.Public | BindingFlags.Static))
|
||||
{
|
||||
// IsLiteral determines if its value is written at
|
||||
// compile time and not changeable
|
||||
// IsInitOnly determine if the field can be set
|
||||
// in the body of the constructor
|
||||
// for C# a field which is readonly keyword would have both true
|
||||
// but a const field would have only IsLiteral equal to true
|
||||
if (fi.IsLiteral && fi.IsInitOnly == false)
|
||||
{
|
||||
var value = fi.GetValue(null).ToString();
|
||||
|
||||
if (types.ContainsKey(value) == false)
|
||||
Assert.Fail("Error in class Constants.UdiEntityType, type \"{0}\" is not declared by GetTypes.", value);
|
||||
types.Remove(value);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.AreEqual(0, types.Count, "Error in class Constants.UdiEntityType, GetTypes declares types that don't exist ({0}).", string.Join(",", types.Keys.Select(x => "\"" + x + "\"")));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void KnownTypes()
|
||||
{
|
||||
Udi udi;
|
||||
|
||||
// cannot parse an unknown type, udi is null
|
||||
// this will scan
|
||||
Assert.IsFalse(Udi.TryParse("umb://whatever/1234", out udi));
|
||||
Assert.IsNull(udi);
|
||||
|
||||
Udi.ResetUdiTypes();
|
||||
|
||||
// unless we want to know
|
||||
Assert.IsFalse(Udi.TryParse("umb://whatever/1234", true, out udi));
|
||||
Assert.AreEqual(Constants.UdiEntityType.Unknown, udi.EntityType);
|
||||
Assert.AreEqual("Umbraco.Core.Udi+UnknownTypeUdi", udi.GetType().FullName);
|
||||
|
||||
Udi.ResetUdiTypes();
|
||||
|
||||
// not known
|
||||
Assert.IsFalse(Udi.TryParse("umb://foo/A87F65C8D6B94E868F6949BA92C93045", true, out udi));
|
||||
Assert.AreEqual(Constants.UdiEntityType.Unknown, udi.EntityType);
|
||||
Assert.AreEqual("Umbraco.Core.Udi+UnknownTypeUdi", udi.GetType().FullName);
|
||||
|
||||
// scanned
|
||||
Assert.IsTrue(Udi.TryParse("umb://foo/A87F65C8D6B94E868F6949BA92C93045", out udi));
|
||||
Assert.IsInstanceOf<GuidUdi>(udi);
|
||||
|
||||
// known
|
||||
Assert.IsTrue(Udi.TryParse("umb://foo/A87F65C8D6B94E868F6949BA92C93045", true, out udi));
|
||||
Assert.IsInstanceOf<GuidUdi>(udi);
|
||||
|
||||
// can get method for Deploy compatibility
|
||||
var method = typeof (Udi).GetMethod("Parse", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof (string), typeof (bool) }, null);
|
||||
Assert.IsNotNull(method);
|
||||
}
|
||||
|
||||
[UdiDefinition("foo", UdiType.GuidUdi)]
|
||||
public class FooConnector : IServiceConnector
|
||||
{
|
||||
public IArtifact GetArtifact(Udi udi)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IArtifact GetArtifact(object entity)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ArtifactDeployState ProcessInit(IArtifact art, IDeployContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Process(ArtifactDeployState dart, IDeployContext context, int pass)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Explode(UdiRange range, List<Udi> udis)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public NamedUdiRange GetRange(Udi udi, string selector)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public NamedUdiRange GetRange(string entityType, string sid, string selector)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Compare(IArtifact art1, IArtifact art2, ICollection<Difference> differences = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user