2013-01-23 07:45:00 +03:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2013-01-23 18:40:40 +03:00
|
|
|
using System.Threading;
|
2013-01-23 07:45:00 +03:00
|
|
|
using System.Web;
|
|
|
|
|
|
|
|
|
|
namespace Umbraco.Core.ObjectResolution
|
|
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
/// <summary>
|
|
|
|
|
/// The base class for all lazy many-objects resolvers.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="TResolver">The type of the concrete resolver class.</typeparam>
|
|
|
|
|
/// <typeparam name="TResolved">The type of the resolved objects.</typeparam>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// <para>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.</para>
|
|
|
|
|
/// <para>Important notes about this resolver: it does not support Insert or Remove and therefore does not support any ordering unless
|
|
|
|
|
/// the types are marked with the WeightedPluginAttribute.</para>
|
2013-01-23 17:39:07 +03:00
|
|
|
/// </remarks>
|
2013-01-23 07:45:00 +03:00
|
|
|
internal abstract class LazyManyObjectsResolverBase<TResolver, TResolved> : ManyObjectsResolverBase<TResolver, TResolved>
|
|
|
|
|
where TResolved : class
|
2013-03-12 01:50:56 +04:00
|
|
|
where TResolver : ResolverBase
|
2013-01-23 07:45:00 +03:00
|
|
|
{
|
|
|
|
|
#region Constructors
|
|
|
|
|
|
2013-01-23 16:44:38 -01:00
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects,
|
|
|
|
|
/// with creation of objects based on an HttpRequest lifetime scope.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application.</param>
|
|
|
|
|
/// <remarks>If <paramref name="scope"/> is per HttpRequest then there must be a current HttpContext.</remarks>
|
|
|
|
|
/// <exception cref="InvalidOperationException"><paramref name="scope"/> is per HttpRequest but the current HttpContext is null.</exception>
|
2013-01-23 07:45:00 +03:00
|
|
|
protected LazyManyObjectsResolverBase(ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
|
|
|
|
: base(scope)
|
2013-01-23 16:44:38 -01:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects,
|
|
|
|
|
/// with creation of objects based on an HttpRequest lifetime scope.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="httpContext">The HttpContextBase corresponding to the HttpRequest.</param>
|
|
|
|
|
/// <exception cref="ArgumentNullException"><paramref name="httpContext"/> is <c>null</c>.</exception>
|
2013-01-23 07:45:00 +03:00
|
|
|
protected LazyManyObjectsResolverBase(HttpContextBase httpContext)
|
|
|
|
|
: base(httpContext)
|
2013-01-23 16:44:38 -01:00
|
|
|
{ }
|
2013-01-23 07:45:00 +03:00
|
|
|
|
2013-01-23 16:44:38 -01:00
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list
|
|
|
|
|
/// <remarks>If <paramref name="scope"/> is per HttpRequest then there must be a current HttpContext.</remarks>
|
|
|
|
|
/// <exception cref="InvalidOperationException"><paramref name="scope"/> is per HttpRequest but the current HttpContext is null.</exception>
|
|
|
|
|
protected LazyManyObjectsResolverBase(IEnumerable<Lazy<Type>> lazyTypeList, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
2013-01-23 07:45:00 +03:00
|
|
|
: this(scope)
|
|
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
AddTypes(lazyTypeList);
|
2013-01-23 17:39:07 +03:00
|
|
|
}
|
|
|
|
|
|
2013-01-23 16:44:38 -01:00
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list
|
|
|
|
|
/// of functions producing types, and an optional lifetime scope.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="typeListProducerList">The list of functions producing types.</param>
|
|
|
|
|
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application.</param>
|
|
|
|
|
/// <remarks>If <paramref name="scope"/> is per HttpRequest then there must be a current HttpContext.</remarks>
|
|
|
|
|
/// <exception cref="InvalidOperationException"><paramref name="scope"/> is per HttpRequest but the current HttpContext is null.</exception>
|
|
|
|
|
protected LazyManyObjectsResolverBase(Func<IEnumerable<Type>> typeListProducerList, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
2013-01-23 17:39:07 +03:00
|
|
|
: this(scope)
|
|
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
_typeListProducerList.Add(typeListProducerList);
|
2013-01-23 17:39:07 +03:00
|
|
|
}
|
|
|
|
|
|
2013-01-23 16:44:38 -01:00
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of
|
|
|
|
|
/// lazy object types, with creation of objects based on an HttpRequest lifetime scope.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="httpContext">The HttpContextBase corresponding to the HttpRequest.</param>
|
|
|
|
|
/// <param name="lazyTypeList">The list of lazy object types.</param>
|
|
|
|
|
/// <exception cref="ArgumentNullException"><paramref name="httpContext"/> is <c>null</c>.</exception>
|
|
|
|
|
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable<Lazy<Type>> lazyTypeList)
|
2013-01-23 17:39:07 +03:00
|
|
|
: this(httpContext)
|
|
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
AddTypes(lazyTypeList);
|
2013-01-23 07:45:00 +03:00
|
|
|
}
|
|
|
|
|
|
2013-01-23 16:44:38 -01:00
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of
|
|
|
|
|
/// functions producing types, with creation of objects based on an HttpRequest lifetime scope.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="httpContext">The HttpContextBase corresponding to the HttpRequest.</param>
|
|
|
|
|
/// <param name="typeListProducerList">The list of functions producing types.</param>
|
|
|
|
|
/// <exception cref="ArgumentNullException"><paramref name="httpContext"/> is <c>null</c>.</exception>
|
|
|
|
|
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, Func<IEnumerable<Type>> typeListProducerList)
|
2013-01-23 07:45:00 +03:00
|
|
|
: this(httpContext)
|
|
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
_typeListProducerList.Add(typeListProducerList);
|
2013-01-23 07:45:00 +03:00
|
|
|
}
|
2013-01-23 17:39:07 +03:00
|
|
|
|
2013-01-23 07:45:00 +03:00
|
|
|
#endregion
|
|
|
|
|
|
2013-01-23 17:39:07 +03:00
|
|
|
private readonly List<Lazy<Type>> _lazyTypeList = new List<Lazy<Type>>();
|
2013-01-23 16:44:38 -01:00
|
|
|
private readonly List<Func<IEnumerable<Type>>> _typeListProducerList = new List<Func<IEnumerable<Type>>>();
|
2013-02-06 13:03:44 -01:00
|
|
|
private readonly List<Type> _excludedTypesList = new List<Type>();
|
2013-01-23 16:44:38 -01:00
|
|
|
|
2013-01-23 17:39:07 +03:00
|
|
|
private List<Type> _resolvedTypes = null;
|
2013-01-23 16:44:38 -01:00
|
|
|
private readonly ReaderWriterLockSlim _resolvedTypesLock = new ReaderWriterLockSlim();
|
2013-01-23 07:45:00 +03:00
|
|
|
|
|
|
|
|
/// <summary>
|
2013-01-23 16:44:38 -01:00
|
|
|
/// Gets a value indicating whether the resolver has resolved types to create instances from.
|
2013-01-23 07:45:00 +03:00
|
|
|
/// </summary>
|
2013-01-23 16:44:38 -01:00
|
|
|
/// <remarks>To be used in unit tests.</remarks>
|
2013-01-23 07:45:00 +03:00
|
|
|
internal bool HasResolvedTypes
|
|
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
using (new ReadLock(_resolvedTypesLock))
|
|
|
|
|
{
|
|
|
|
|
return _resolvedTypes != null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-01-23 07:45:00 +03:00
|
|
|
}
|
|
|
|
|
|
2013-01-23 16:44:38 -01:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the list of types to create instances from.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>When called, will get the types from the lazy list.</remarks>
|
|
|
|
|
protected override IEnumerable<Type> InstanceTypes
|
2013-01-23 07:45:00 +03:00
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
using (var lck = new UpgradeableReadLock(_resolvedTypesLock))
|
2013-01-23 07:45:00 +03:00
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
if (_resolvedTypes == null)
|
2013-01-23 07:45:00 +03:00
|
|
|
{
|
2013-02-06 09:53:13 +06:00
|
|
|
lck.UpgradeToWriteLock();
|
|
|
|
|
|
|
|
|
|
_resolvedTypes = new List<Type>();
|
|
|
|
|
|
2013-01-23 16:44:38 -01:00
|
|
|
// get the types by evaluating the lazy & producers
|
|
|
|
|
var types = new List<Type>();
|
|
|
|
|
types.AddRange(_lazyTypeList.Select(x => x.Value));
|
|
|
|
|
types.AddRange(_typeListProducerList.SelectMany(x => x()));
|
|
|
|
|
|
|
|
|
|
// we need to validate each resolved type now since we could
|
|
|
|
|
// not do it before evaluating the lazy & producers
|
2013-02-06 13:03:44 -01:00
|
|
|
foreach (var type in types.Where(x => !_excludedTypesList.Contains(x)))
|
2013-02-06 09:53:13 +06:00
|
|
|
{
|
|
|
|
|
AddValidAndNoDuplicate(_resolvedTypes, type);
|
|
|
|
|
}
|
2013-01-23 07:45:00 +03:00
|
|
|
}
|
|
|
|
|
|
2013-01-23 17:39:07 +03:00
|
|
|
return _resolvedTypes;
|
|
|
|
|
}
|
2013-01-23 07:45:00 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-06 09:53:13 +06:00
|
|
|
/// <summary>
|
|
|
|
|
/// Ensures that type is valid and not a duplicate
|
|
|
|
|
/// then appends the type to the end of the list
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="list"></param>
|
|
|
|
|
/// <param name="type"></param>
|
2013-01-23 16:44:38 -01:00
|
|
|
private void AddValidAndNoDuplicate(List<Type> list, Type type)
|
2013-01-23 17:39:07 +03:00
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
EnsureCorrectType(type);
|
|
|
|
|
if (list.Contains(type))
|
2013-01-23 17:39:07 +03:00
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
throw new InvalidOperationException(string.Format(
|
|
|
|
|
"Type {0} is already in the collection of types.", type.FullName));
|
|
|
|
|
}
|
|
|
|
|
list.Add(type);
|
2013-01-23 17:39:07 +03:00
|
|
|
}
|
|
|
|
|
|
2013-01-23 16:44:38 -01:00
|
|
|
#region Types collection manipulation
|
|
|
|
|
|
2013-02-06 09:53:13 +06:00
|
|
|
/// <summary>
|
2013-02-06 13:03:44 -01:00
|
|
|
/// Removes types from the list of types, once it has been lazily evaluated, and before actual objects are instanciated.
|
2013-02-06 09:53:13 +06:00
|
|
|
/// </summary>
|
2013-02-06 13:03:44 -01:00
|
|
|
/// <param name="value">The type to remove.</param>
|
2013-02-06 09:53:13 +06:00
|
|
|
public override void RemoveType(Type value)
|
|
|
|
|
{
|
|
|
|
|
EnsureSupportsRemove();
|
|
|
|
|
|
2013-02-06 13:03:44 -01:00
|
|
|
_excludedTypesList.Add(value);
|
2013-02-06 09:53:13 +06:00
|
|
|
}
|
|
|
|
|
|
2013-01-23 16:44:38 -01:00
|
|
|
/// <summary>
|
|
|
|
|
/// Lazily adds types from lazy types.
|
2013-01-23 17:39:07 +03:00
|
|
|
/// </summary>
|
2013-01-23 16:44:38 -01:00
|
|
|
/// <param name="types">The lazy types, to add.</param>
|
2013-01-23 07:45:00 +03:00
|
|
|
protected void AddTypes(IEnumerable<Lazy<Type>> types)
|
|
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
EnsureSupportsAdd();
|
2013-01-23 07:45:00 +03:00
|
|
|
|
2013-01-16 13:31:04 -01:00
|
|
|
using (Resolution.Configuration)
|
|
|
|
|
using (GetWriteLock())
|
2013-01-23 07:45:00 +03:00
|
|
|
{
|
|
|
|
|
foreach (var t in types)
|
|
|
|
|
{
|
2013-01-23 17:39:07 +03:00
|
|
|
_lazyTypeList.Add(t);
|
2013-01-23 07:45:00 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-23 17:39:07 +03:00
|
|
|
/// <summary>
|
2013-01-23 16:44:38 -01:00
|
|
|
/// Lazily adds types from a function producing types.
|
2013-01-23 17:39:07 +03:00
|
|
|
/// </summary>
|
2013-01-23 16:44:38 -01:00
|
|
|
/// <param name="typeListProducer">The functions producing types, to add.</param>
|
|
|
|
|
public void AddTypeListDelegate(Func<IEnumerable<Type>> typeListProducer)
|
2013-01-23 17:39:07 +03:00
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
EnsureSupportsAdd();
|
2013-01-23 17:39:07 +03:00
|
|
|
|
2013-01-16 13:31:04 -01:00
|
|
|
using (Resolution.Configuration)
|
|
|
|
|
using (GetWriteLock())
|
2013-01-23 17:39:07 +03:00
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
_typeListProducerList.Add(typeListProducer);
|
2013-01-23 17:39:07 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-23 07:45:00 +03:00
|
|
|
/// <summary>
|
2013-01-23 16:44:38 -01:00
|
|
|
/// Lazily adds a type from a lazy type.
|
2013-01-23 07:45:00 +03:00
|
|
|
/// </summary>
|
2013-01-23 16:44:38 -01:00
|
|
|
/// <param name="value">The lazy type, to add.</param>
|
2013-01-23 07:45:00 +03:00
|
|
|
public void AddType(Lazy<Type> value)
|
|
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
EnsureSupportsAdd();
|
2013-01-23 07:45:00 +03:00
|
|
|
|
2013-01-16 13:31:04 -01:00
|
|
|
using (Resolution.Configuration)
|
|
|
|
|
using (GetWriteLock())
|
2013-01-23 07:45:00 +03:00
|
|
|
{
|
2013-01-23 17:39:07 +03:00
|
|
|
_lazyTypeList.Add(value);
|
2013-01-23 07:45:00 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2013-01-23 16:44:38 -01:00
|
|
|
/// Lazily adds a type from an actual type.
|
2013-01-23 07:45:00 +03:00
|
|
|
/// </summary>
|
2013-02-06 09:53:13 +06:00
|
|
|
/// <param name="value">The actual type, to add.</param>
|
2013-01-23 16:44:38 -01:00
|
|
|
/// <remarks>The type is converted to a lazy type.</remarks>
|
2013-01-23 07:45:00 +03:00
|
|
|
public override void AddType(Type value)
|
|
|
|
|
{
|
|
|
|
|
AddType(new Lazy<Type>(() => value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Clears all lazy types
|
|
|
|
|
/// </summary>
|
|
|
|
|
public override void Clear()
|
|
|
|
|
{
|
2013-01-23 16:44:38 -01:00
|
|
|
EnsureSupportsClear();
|
2013-01-23 07:45:00 +03:00
|
|
|
|
2013-01-16 13:31:04 -01:00
|
|
|
using (Resolution.Configuration)
|
|
|
|
|
using (GetWriteLock())
|
2013-01-23 07:45:00 +03:00
|
|
|
{
|
2013-01-23 17:39:07 +03:00
|
|
|
_lazyTypeList.Clear();
|
2013-01-23 07:45:00 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-23 16:44:38 -01:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Types collection manipulation support
|
|
|
|
|
|
2013-01-23 07:45:00 +03:00
|
|
|
/// <summary>
|
2013-01-23 16:44:38 -01:00
|
|
|
/// Gets a <c>false</c> value indicating that the resolver does NOT support inserting types.
|
2013-01-23 07:45:00 +03:00
|
|
|
/// </summary>
|
|
|
|
|
protected override bool SupportsInsert
|
|
|
|
|
{
|
|
|
|
|
get { return false; }
|
2013-01-23 16:44:38 -01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
2013-01-23 07:45:00 +03:00
|
|
|
}
|