Files
Umbraco-CMS/src/Umbraco.Core/Resolving/ManyObjectResolverBase.cs

228 lines
7.4 KiB
C#
Raw Normal View History

using System;
2012-07-27 05:52:01 +06:00
using System.Collections.Generic;
using System.Threading;
using System.Web;
2012-07-27 05:52:01 +06:00
namespace Umbraco.Core.Resolving
{
internal abstract class ManyObjectResolverBase<TResolved>
2012-07-27 05:52:01 +06:00
where TResolved : class
{
private List<TResolved> _applicationInstances = null;
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ManyObjectResolverBase{TResolved}"/> class with an empty list of objects.
/// </summary>
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application</param>
protected ManyObjectResolverBase(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>();
}
2012-07-27 05:52:01 +06:00
2012-07-27 14:06:41 -02:00
/// <summary>
/// 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.
2012-07-27 14:06:41 -02:00
/// </summary>
/// <param name="httpContext"></param>
protected ManyObjectResolverBase(HttpContextBase httpContext)
2012-07-27 05:52:01 +06:00
{
LifetimeScope = ObjectLifetimeScope.HttpRequest;
CurrentHttpContext = httpContext;
InstanceTypes = new List<Type>();
2012-07-27 05:52:01 +06:00
}
2012-07-27 14:06:41 -02:00
/// <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>
/// <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 ManyObjectResolverBase(IEnumerable<Type> value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
: this(scope)
{
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>
/// 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>
/// <param name="value"></param>
protected ManyObjectResolverBase(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.
2012-07-27 14:06:41 -02:00
/// </summary>
protected IEnumerable<TResolved> Values
2012-07-27 05:52:01 +06:00
{
get
{
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 (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>(
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>
/// Removes a type.
2012-07-27 14:06:41 -02:00
/// </summary>
/// <param name="value">The type to remove.</param>
public void RemoveType(Type value)
{
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>
/// 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.
2012-07-27 14:06:41 -02:00
/// </summary>
/// <param name="value">The object to be added.</param>
public void AddType(Type value)
2012-07-27 05:52:01 +06:00
{
EnsureCorrectType(value);
using (var l = new UpgradeableReadLock(_lock))
2012-07-27 05:52:01 +06:00
{
if (InstanceTypes.Contains(value))
{
throw new InvalidOperationException("The Type " + value + " already exists in the collection");
};
l.UpgradeToWriteLock();
InstanceTypes.Add(value);
}
2012-07-27 05:52:01 +06:00
}
/// <summary>
/// Adds a Type to the end of the list.
/// </summary>
/// <typeparam name="T"></typeparam>
public void AddType<T>()
{
AddType(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()
{
using (new WriteLock(_lock))
2012-07-27 05:52:01 +06:00
{
InstanceTypes.Clear();
}
2012-07-27 05:52:01 +06:00
}
2012-07-27 14:06:41 -02:00
/// <summary>
/// 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>
public void InsertType(int index, Type value)
2012-07-27 05:52:01 +06:00
{
EnsureCorrectType(value);
using (var l = new UpgradeableReadLock(_lock))
2012-07-27 05:52:01 +06:00
{
if (InstanceTypes.Contains(value))
{
throw new InvalidOperationException("The Type " + value + " already exists in the collection");
};
l.UpgradeToWriteLock();
InstanceTypes.Insert(index, value);
}
2012-07-27 05:52:01 +06:00
}
/// <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);
}
2012-07-27 05:52:01 +06:00
}
}