Rename namespace from Umbraco.Core.Resolving to Umbraco.Core.ObjectResolution
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// A base resolver used for old legacy factories such as the DataTypeFactory or CacheResolverFactory.
|
||||
/// </summary>
|
||||
/// <typeparam name="TResolver"></typeparam>
|
||||
/// <typeparam name="TResolved"> </typeparam>
|
||||
/// <remarks>
|
||||
/// This class contains basic functionality to mimic the functionality in these old factories since they all return
|
||||
/// transient objects (though this should be changed) and the method GetById needs to lookup a type to an ID and since
|
||||
/// these old classes don't contain metadata, the objects need to be instantiated first to get their metadata, we then store this
|
||||
/// for use in the GetById method.
|
||||
/// </remarks>
|
||||
internal abstract class LegacyTransientObjectsResolver<TResolver, TResolved> : ManyObjectsResolverBase<TResolver, TResolved>
|
||||
where TResolved : class
|
||||
where TResolver : class
|
||||
{
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="refreshers"></param>
|
||||
/// <remarks>
|
||||
/// We are creating Transient instances (new instances each time) because this is how the legacy code worked and
|
||||
/// I don't want to muck anything up by changing them to application based instances.
|
||||
/// TODO: However, it would make much more sense to do this and would speed up the application plus this would make the GetById method much easier.
|
||||
/// </remarks>
|
||||
protected LegacyTransientObjectsResolver(IEnumerable<Type> refreshers)
|
||||
: base(ObjectLifetimeScope.Transient) // false = new objects every time
|
||||
{
|
||||
foreach (var l in refreshers)
|
||||
{
|
||||
this.AddType(l);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Maintains a list of Ids and their types when first call to CacheResolvers or GetById occurs, this is used
|
||||
/// in order to return a single object by id without instantiating the entire type stack.
|
||||
/// </summary>
|
||||
private ConcurrentDictionary<Guid, Type> _trackIdToType;
|
||||
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// method to return the unique id for type T
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract Guid GetUniqueIdentifier(TResolved obj);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new ICacheRefresher instance by id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public TResolved GetById(Guid id)
|
||||
{
|
||||
EnsureRefreshersList();
|
||||
return !_trackIdToType.ContainsKey(id)
|
||||
? null
|
||||
: PluginManager.Current.CreateInstance<TResolved>(_trackIdToType[id]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates the refreshers dictionary to allow us to instantiate a type by Id since the ICacheRefresher type doesn't contain any metadata
|
||||
/// </summary>
|
||||
protected void EnsureRefreshersList()
|
||||
{
|
||||
using (var l = new UpgradeableReadLock(_lock))
|
||||
{
|
||||
if (_trackIdToType == null)
|
||||
{
|
||||
l.UpgradeToWriteLock();
|
||||
_trackIdToType = new ConcurrentDictionary<Guid, Type>();
|
||||
foreach (var v in Values)
|
||||
{
|
||||
_trackIdToType.TryAdd(GetUniqueIdentifier(v), v.GetType());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Web.UI;
|
||||
using Umbraco.Core.Macros;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// A resolver to return all IMacroGuiRendering objects
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Much of this classes methods are based on legacy code from umbraco.editorControls.macrocontainer.MacroControlFactory
|
||||
/// this code should probably be reviewed and cleaned up if necessary.
|
||||
/// </remarks>
|
||||
internal sealed class MacroFieldEditorsResolver : ManyObjectsResolverBase<MacroFieldEditorsResolver, IMacroGuiRendering>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="macroEditors"></param>
|
||||
internal MacroFieldEditorsResolver(IEnumerable<Type> macroEditors)
|
||||
: base(macroEditors, ObjectLifetimeScope.Transient)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IMacroGuiRendering"/> implementations.
|
||||
/// </summary>
|
||||
public IEnumerable<IMacroGuiRendering> MacroFieldEditors
|
||||
{
|
||||
get
|
||||
{
|
||||
return Values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value based on the type of control
|
||||
/// </summary>
|
||||
/// <param name="macroControl"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is legacy code migrated from umbraco.editorControls.macrocontainer.MacroControlFactory
|
||||
/// </remarks>
|
||||
internal string GetValueFromMacroControl(Control macroControl)
|
||||
{
|
||||
return ((IMacroGuiRendering)macroControl).Value;
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// This is legacy code migrated from umbraco.editorControls.macrocontainer.MacroControlFactory
|
||||
/// </remarks>
|
||||
internal List<Type> MacroControlTypes
|
||||
{
|
||||
get { return InstanceTypes; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of a Macro control and return it.
|
||||
/// Because the macro control uses inline client script whichs is not generated after postback
|
||||
/// That's why we use the Page Picker instead of the content picker of the macro.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is legacy code migrated from umbraco.editorControls.macrocontainer.MacroControlFactory
|
||||
/// </remarks>
|
||||
internal Control GetMacroRenderControlByType(PersistableMacroProperty prop, string uniqueId)
|
||||
{
|
||||
var m = MacroControlTypes.FindLast(macroGuiCcontrol => macroGuiCcontrol.ToString() == string.Format("{0}.{1}", prop.AssemblyName, prop.TypeName));
|
||||
var instance = PluginManager.Current.CreateInstance<IMacroGuiRendering>(m);
|
||||
if (instance != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(prop.Value))
|
||||
{
|
||||
instance.Value = prop.Value;
|
||||
}
|
||||
var macroControl = instance as Control;
|
||||
if (macroControl != null)
|
||||
{
|
||||
macroControl.ID = uniqueId;
|
||||
return macroControl;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
236
src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs
Normal file
236
src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs
Normal file
@@ -0,0 +1,236 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
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>(CreateInstances());
|
||||
}
|
||||
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>(CreateInstances());
|
||||
}
|
||||
return _applicationInstances;
|
||||
}
|
||||
case ObjectLifetimeScope.Transient:
|
||||
default:
|
||||
//create new instances each time
|
||||
return CreateInstances();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<TResolved> CreateInstances()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
9
src/Umbraco.Core/ObjectResolution/ObjectLifetimeScope.cs
Normal file
9
src/Umbraco.Core/ObjectResolution/ObjectLifetimeScope.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
internal enum ObjectLifetimeScope
|
||||
{
|
||||
HttpRequest,
|
||||
Application,
|
||||
Transient
|
||||
}
|
||||
}
|
||||
38
src/Umbraco.Core/ObjectResolution/Resolution.cs
Normal file
38
src/Umbraco.Core/ObjectResolution/Resolution.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
|
||||
|
||||
|
||||
// notes: nothing in Resolving is thread-safe because everything should happen when the app is starting
|
||||
|
||||
internal class Resolution
|
||||
{
|
||||
public static event EventHandler Frozen;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating that resolution is frozen
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The internal setter is normally used for unit tests
|
||||
/// </remarks>
|
||||
public static bool IsFrozen { get; internal set; }
|
||||
|
||||
public static void EnsureNotFrozen()
|
||||
{
|
||||
if (Resolution.IsFrozen)
|
||||
throw new InvalidOperationException("Resolution is frozen. It is not possible to modify resolvers once resolution is frozen.");
|
||||
}
|
||||
|
||||
public static void Freeze()
|
||||
{
|
||||
if (Resolution.IsFrozen)
|
||||
throw new InvalidOperationException("Resolution is frozen. It is not possible to freeze it again.");
|
||||
|
||||
IsFrozen = true;
|
||||
if (Frozen != null)
|
||||
Frozen(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
57
src/Umbraco.Core/ObjectResolution/ResolverBase.cs
Normal file
57
src/Umbraco.Core/ObjectResolution/ResolverBase.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// base class for resolvers which declare a singleton accessor
|
||||
/// </summary>
|
||||
/// <typeparam name="TResolver"></typeparam>
|
||||
internal abstract class ResolverBase<TResolver>
|
||||
where TResolver : class
|
||||
{
|
||||
static TResolver _resolver;
|
||||
|
||||
/// <summary>
|
||||
/// The lock for the singleton
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Though resharper says this is in error, it is actually correct. We want a different lock object for each generic type.
|
||||
/// See this for details: http://confluence.jetbrains.net/display/ReSharper/Static+field+in+generic+type
|
||||
/// </remarks>
|
||||
static readonly ReaderWriterLockSlim ResolversLock = new ReaderWriterLockSlim();
|
||||
|
||||
public static TResolver Current
|
||||
{
|
||||
get
|
||||
{
|
||||
using (new ReadLock(ResolversLock))
|
||||
{
|
||||
if (_resolver == null)
|
||||
throw new InvalidOperationException("Current has not been initialized. You must initialize Current before trying to read it.");
|
||||
return _resolver;
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
using (new WriteLock(ResolversLock))
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
if (_resolver != null)
|
||||
throw new InvalidOperationException("Current has already been initialized. It is not possible to re-initialize Current once it has been initialized.");
|
||||
_resolver = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// used in unit tests to reset current to null
|
||||
/// </summary>
|
||||
internal static void Reset()
|
||||
{
|
||||
_resolver = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// A Resolver to return and set a Single registered object.
|
||||
/// </summary>
|
||||
/// <typeparam name="TResolved"></typeparam>
|
||||
/// <typeparam name="TResolver"> </typeparam>
|
||||
/// <remarks>
|
||||
/// Used for 'singly' registered objects. An example is like the MVC Controller Factory, only one exists application wide and it can
|
||||
/// be get/set.
|
||||
/// </remarks>
|
||||
internal abstract class SingleObjectResolverBase<TResolver, TResolved> : ResolverBase<TResolver>
|
||||
where TResolved : class
|
||||
where TResolver : class
|
||||
{
|
||||
TResolved _resolved;
|
||||
readonly bool _canBeNull;
|
||||
|
||||
protected SingleObjectResolverBase()
|
||||
: this(false)
|
||||
{ }
|
||||
|
||||
protected SingleObjectResolverBase(TResolved value)
|
||||
: this(false)
|
||||
{
|
||||
_resolved = value;
|
||||
}
|
||||
|
||||
protected SingleObjectResolverBase(bool canBeNull)
|
||||
{
|
||||
_canBeNull = canBeNull;
|
||||
}
|
||||
|
||||
protected SingleObjectResolverBase(TResolved value, bool canBeNull)
|
||||
{
|
||||
_resolved = value;
|
||||
_canBeNull = canBeNull;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the value of the object
|
||||
/// </summary>
|
||||
protected TResolved Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return _resolved;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (!_canBeNull && value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
_resolved = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user