diff --git a/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs b/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs
index a71d0a3f1e..0cd5705aa5 100644
--- a/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs
+++ b/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs
@@ -5,6 +5,19 @@ using System.Web;
namespace Umbraco.Core.ObjectResolution
{
+ ///
+ /// A base class for lazily resolving types for a resolver
+ ///
+ ///
+ ///
+ ///
+ /// This is a special case resolver for when types get lazily resolved in order to resolve the actual types. This is useful
+ /// for when there is some processing overhead (i.e. Type finding in assemblies) to return the Types used to instantiate the instances.
+ /// In some these cases we don't want to have to type find during application startup, only when we need to resolve the instances.
+ ///
+ /// Important notes about this resolver: This does not support Insert or Remove and therefore does not support any ordering unless
+ /// the types are marked with the WeightedPluginAttribute.
+ ///
internal abstract class LazyManyObjectsResolverBase : ManyObjectsResolverBase
where TResolved : class
where TResolver : class
@@ -21,28 +34,62 @@ namespace Umbraco.Core.ObjectResolution
{
}
- protected LazyManyObjectsResolverBase(IEnumerable> value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
+ ///
+ /// Constructor accepting a list of lazy types
+ ///
+ ///
+ ///
+ protected LazyManyObjectsResolverBase(IEnumerable> listOfLazyTypes, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
: this(scope)
{
- AddTypes(value);
+ AddTypes(listOfLazyTypes);
}
- protected LazyManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable> value)
+ ///
+ /// Constructor accepting a delegate to return a list of types
+ ///
+ ///
+ ///
+ protected LazyManyObjectsResolverBase(Func> typeListDelegate, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
+ : this(scope)
+ {
+ _listOfTypeListDelegates.Add(typeListDelegate);
+ }
+
+ ///
+ /// Constructor accepting a list of lazy types
+ ///
+ ///
+ ///
+ protected LazyManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable> listOfLazyTypes)
: this(httpContext)
{
-
+ AddTypes(listOfLazyTypes);
+ }
+
+ ///
+ /// Constructor accepting a delegate to return a list of types
+ ///
+ ///
+ ///
+ protected LazyManyObjectsResolverBase(HttpContextBase httpContext, Func> typeListDelegate)
+ : this(httpContext)
+ {
+ _listOfTypeListDelegates.Add(typeListDelegate);
}
+
#endregion
- private readonly List> _lazyTypes = new List>();
- private bool _hasResolvedTypes = false;
+ private readonly List> _lazyTypeList = new List>();
+ private readonly List>> _listOfTypeListDelegates = new List>>();
+ private List _resolvedTypes = null;
///
/// Used for unit tests
///
internal bool HasResolvedTypes
{
- get { return _hasResolvedTypes; }
+ get { return _resolvedTypes != null; }
}
///
@@ -52,28 +99,50 @@ namespace Umbraco.Core.ObjectResolution
{
get
{
- var list = _lazyTypes.Select(x => x.Value).ToArray();
-
- //we need to validate each resolved type now since we could not do it before when inserting the lazy delegates
- if (!_hasResolvedTypes)
+ using (var lck = GetUpgradeableReadLock())
{
- var uniqueList = new List();
- foreach (var l in list)
- {
- EnsureCorrectType(l);
- if (uniqueList.Contains(l))
- {
- throw new InvalidOperationException("The Type " + l + " already exists in the collection");
- }
- uniqueList.Add(l);
- }
- _hasResolvedTypes = true;
- }
+ var lazyTypeList = _lazyTypeList.Select(x => x.Value).ToArray();
+ var listofTypeListDelegates = _listOfTypeListDelegates.SelectMany(x => x()).ToArray();
- return list;
+ //we need to validate each resolved type now since we could not do it before when inserting the lazy delegates
+ if (!HasResolvedTypes)
+ {
+ lck.UpgradeToWriteLock();
+
+ _resolvedTypes = new List();
+
+ //first iterate the lazy type list
+ foreach (var l in lazyTypeList)
+ {
+ UpdateUniqueList(_resolvedTypes, l);
+ }
+
+ //next iterate the list of list type delegates
+ foreach (var l in listofTypeListDelegates)
+ {
+ UpdateUniqueList(_resolvedTypes, l);
+ }
+ }
+
+ return _resolvedTypes;
+ }
}
}
+ private void UpdateUniqueList(List uniqueList, Type toAdd)
+ {
+ EnsureCorrectType(toAdd);
+ if (uniqueList.Contains(toAdd))
+ {
+ throw new InvalidOperationException("The Type " + toAdd + " already exists in the collection");
+ }
+ uniqueList.Add(toAdd);
+ }
+
+ ///
+ /// Allows adding of multiple lazy types at once
+ ///
+ ///
protected void AddTypes(IEnumerable> types)
{
EnsureAddSupport();
@@ -84,11 +153,27 @@ namespace Umbraco.Core.ObjectResolution
{
foreach (var t in types)
{
- _lazyTypes.Add(t);
+ _lazyTypeList.Add(t);
}
}
}
+ ///
+ /// Adds a type list delegate to the collection
+ ///
+ ///
+ public void AddTypeListDelegate(Func> typeListDelegate)
+ {
+ EnsureAddSupport();
+
+ EnsureResolutionNotFrozen();
+
+ using (GetWriteLock())
+ {
+ _listOfTypeListDelegates.Add(typeListDelegate);
+ }
+ }
+
///
/// Adds a lazy type to the list
///
@@ -101,7 +186,7 @@ namespace Umbraco.Core.ObjectResolution
using (GetWriteLock())
{
- _lazyTypes.Add(value);
+ _lazyTypeList.Add(value);
}
}
@@ -125,7 +210,7 @@ namespace Umbraco.Core.ObjectResolution
using (GetWriteLock())
{
- _lazyTypes.Clear();
+ _lazyTypeList.Clear();
}
}
diff --git a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs
index 9343b1a58b..c2fb584602 100644
--- a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs
+++ b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs
@@ -320,7 +320,16 @@ namespace Umbraco.Core.ObjectResolution
{
return new WriteLock(_lock);
}
-
+
+ ///
+ /// Returns an upgradeable read lock for use when reading/modifying collections
+ ///
+ ///
+ protected UpgradeableReadLock GetUpgradeableReadLock()
+ {
+ return new UpgradeableReadLock(_lock);
+ }
+
///
/// Throws an exception if resolution is frozen
///
diff --git a/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs b/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs
index 56ed107e68..977ddee355 100644
--- a/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs
+++ b/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
@@ -42,6 +43,58 @@ namespace Umbraco.Tests.Resolvers
Assert.IsTrue(instances1.Select(x => x.GetType()).ContainsAll(new []{typeof(TransientObject1), typeof(TransientObject2), typeof(TransientObject3)}));
}
+ [Test]
+ public void Type_List_Delegates_Combination()
+ {
+ Func> types = () => new[] { typeof(TransientObject3), typeof(TransientObject2) };
+
+ var resolver = new LazyResolver(types);
+ resolver.AddTypeListDelegate(() => new[] { typeof(TransientObject1)});
+
+ Resolution.Freeze();
+
+ var instances1 = resolver.Objects;
+
+ Assert.AreEqual(3, instances1.Count());
+ Assert.IsTrue(instances1.Select(x => x.GetType()).ContainsAll(new[] { typeof(TransientObject1), typeof(TransientObject2), typeof(TransientObject3) }));
+ }
+
+ [Test]
+ public void Type_List_Delegates_And_Lazy_Type_Combination()
+ {
+ Func> types = () => new[] { typeof(TransientObject3) };
+
+ var resolver = new LazyResolver(types);
+ resolver.AddType(new Lazy(() => typeof(TransientObject2)));
+ resolver.AddType();
+
+ Resolution.Freeze();
+
+ var instances1 = resolver.Objects;
+
+ Assert.AreEqual(3, instances1.Count());
+ Assert.IsTrue(instances1.Select(x => x.GetType()).ContainsAll(new[] { typeof(TransientObject1), typeof(TransientObject2), typeof(TransientObject3) }));
+ }
+
+ [Test]
+ public void Throws_If_Duplication()
+ {
+ Func> types = () => new[] { typeof(TransientObject3), typeof(TransientObject2), typeof(TransientObject1) };
+
+ var resolver = new LazyResolver(types);
+ //duplicate, but will not throw here
+ resolver.AddType();
+
+ Resolution.Freeze();
+
+ Assert.Throws(() =>
+ {
+ var instances = resolver.Objects;
+ });
+
+
+ }
+
#region Test classes
private interface ITestInterface
@@ -73,6 +126,12 @@ namespace Umbraco.Tests.Resolvers
}
+ public LazyResolver(Func> typeList)
+ : base(typeList, ObjectLifetimeScope.Transient)
+ {
+
+ }
+
public IEnumerable Objects
{
get { return Values; }