Files
Umbraco-CMS/src/Umbraco.Core/Resolving/ManyObjectsResolverBase.cs
shannon@ShandemVaio 646e96ab15 Changed PluginResolverType to PluginManager. Reinstated Resolution and ResolverBase<T> since
this gives us more control over all Resolvers and streamlines them. Created IBootManager, CoreBootManager and WebBootManager
to handle the application initialization including the creation of Resolvers. This means that if people are using the dlls outside
of the web app, they can run the boot strappers to initialize everything.
2012-08-01 22:06:15 +06:00

233 lines
7.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading;
using System.Web;
namespace Umbraco.Core.Resolving
{
internal abstract class ManyObjectsResolverBase<TResolver, TResolved> : ResolverBase<TResolver>
where TResolved : class
where TResolver : class
{
private List<TResolved> _applicationInstances = null;
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects.
/// </summary>
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application</param>
protected ManyObjectsResolverBase(ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
{
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;
InstanceTypes = new List<Type>();
}
/// <summary>
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects.
/// with creation of objects based on an HttpRequest lifetime scope.
/// </summary>
/// <param name="httpContext"></param>
protected ManyObjectsResolverBase(HttpContextBase httpContext)
{
LifetimeScope = ObjectLifetimeScope.HttpRequest;
CurrentHttpContext = httpContext;
InstanceTypes = new List<Type>();
}
/// <summary>
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of objects.
/// </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>
protected ManyObjectsResolverBase(IEnumerable<Type> value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
: this(scope)
{
InstanceTypes = new List<Type>(value);
}
/// <summary>
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of objects
/// with creation of objects based on an HttpRequest lifetime scope.
/// </summary>
/// <param name="httpContext"></param>
/// <param name="value"></param>
protected ManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable<Type> value)
: this(httpContext)
{
InstanceTypes = new List<Type>(value);
}
#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; private set; }
/// <summary>
/// Returns the list of new object instances.
/// </summary>
protected IEnumerable<TResolved> Values
{
get
{
//We cannot return values unless resolution is locked
if (!Resolution.IsFrozen)
throw new InvalidOperationException("Values cannot be returned until Resolution is frozen");
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>(
PluginManager.Current.CreateInstances<TResolved>(InstanceTypes));
}
return (List<TResolved>)CurrentHttpContext.Items[this.GetType().FullName];
}
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>(
PluginManager.Current.CreateInstances<TResolved>(InstanceTypes));
}
return _applicationInstances;
}
case ObjectLifetimeScope.Transient:
default:
//create new instances each time
return PluginManager.Current.CreateInstances<TResolved>(InstanceTypes);
}
}
}
/// <summary>
/// Removes a type.
/// </summary>
/// <param name="value">The type to remove.</param>
public void RemoveType(Type value)
{
EnsureCorrectType(value);
using (new WriteLock(_lock))
{
InstanceTypes.Remove(value);
}
}
/// <summary>
/// Removes a type.
/// </summary>
/// <typeparam name="T"></typeparam>
public void RemoveType<T>()
{
RemoveType(typeof (T));
}
/// <summary>
/// Adds a Type to the end of the list.
/// </summary>
/// <param name="value">The object to be added.</param>
public void AddType(Type value)
{
EnsureCorrectType(value);
using (var l = new UpgradeableReadLock(_lock))
{
if (InstanceTypes.Contains(value))
{
throw new InvalidOperationException("The Type " + value + " already exists in the collection");
};
l.UpgradeToWriteLock();
InstanceTypes.Add(value);
}
}
/// <summary>
/// Adds a Type to the end of the list.
/// </summary>
/// <typeparam name="T"></typeparam>
public void AddType<T>()
{
AddType(typeof (T));
}
/// <summary>
/// Clears the list.
/// </summary>
public void Clear()
{
using (new WriteLock(_lock))
{
InstanceTypes.Clear();
}
}
/// <summary>
/// Inserts a Type at the specified index.
/// </summary>
/// <param name="index">The zero-based index at which the object should be inserted.</param>
/// <param name="value">The object to insert.</param>
public void InsertType(int index, Type value)
{
EnsureCorrectType(value);
using (var l = new UpgradeableReadLock(_lock))
{
if (InstanceTypes.Contains(value))
{
throw new InvalidOperationException("The Type " + value + " already exists in the collection");
};
l.UpgradeToWriteLock();
InstanceTypes.Insert(index, value);
}
}
/// <summary>
/// Inserts a Type at the specified index.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="index"></param>
public void InsertType<T>(int index)
{
InsertType(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);
}
}
}