Skip to content
This repository has been archived by the owner on Dec 13, 2021. It is now read-only.

Commit

Permalink
Merge pull request #226 from leekelleher/develop
Browse files Browse the repository at this point in the history
Preparing Ditto 0.11.1 release
  • Loading branch information
leekelleher authored Sep 5, 2017
2 parents 8ff1426 + ebad9ee commit b4f2243
Show file tree
Hide file tree
Showing 22 changed files with 431 additions and 277 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.vs
_ReSharper.*
[Bb]in/
[Oo]bj/
Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
os: Visual Studio 2015

# version format
version: 0.11.0.{build}
version: 0.11.1.{build}

# UMBRACO_PACKAGE_PRERELEASE_SUFFIX if a rtm release build this should be blank, otherwise if empty will default to alpha
# example UMBRACO_PACKAGE_PRERELEASE_SUFFIX=beta
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ internal TOuputType GetCacheItem<TOuputType>(DittoCacheContext cacheContext, Fun
// Check the cache key builder type
if (!typeof(DittoCacheKeyBuilder).IsAssignableFrom(cacheKeyBuilderType))
{
throw new ApplicationException("Expected a cache key builder of type " + typeof(DittoCacheKeyBuilder) + " but got " + this.CacheKeyBuilderType);
throw new ApplicationException($"Expected a cache key builder of type {typeof(DittoCacheKeyBuilder)} but got {this.CacheKeyBuilderType}");
}

// Construct the cache key builder
Expand All @@ -73,8 +73,8 @@ internal TOuputType GetCacheItem<TOuputType>(DittoCacheContext cacheContext, Fun

// Get and cache the result
return (TOuputType)ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem(
cacheKey,
() => refresher(),
cacheKey,
() => refresher(),
priority: CacheItemPriority.NotRemovable, // Same as Umbraco macros
timeout: new TimeSpan(0, 0, 0, this.CacheDuration));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ protected DittoProcessorAttribute()
/// The context.
/// </value>
public DittoProcessorContext Context { get; protected set; }

/// <summary>
/// Gets the chain context.
/// </summary>
Expand Down Expand Up @@ -169,13 +169,13 @@ internal virtual object ProcessValue(
/// The <see cref="object" /> representing the processed value.
/// </returns>
internal virtual object ProcessValue(
object value,
object value,
DittoProcessorContext context,
DittoChainContext chainContext)
{
if (value != null && !this.ValueType.IsInstanceOfType(value))
{
throw new ArgumentException("Expected a value argument of type " + this.ValueType + " but got " + value.GetType(), "value");
throw new ArgumentException($"Expected a value argument of type {this.ValueType} but got {value.GetType()}", "value");
}

if (context == null)
Expand All @@ -185,7 +185,7 @@ internal virtual object ProcessValue(

if (!this.ContextType.IsInstanceOfType(context))
{
throw new ArgumentException("Expected a context argument of type " + this.ContextType + " but got " + context.GetType(), "context");
throw new ArgumentException($"Expected a context argument of type {this.ContextType} but got {context.GetType()}", "context");
}

if (chainContext == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ public override object ProcessValue()
// property's type matches the containing model's type, then we throw an exception.
if (this.Context.PropertyDescriptor.PropertyType == this.Context.PropertyDescriptor.ComponentType)
{
throw new InvalidOperationException(
string.Format(
"Unable to process property type '{0}', it is the same as the containing model type.",
this.Context.PropertyDescriptor.PropertyType.Name));
throw new InvalidOperationException($"Unable to process property type '{this.Context.PropertyDescriptor.PropertyType.Name}', it is the same as the containing model type.");
}

return this.Context.Content;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,33 +73,34 @@ public override object ProcessValue()
}
else
{
types = (IEnumerable<Type>)ApplicationContext.Current.ApplicationCache.StaticCache.GetCacheItem("DittoFactoryAttribute_ResolveTypes_" + baseType.AssemblyQualifiedName, () =>
{
// Workaround for http://issues.umbraco.org/issue/U4-9011
if (baseType.Assembly.IsAppCodeAssembly())
types = (IEnumerable<Type>)ApplicationContext.Current.ApplicationCache.StaticCache.GetCacheItem(
string.Concat("DittoFactoryAttribute_ResolveTypes_", baseType.AssemblyQualifiedName),
() =>
{
// This logic is taken from the core type finder so
// it should be performing the same checks
return baseType.Assembly
.GetTypes()
.Where(t => baseType.IsAssignableFrom(t)
&& t.IsClass
&& !t.IsAbstract
&& !t.IsSealed
&& !t.IsNestedPrivate
&& t.GetCustomAttribute<HideFromTypeFinderAttribute>(true) == null)
.ToArray();
}

// Find the appropriate types
// There is no non generic version of ResolveTypes so we have to
// call it via reflection.
var method = typeof(PluginManager).GetMethod("ResolveTypes");
var generic = method.MakeGenericMethod(baseType);
return ((IEnumerable<Type>)generic.Invoke(PluginManager.Current, new object[] { true, null })).ToArray();

});

// Workaround for http://issues.umbraco.org/issue/U4-9011
if (baseType.Assembly.IsAppCodeAssembly())
{
// This logic is taken from the core type finder so
// it should be performing the same checks
return baseType.Assembly
.GetTypes()
.Where(t => baseType.IsAssignableFrom(t)
&& t.IsClass
&& !t.IsAbstract
&& !t.IsSealed
&& !t.IsNestedPrivate
&& t.GetCustomAttribute<HideFromTypeFinderAttribute>(true) == null)
.ToArray();
}

// Find the appropriate types
// There is no non generic version of ResolveTypes so we have to
// call it via reflection.
var method = typeof(PluginManager).GetMethod("ResolveTypes");
var generic = method.MakeGenericMethod(baseType);
return ((IEnumerable<Type>)generic.Invoke(PluginManager.Current, new object[] { true, null })).ToArray();

});
}

// Check for IEnumerable<IPublishedContent> value
Expand All @@ -123,7 +124,7 @@ public override object ProcessValue()
{
var typeName = this.ResolveTypeName(ipublishedContentValue);
var type = types.FirstOrDefault(y => y.Name.InvariantEquals(typeName));
return type != null ? ipublishedContentValue.As(type, chainContext:ChainContext) : null;
return type != null ? ipublishedContentValue.As(type, chainContext: ChainContext) : null;
}

// No other possible options
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,45 @@ namespace Our.Umbraco.Ditto
internal class DittoProcessorRegistry
{
/// <summary>
/// The cache for storing handler information.
/// The cache for storing processors associated by type.
/// </summary>
private static readonly Dictionary<Type, List<DittoProcessorAttribute>> Cache = new Dictionary<Type, List<DittoProcessorAttribute>>();
private static readonly Dictionary<Type, List<DittoProcessorAttribute>> ProcessorCache = new Dictionary<Type, List<DittoProcessorAttribute>>();

/// <summary>
/// Static holder for singleton instance.
/// </summary>
private static readonly Lazy<DittoProcessorRegistry> InternalInstance = new Lazy<DittoProcessorRegistry>(() => new DittoProcessorRegistry());

/// <summary>
/// The lock object to make Cache access thread safe
/// The lock object to make ProcessorCache access thread safe.
/// </summary>
private static readonly object CacheLock = new object();
private static readonly object ProcessorCacheLock = new object();

/// <summary>
/// The default processor type, (defaults to `UmbracoProperty`).
/// </summary>
private Type defaultProcessorType = typeof(UmbracoPropertyAttribute);
private static Type DefaultProcessorType = typeof(UmbracoPropertyAttribute);

/// <summary>
/// The lock object to make DefaultProcessorType access thread safe.
/// </summary>
private static readonly object DefaultProcessorTypeLock = new object();

/// <summary>
/// The default post-processors.
/// </summary>
private static readonly List<DittoProcessorAttribute> PostProcessorCache = new List<DittoProcessorAttribute>()
{
new HtmlStringAttribute(),
new EnumerableConverterAttribute(),
new RecursiveDittoAttribute(),
new TryConvertToAttribute()
};

/// <summary>
/// The lock object to make DefaultPostProcessorAttributes access thread safe.
/// </summary>
private static readonly object PostProcessorCacheLock = new object();

/// <summary>
/// Prevents a default instance of the <see cref="DittoProcessorRegistry"/> class from being created.
Expand Down Expand Up @@ -57,7 +78,10 @@ public static DittoProcessorRegistry Instance
public void RegisterDefaultProcessorType<TProcessorAttributeType>()
where TProcessorAttributeType : DittoProcessorAttribute, new()
{
this.defaultProcessorType = typeof(TProcessorAttributeType);
lock (DefaultProcessorTypeLock)
{
DefaultProcessorType = typeof(TProcessorAttributeType);
}
}

/// <summary>
Expand All @@ -82,14 +106,14 @@ public void RegisterProcessorAttribute<TObjectType, TProcessorAttributeType>(TPr
{
var objType = typeof(TObjectType);

lock (CacheLock)
lock (ProcessorCacheLock)
{
if (!Cache.ContainsKey(objType))
if (!ProcessorCache.ContainsKey(objType))
{
Cache.Add(objType, new List<DittoProcessorAttribute>());
ProcessorCache.Add(objType, new List<DittoProcessorAttribute>());
}

Cache[objType].Add(instance);
ProcessorCache[objType].Add(instance);
}
}

Expand All @@ -108,7 +132,7 @@ public Type GetDefaultProcessorType(Type objectType)
return attr.ProcessorType;
}

return this.defaultProcessorType;
return DefaultProcessorType;
}

/// <summary>
Expand All @@ -119,11 +143,10 @@ public Type GetDefaultProcessorType(Type objectType)
/// </returns>
public IEnumerable<DittoProcessorAttribute> GetPostProcessorAttributes()
{
// TODO: [LK] Enable the post-processor attributes to be configurable
yield return new HtmlStringAttribute();
yield return new EnumerableConverterAttribute();
yield return new RecursiveDittoAttribute();
yield return new TryConvertToAttribute();
lock (PostProcessorCacheLock)
{
return PostProcessorCache;
}
}

/// <summary>
Expand All @@ -135,12 +158,51 @@ public IEnumerable<DittoProcessorAttribute> GetPostProcessorAttributes()
/// </returns>
public IEnumerable<DittoProcessorAttribute> GetRegisteredProcessorAttributesFor(Type objectType)
{
lock (CacheLock)
lock (ProcessorCacheLock)
{
return Cache.ContainsKey(objectType)
? Cache[objectType]
return ProcessorCache.ContainsKey(objectType)
? ProcessorCache[objectType]
: Enumerable.Empty<DittoProcessorAttribute>();
}
}
}

/// <summary>
/// Registers a processor attribute to the end of the default set of post-processor attributes.
/// </summary>
/// <typeparam name="TProcessorAttributeType"></typeparam>
/// <param name="position"></param>
public void RegisterPostProcessorAttribute<TProcessorAttributeType>(int position = -1)
where TProcessorAttributeType : DittoProcessorAttribute, new()
{
var processor = (DittoProcessorAttribute)typeof(TProcessorAttributeType).GetInstance();

lock (PostProcessorCacheLock)
{
if (!PostProcessorCache.Contains(processor))
{
if (position < 0)
{
PostProcessorCache.Add(processor);
}
else
{
PostProcessorCache.Insert(position, processor);
}
}
}
}

/// <summary>
/// Deregisters a processor attribute from the default set of post-processor attributes.
/// </summary>
/// <typeparam name="TProcessorAttributeType"></typeparam>
public void DeregisterPostProcessorAttribute<TProcessorAttributeType>()
where TProcessorAttributeType : DittoProcessorAttribute, new()
{
lock (PostProcessorCacheLock)
{
PostProcessorCache.RemoveAll(x => x is TProcessorAttributeType);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,16 @@ public override object ProcessValue()

if (this.Value != null)
{
var valueIsEnumerableType = this.Value.GetType().IsEnumerableType()
var valueType = this.Value.GetType();
var valueIsEnumerableType = valueType.IsEnumerableType()
&& !(this.Value is string);

if (propertyIsEnumerableType)
{
if (!valueIsEnumerableType)
{
// Property is enumerable, but value isn't, so make enumerable
var arr = Array.CreateInstance(this.Value.GetType(), 1);
var arr = Array.CreateInstance(valueType, 1);
arr.SetValue(this.Value, 0);
result = arr;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public override object ProcessValue()
if (this.Value != null && !this.Context.PropertyDescriptor.PropertyType.IsInstanceOfType(this.Value))
{
// TODO: Maybe support enumerables?
using (DittoDisposableTimer.DebugDuration<TryConvertToAttribute>(string.Format("TryConvertTo ({0}, {1})", this.Context.Content.Id, this.Context.PropertyDescriptor.Name)))
using (DittoDisposableTimer.DebugDuration<TryConvertToAttribute>($"TryConvertTo '{this.Context.PropertyDescriptor.Name}' ({this.Context.Content.Id})"))
{
var convert = this.Value.TryConvertTo(this.Context.PropertyDescriptor.PropertyType);
if (convert.Success)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ private object GetClassPropertyValue(IPublishedContent content, string umbracoPr
&& content.HasProperty(umbracoPropertyName))
{
// Property is an IPublishedContent property and an umbraco property exists so warn the user
LogHelper.Warn<UmbracoPropertyAttribute>("The property " + umbracoPropertyName + " being mapped from content type " + contentType.Name + "'s instance properties hides a property in the umbraco properties collection of the same name. It is recommended that you avoid using umbraco property aliases that conflict with IPublishedContent instance property names, but if you can't avoid this and you require access to the hidden property you can use the PropertySource parameter of the processors attribute to override the order in which properties are checked.");
LogHelper.Warn<UmbracoPropertyAttribute>($"The property {umbracoPropertyName} being mapped from content type {contentType.Name}'s instance properties hides a property in the Umbraco properties collection of the same name. It is recommended that you avoid using Umbraco property aliases that conflict with IPublishedContent instance property names, but if you can't avoid this and you require access to the hidden property you can use the PropertySource parameter of the processors attribute to override the order in which properties are checked.");
}

// This is over 4x faster than propertyValue = contentProperty.GetValue(content, null);
Expand All @@ -230,7 +230,7 @@ private object GetUmbracoPropertyValue(IPublishedContent content, string umbraco
&& content.HasProperty(umbracoPropertyName))
{
// Property is an IPublishedContent property and an umbraco property exists so warn the user
LogHelper.Warn<UmbracoPropertyAttribute>("The property " + umbracoPropertyName + " being mapped from the umbraco properties collection hides an instance property of the same name on content type " + content.GetType().Name + ". It is recommended that you avoid using umbraco property aliases that conflict with IPublishedContent instance property names, but if you can't avoid this and you require access to the hidden property you can use the PropertySource parameter of the processors attribute to override the order in which properties are checked.");
LogHelper.Warn<UmbracoPropertyAttribute>($"The property {umbracoPropertyName} being mapped from the Umbraco properties collection hides an instance property of the same name on content type {content.GetType().Name}. It is recommended that you avoid using Umbraco property aliases that conflict with IPublishedContent instance property names, but if you can't avoid this and you require access to the hidden property you can use the PropertySource parameter of the processors attribute to override the order in which properties are checked.");
}

return content.GetPropertyValue(umbracoPropertyName, recursive);
Expand Down
Loading

0 comments on commit b4f2243

Please sign in to comment.