2012-07-31 01:06:10 +06:00
using System ;
2012-07-27 05:52:01 +06:00
using System.Collections.Generic ;
using System.Threading ;
2012-08-01 09:49:10 +06:00
using System.Web ;
2012-07-27 05:52:01 +06:00
namespace Umbraco.Core.Resolving
{
2012-08-01 22:06:15 +06:00
internal abstract class ManyObjectsResolverBase < TResolver , TResolved > : ResolverBase < TResolver >
where TResolved : class
where TResolver : class
2012-07-27 05:52:01 +06:00
{
2012-08-01 09:49:10 +06:00
private List < TResolved > _applicationInstances = null ;
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim ( ) ;
#region Constructors
/// <summary>
2012-08-01 22:06:15 +06:00
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects.
2012-08-01 09:49:10 +06:00
/// </summary>
2012-08-01 10:48:19 +06:00
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application</param>
2012-08-01 11:24:39 +06:00
protected ManyObjectsResolverBase ( ObjectLifetimeScope scope = ObjectLifetimeScope . Application )
2012-08-01 09:49:10 +06:00
{
2012-08-01 10:48:19 +06:00
if ( scope = = ObjectLifetimeScope . HttpRequest )
{
if ( HttpContext . Current = = null )
{
throw new InvalidOperationException ( "Use alternative constructor accepting a HttpContextBase object in order to set the lifetime scope to HttpRequest when HttpContext.Current is null" ) ;
}
CurrentHttpContext = new HttpContextWrapper ( HttpContext . Current ) ;
}
LifetimeScope = scope ;
2012-08-01 09:49:10 +06:00
InstanceTypes = new List < Type > ( ) ;
}
2012-07-27 05:52:01 +06:00
2012-07-27 14:06:41 -02:00
/// <summary>
2012-08-01 22:06:15 +06:00
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects.
2012-08-01 09:49:10 +06:00
/// with creation of objects based on an HttpRequest lifetime scope.
2012-07-27 14:06:41 -02:00
/// </summary>
2012-08-01 09:49:10 +06:00
/// <param name="httpContext"></param>
2012-08-01 11:24:39 +06:00
protected ManyObjectsResolverBase ( HttpContextBase httpContext )
2012-07-27 05:52:01 +06:00
{
2012-08-01 10:48:19 +06:00
LifetimeScope = ObjectLifetimeScope . HttpRequest ;
2012-08-01 09:49:10 +06:00
CurrentHttpContext = httpContext ;
2012-08-01 10:48:19 +06:00
InstanceTypes = new List < Type > ( ) ;
2012-07-27 05:52:01 +06:00
}
2012-07-27 14:06:41 -02:00
/// <summary>
2012-08-01 22:06:15 +06:00
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of objects.
2012-07-27 14:06:41 -02:00
/// </summary>
2012-07-31 01:06:10 +06:00
/// <param name="value">The list of objects.</param>
2012-08-01 10:48:19 +06:00
/// <param name="scope">If set to true will resolve singleton objects which will be created once for the lifetime of the application</param>
2012-08-01 11:24:39 +06:00
protected ManyObjectsResolverBase ( IEnumerable < Type > value , ObjectLifetimeScope scope = ObjectLifetimeScope . Application )
2012-08-01 10:48:19 +06:00
: this ( scope )
{
2012-08-01 09:49:10 +06:00
InstanceTypes = new List < Type > ( value ) ;
2012-07-27 14:06:41 -02:00
}
2012-07-27 05:52:01 +06:00
2012-07-27 14:06:41 -02:00
/// <summary>
2012-08-01 22:06:15 +06:00
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of objects
2012-08-01 09:49:10 +06:00
/// with creation of objects based on an HttpRequest lifetime scope.
/// </summary>
/// <param name="httpContext"></param>
/// <param name="value"></param>
2012-08-01 11:24:39 +06:00
protected ManyObjectsResolverBase ( HttpContextBase httpContext , IEnumerable < Type > value )
2012-08-01 10:48:19 +06:00
: this ( httpContext )
2012-08-01 09:49:10 +06:00
{
2012-08-01 10:48:19 +06:00
InstanceTypes = new List < Type > ( value ) ;
2012-08-01 09:49:10 +06:00
}
#endregion
/// <summary>
/// Returns the list of Types registered that instances will be created from
/// </summary>
protected List < Type > InstanceTypes { get ; private set ; }
/// <summary>
/// Returns the Current HttpContextBase used to construct this object if one exists.
/// If one exists then the LifetimeScope will be ObjectLifetimeScope.HttpRequest
/// </summary>
protected HttpContextBase CurrentHttpContext { get ; private set ; }
/// <summary>
/// Returns the ObjectLifetimeScope for created objects
/// </summary>
2012-08-01 10:48:19 +06:00
protected ObjectLifetimeScope LifetimeScope { get ; private set ; }
2012-08-01 09:49:10 +06:00
/// <summary>
/// Returns the list of new object instances.
2012-07-27 14:06:41 -02:00
/// </summary>
protected IEnumerable < TResolved > Values
2012-07-27 05:52:01 +06:00
{
2012-08-01 09:49:10 +06:00
get
2012-08-01 10:15:39 +06:00
{
2012-08-01 22:06:15 +06:00
//We cannot return values unless resolution is locked
if ( ! Resolution . IsFrozen )
throw new InvalidOperationException ( "Values cannot be returned until Resolution is frozen" ) ;
2012-08-01 09:49:10 +06:00
switch ( LifetimeScope )
{
case ObjectLifetimeScope . HttpRequest :
//create new instances per HttpContext, this means we'll lazily create them and once created, cache them in the HttpContext
//create new instances per application, this means we'll lazily create them and once created, cache them
using ( var l = new UpgradeableReadLock ( _lock ) )
{
//check if the items contain the key (based on the full type name)
if ( CurrentHttpContext . Items [ this . GetType ( ) . FullName ] = = null )
{
l . UpgradeToWriteLock ( ) ;
//add the items to the context items (based on full type name)
CurrentHttpContext . Items [ this . GetType ( ) . FullName ] = new List < TResolved > (
2012-08-01 22:06:15 +06:00
PluginManager . Current . CreateInstances < TResolved > ( InstanceTypes ) ) ;
2012-08-01 09:49:10 +06:00
}
2012-08-01 10:48:19 +06:00
return ( List < TResolved > ) CurrentHttpContext . Items [ this . GetType ( ) . FullName ] ;
2012-08-01 09:49:10 +06:00
}
case ObjectLifetimeScope . Application :
//create new instances per application, this means we'll lazily create them and once created, cache them
using ( var l = new UpgradeableReadLock ( _lock ) )
{
if ( _applicationInstances = = null )
{
l . UpgradeToWriteLock ( ) ;
_applicationInstances = new List < TResolved > (
2012-08-01 22:06:15 +06:00
PluginManager . Current . CreateInstances < TResolved > ( InstanceTypes ) ) ;
2012-08-01 09:49:10 +06:00
}
return _applicationInstances ;
}
case ObjectLifetimeScope . Transient :
default :
//create new instances each time
2012-08-01 22:06:15 +06:00
return PluginManager . Current . CreateInstances < TResolved > ( InstanceTypes ) ;
2012-08-01 09:49:10 +06:00
}
}
2012-07-27 05:52:01 +06:00
}
2012-07-27 14:06:41 -02:00
/// <summary>
2012-08-01 09:49:10 +06:00
/// Removes a type.
2012-07-27 14:06:41 -02:00
/// </summary>
2012-08-01 09:49:10 +06:00
/// <param name="value">The type to remove.</param>
2012-08-01 10:48:19 +06:00
public void RemoveType ( Type value )
2012-08-01 10:15:39 +06:00
{
2012-08-01 09:49:10 +06:00
EnsureCorrectType ( value ) ;
using ( new WriteLock ( _lock ) )
{
InstanceTypes . Remove ( value ) ;
2012-07-27 05:52:01 +06:00
}
}
2012-07-27 14:06:41 -02:00
/// <summary>
2012-08-01 09:49:10 +06:00
/// Removes a type.
/// </summary>
/// <typeparam name="T"></typeparam>
2012-08-01 10:48:19 +06:00
public void RemoveType < T > ( )
2012-08-01 09:49:10 +06:00
{
2012-08-01 10:48:19 +06:00
RemoveType ( typeof ( T ) ) ;
2012-08-01 09:49:10 +06:00
}
/// <summary>
/// Adds a Type to the end of the list.
2012-07-27 14:06:41 -02:00
/// </summary>
/// <param name="value">The object to be added.</param>
2012-08-01 10:48:19 +06:00
public void AddType ( Type value )
2012-07-27 05:52:01 +06:00
{
2012-08-01 09:49:10 +06:00
EnsureCorrectType ( value ) ;
using ( var l = new UpgradeableReadLock ( _lock ) )
2012-07-27 05:52:01 +06:00
{
2012-08-01 09:49:10 +06:00
if ( InstanceTypes . Contains ( value ) )
2012-07-31 01:06:10 +06:00
{
2012-08-01 09:49:10 +06:00
throw new InvalidOperationException ( "The Type " + value + " already exists in the collection" ) ;
2012-07-31 01:06:10 +06:00
} ;
2012-08-01 09:49:10 +06:00
2012-07-31 01:06:10 +06:00
l . UpgradeToWriteLock ( ) ;
2012-08-01 09:49:10 +06:00
InstanceTypes . Add ( value ) ;
2012-07-27 06:02:41 +06:00
}
2012-07-27 05:52:01 +06:00
}
2012-08-01 09:49:10 +06:00
/// <summary>
/// Adds a Type to the end of the list.
/// </summary>
/// <typeparam name="T"></typeparam>
2012-08-01 10:48:19 +06:00
public void AddType < T > ( )
2012-08-01 09:49:10 +06:00
{
2012-08-01 10:48:19 +06:00
AddType ( typeof ( T ) ) ;
2012-08-01 09:49:10 +06:00
}
2012-07-27 14:06:41 -02:00
/// <summary>
/// Clears the list.
/// </summary>
2012-07-27 05:52:01 +06:00
public void Clear ( )
{
2012-08-01 09:49:10 +06:00
using ( new WriteLock ( _lock ) )
2012-07-27 05:52:01 +06:00
{
2012-08-01 09:49:10 +06:00
InstanceTypes . Clear ( ) ;
2012-07-27 06:02:41 +06:00
}
2012-07-27 05:52:01 +06:00
}
2012-07-27 14:06:41 -02:00
/// <summary>
2012-08-01 09:49:10 +06:00
/// Inserts a Type at the specified index.
2012-07-27 14:06:41 -02:00
/// </summary>
/// <param name="index">The zero-based index at which the object should be inserted.</param>
/// <param name="value">The object to insert.</param>
2012-08-01 10:48:19 +06:00
public void InsertType ( int index , Type value )
2012-07-27 05:52:01 +06:00
{
2012-08-01 09:49:10 +06:00
EnsureCorrectType ( value ) ;
using ( var l = new UpgradeableReadLock ( _lock ) )
2012-07-27 05:52:01 +06:00
{
2012-08-01 09:49:10 +06:00
if ( InstanceTypes . Contains ( value ) )
2012-07-31 01:06:10 +06:00
{
2012-08-01 09:49:10 +06:00
throw new InvalidOperationException ( "The Type " + value + " already exists in the collection" ) ;
2012-07-31 01:06:10 +06:00
} ;
l . UpgradeToWriteLock ( ) ;
2012-08-01 09:49:10 +06:00
InstanceTypes . Insert ( index , value ) ;
2012-07-27 06:02:41 +06:00
}
2012-07-27 05:52:01 +06:00
}
2012-08-01 09:49:10 +06:00
/// <summary>
/// Inserts a Type at the specified index.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="index"></param>
2012-08-01 10:48:19 +06:00
public void InsertType < T > ( int index )
2012-08-01 09:49:10 +06:00
{
2012-08-01 10:48:19 +06:00
InsertType ( index , typeof ( T ) ) ;
2012-08-01 09:49:10 +06:00
}
private void EnsureCorrectType ( Type t )
{
if ( ! TypeHelper . IsTypeAssignableFrom < TResolved > ( t ) )
throw new InvalidOperationException ( "The resolver " + this . GetType ( ) + " can only accept types of " + typeof ( TResolved ) + ". The Type passed in to this method is " + t ) ;
}
2012-07-27 05:52:01 +06:00
}
}