diff --git a/UmbracoVault/Attributes/UmbracoEntityAttribute.cs b/UmbracoVault/Attributes/UmbracoEntityAttribute.cs index 31b0fe1..6a2e572 100644 --- a/UmbracoVault/Attributes/UmbracoEntityAttribute.cs +++ b/UmbracoVault/Attributes/UmbracoEntityAttribute.cs @@ -12,7 +12,8 @@ public class UmbracoEntityAttribute : Attribute { public UmbracoEntityAttribute() { - } + ReturnStronglyTypedChildren = true; + } /// /// Only needed if the name of the Entity is not the same as the umbraco Doc Type alias @@ -21,7 +22,8 @@ public UmbracoEntityAttribute() public UmbracoEntityAttribute(string alias) { Alias = alias; - } + ReturnStronglyTypedChildren = true; + } /// /// When false (default), you must manually opt in all properties to be mapped with the [UmbracoProperty] attribute. @@ -39,5 +41,7 @@ public UmbracoEntityAttribute(string alias) /// Typehandler must implement ITypeHandler /// public virtual Type TypeHandlerOverride { get; set; } - } + + public bool ReturnStronglyTypedChildren { get; set; } + } } diff --git a/UmbracoVault/Base/BaseUmbracoContext.cs b/UmbracoVault/Base/BaseUmbracoContext.cs index 17e9175..afaebd1 100644 --- a/UmbracoVault/Base/BaseUmbracoContext.cs +++ b/UmbracoVault/Base/BaseUmbracoContext.cs @@ -9,6 +9,7 @@ using UmbracoVault.Attributes; using UmbracoVault.Caching; using UmbracoVault.Extensions; +using UmbracoVault.Models; using UmbracoVault.TypeHandlers; @@ -20,6 +21,24 @@ public abstract class BaseUmbracoContext : IUmbracoContext protected readonly TypeHandlerFactory _typeHandlerFactory; protected readonly CacheManager _cacheManager; + private static List _vaultEntities; + + internal List VaultEntities + { + get + { + if (_vaultEntities == null) + { + _vaultEntities = VaultEntityExtensions.GetValutEntities(); + } + return _vaultEntities; + } + set + { + _vaultEntities = value; + } + } + protected BaseUmbracoContext() { _typeHandlerFactory = TypeHandlerFactory.Instance; diff --git a/UmbracoVault/Extensions/VaultEntityExtensions.cs b/UmbracoVault/Extensions/VaultEntityExtensions.cs new file mode 100644 index 0000000..9e397f3 --- /dev/null +++ b/UmbracoVault/Extensions/VaultEntityExtensions.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UmbracoVault.Attributes; +using UmbracoVault.Models; + +namespace UmbracoVault.Extensions +{ + internal static class VaultEntityExtensions + { + private static List _entities; + private static readonly object Padlock = new object(); + + internal static List GetValutEntities() + { + if (_entities == null) + { + lock (Padlock) + { + if (_entities == null) + { + _entities = LoadVaultEntities(); + } + } + } + + return _entities; + } + + private static List LoadVaultEntities() + { + var output = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany( + x => + { + Type[] types; + try + { + types = x.GetTypes(); + } + // TODO: We may need to create a fluent registration system for these viewmodels. + catch (Exception) // TODO: Generic exception says 'whaa!?' + { + return new Type[] { }; + } + return types; + }) + .Select(x => + { + try + { + return new VaultEntity + { + MetaData = ((UmbracoEntityAttribute)Attribute.GetCustomAttribute(x, typeof(UmbracoEntityAttribute), false)), + Type = x + + }; + } + catch (TypeLoadException) // Ignore type loads + { + return new VaultEntity(); + } + }) + .Where(x => x.MetaData != null) + .ToList(); + + return output; + } + } +} diff --git a/UmbracoVault/Models/VaultEntity.cs b/UmbracoVault/Models/VaultEntity.cs new file mode 100644 index 0000000..a8b7417 --- /dev/null +++ b/UmbracoVault/Models/VaultEntity.cs @@ -0,0 +1,11 @@ +using System; +using UmbracoVault.Attributes; + +namespace UmbracoVault.Models +{ + internal class VaultEntity + { + public UmbracoEntityAttribute MetaData { get; set; } + public Type Type { get; set; } + } +} diff --git a/UmbracoVault/UmbracoContext.cs b/UmbracoVault/UmbracoContext.cs index 76634ab..5f5d35d 100644 --- a/UmbracoVault/UmbracoContext.cs +++ b/UmbracoVault/UmbracoContext.cs @@ -151,6 +151,25 @@ public override IEnumerable QueryRelative(string query) } protected T GetItem(IPublishedContent n) + { + var typesMetaData = this.VaultEntities.FirstOrDefault(x => x.Type == typeof(T)); + var explicitType = this.VaultEntities.FirstOrDefault(x => + typeof(T).IsAssignableFrom(x.Type) + && (x.Type.Name.Equals(n.ContentType.Alias, StringComparison.CurrentCultureIgnoreCase) + || (x.MetaData.Alias != null && x.MetaData.Alias.Equals(n.ContentType.Alias, StringComparison.CurrentCultureIgnoreCase)))); + + var useExplicitType = explicitType != null && typesMetaData != null && typesMetaData.MetaData.ReturnStronglyTypedChildren; + var typeToUse = useExplicitType ? explicitType.Type : typeof(T); + + var getItemMethod = this.GetType() + .GetMethod(nameof(GetItemForExplicitType), BindingFlags.Instance | BindingFlags.NonPublic) + .MakeGenericMethod(typeToUse); + + var result = getItemMethod.Invoke(this, new object[] { n }); + return (T)result; + } + + protected T GetItemForExplicitType(IPublishedContent n) { var cachedItem = _cacheManager.GetItem(n.Id); if (cachedItem != null) diff --git a/UmbracoVault/UmbracoVault.csproj b/UmbracoVault/UmbracoVault.csproj index 2597ee8..906ba1b 100644 --- a/UmbracoVault/UmbracoVault.csproj +++ b/UmbracoVault/UmbracoVault.csproj @@ -88,7 +88,9 @@ + + diff --git a/UmbracoVault/UmbracoWeblessContext.cs b/UmbracoVault/UmbracoWeblessContext.cs index ce24b8c..0fde3d3 100644 --- a/UmbracoVault/UmbracoWeblessContext.cs +++ b/UmbracoVault/UmbracoWeblessContext.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -81,6 +82,25 @@ protected IContent GetUmbracoContent(int id) } protected T GetItem(IContent n) + { + var typesMetaData = this.VaultEntities.FirstOrDefault(x => x.Type == typeof(T)); + var explicitType = this.VaultEntities.FirstOrDefault(x => + typeof(T).IsAssignableFrom(x.Type) + && (x.Type.Name.Equals(n.ContentType.Alias, StringComparison.CurrentCultureIgnoreCase) + || (x.MetaData.Alias != null && x.MetaData.Alias.Equals(n.ContentType.Alias, StringComparison.CurrentCultureIgnoreCase)))); + + var useExplicitType = explicitType != null && typesMetaData != null && typesMetaData.MetaData.ReturnStronglyTypedChildren; + var typeToUse = useExplicitType ? explicitType.Type : typeof(T); + + var getItemMethod = this.GetType() + .GetMethod(nameof(GetItemForExplicitType), BindingFlags.Instance | BindingFlags.NonPublic) + .MakeGenericMethod(typeToUse); + + var result = getItemMethod.Invoke(this, new object[] { n }); + return (T)result; + } + + private T GetItemForExplicitType(IContent n) { var cachedItem = _cacheManager.GetItem(n.Id); if (cachedItem != null) @@ -109,6 +129,13 @@ protected T GetItem(IContent n) return property.Value; } + else + { + if (string.Equals("name", propertyInfo.Name, StringComparison.CurrentCultureIgnoreCase) && propertyInfo.PropertyType == typeof(string)) + { + return n.Name; + } + } return null; });