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 09:49:10 +06:00
internal abstract class ManyObjectResolverBase < TResolved >
2012-07-27 05:52:01 +06:00
where TResolved : class
{
2012-08-01 09:49:10 +06:00
private readonly bool _instancePerApplication = false ;
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 09:49:10 +06:00
/// Initializes a new instance of the <see cref="ManyObjectResolverBase{TResolved}"/> class with an empty list of objects.
2012-07-27 14:06:41 -02:00
/// </summary>
2012-08-01 09:49:10 +06:00
/// <param name="instancePerApplication">If set to true will resolve singleton objects which will be created once for the lifetime of the application</param>
protected ManyObjectResolverBase ( bool instancePerApplication = true )
2012-07-27 05:52:01 +06:00
{
2012-08-01 09:49:10 +06:00
_instancePerApplication = instancePerApplication ;
InstanceTypes = new List < Type >();
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
/// Initializes a new instance of the <see cref="ManyObjectResolverBase{TResolved}"/> class with an initial list of objects
/// with creation of objects based on an HttpRequest lifetime scope.
/// </summary>
/// <param name="httpContext"></param>
protected ManyObjectResolverBase ( HttpContextBase httpContext )
: this ( false )
{
CurrentHttpContext = httpContext ;
}
/// <summary>
/// Initializes a new instance of the <see cref="ManyObjectResolverBase{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 09:49:10 +06:00
/// <param name="instancePerApplication">If set to true will resolve singleton objects which will be created once for the lifetime of the application</param>
protected ManyObjectResolverBase ( IEnumerable < Type > value , bool instancePerApplication = true )
2012-07-27 05:52:01 +06:00
{
2012-08-01 09:49:10 +06:00
_instancePerApplication = instancePerApplication ;
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 09:49:10 +06:00
/// Initializes a new instance of the <see cref="ManyObjectResolverBase{TResolved}"/> class with an empty list of objects
/// with creation of objects based on an HttpRequest lifetime scope.
/// </summary>
/// <param name="httpContext"></param>
/// <param name="value"></param>
protected ManyObjectResolverBase ( HttpContextBase httpContext , IEnumerable < Type > value )
: this ( value , false )
{
CurrentHttpContext = httpContext ;
}
#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>
protected ObjectLifetimeScope LifetimeScope
{
get
{
if ( _instancePerApplication )
return ObjectLifetimeScope . Application ;
if ( CurrentHttpContext != null )
return ObjectLifetimeScope . HttpRequest ;
return ObjectLifetimeScope . Transient ;
}
}
/// <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
{
//we should not allow the returning/creating of objects if resolution is not yet frozen!
if ( Resolution . IsFrozen )
throw new InvalidOperationException ( "Resolution is not frozen. It is not possible to instantiate and returng objects until resolution is frozen." );
2012-07-27 05:52:01 +06:00
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 >(
PluginTypeResolver . Current . CreateInstances < TResolved >( InstanceTypes ));
}
return _applicationInstances ;
}
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 >(
PluginTypeResolver . Current . CreateInstances < TResolved >( InstanceTypes ));
}
return _applicationInstances ;
}
case ObjectLifetimeScope . Transient :
default :
//create new instances each time
return PluginTypeResolver . Current . CreateInstances < TResolved >( InstanceTypes );
}
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>
/// <param name="value">The type to remove.</param>
public void Remove ( Type value )
{
Resolution . EnsureNotFrozen ();
EnsureCorrectType ( value );
using ( new WriteLock ( _lock ))
{
InstanceTypes . Remove ( value );
}
}
/// <summary>
/// Removes a type.
/// </summary>
/// <typeparam name="T"></typeparam>
public void Remove < T >()
{
Remove ( typeof ( T ));
}
/// <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 09:49:10 +06:00
public void Add ( Type value )
2012-07-27 05:52:01 +06:00
{
Resolution . EnsureNotFrozen ();
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>
public void Add < T >()
{
Add ( typeof ( T ));
}
2012-07-27 14:06:41 -02:00
/// <summary>
/// Clears the list.
/// </summary>
2012-07-27 05:52:01 +06:00
public void Clear ()
{
Resolution . EnsureNotFrozen ();
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 09:49:10 +06:00
public void Insert ( int index , Type value )
2012-07-27 05:52:01 +06:00
{
Resolution . EnsureNotFrozen ();
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>
public void Insert < T >( int index )
{
Insert ( index , typeof ( T ));
}
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
}
}