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
2012-08-10 13:18:13 +06:00
namespace Umbraco.Core.ObjectResolution
2012-07-27 05:52:01 +06:00
{
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
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-07-27 14:06:41 -02: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-07-27 05:52:01 +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-08-01 10:48:19 +06: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 10:48:19 +06:00
/// with creation of objects based on an HttpRequest lifetime scope.
/// </summary>
/// <param name="httpContext"></param>
2012-08-01 11:24:39 +06:00
protected ManyObjectsResolverBase ( HttpContextBase httpContext )
2012-08-01 10:48:19 +06:00
{
LifetimeScope = ObjectLifetimeScope . HttpRequest ;
CurrentHttpContext = httpContext ;
InstanceTypes = new List < Type >();
}
/// <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 10:48:19 +06:00
/// </summary>
/// <param name="value">The list of objects.</param>
/// <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 )
{
InstanceTypes = new List < Type >( value );
}
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)
2012-08-01 23:30:37 +06:00
CurrentHttpContext . Items [ this . GetType (). FullName ] = new List < TResolved >( CreateInstances ());
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 ();
2012-08-01 23:30:37 +06:00
_applicationInstances = new List < TResolved >( CreateInstances ());
2012-08-01 09:49:10 +06:00
}
return _applicationInstances ;
}
case ObjectLifetimeScope . Transient :
default :
//create new instances each time
2012-08-01 23:30:37 +06:00
return CreateInstances ();
2012-08-01 09:49:10 +06:00
}
2012-07-27 05:52:01 +06:00
}
}
2012-08-01 23:30:37 +06:00
protected virtual IEnumerable < TResolved > CreateInstances ()
{
return PluginManager . Current . CreateInstances < TResolved >( InstanceTypes );
}
2012-07-27 14:06:41 -02:00
/// <summary>
2012-08-01 09:49:10 +06:00
/// Removes a type.
/// </summary>
/// <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 );
}
}
/// <summary>
/// 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
}
}