Resvolution - Kill
This commit is contained in:
@@ -171,5 +171,18 @@ namespace Umbraco.Core.DependencyInjection
|
||||
if (_collectionCtor == null) throw new InvalidOperationException("Collection auto-creation is not possible.");
|
||||
return _collectionCtor(CreateItems());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the collection contains a type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to look for.</typeparam>
|
||||
/// <returns>A value indicating whether the collection contains the type.</returns>
|
||||
/// <remarks>Some builder implementations may use this to expose a public Has{T}() method,
|
||||
/// when it makes sense. Probably does not make sense for lazy builders, for example.</remarks>
|
||||
protected bool HasBase<T>()
|
||||
where T : TItem
|
||||
{
|
||||
return _types.Contains(typeof (T));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,9 @@ namespace Umbraco.Core.DependencyInjection
|
||||
{
|
||||
foreach (var type in types)
|
||||
{
|
||||
// would be detected by CollectionBuilderBase when registering, anyways, but let's fail fast
|
||||
if (typeof(TItem).IsAssignableFrom(type) == false)
|
||||
throw new InvalidOperationException($"Cannot register type {type.FullName} as it does not inherit from/implement {typeof(TItem).FullName}.");
|
||||
if (list.Contains(type)) list.Remove(type);
|
||||
list.Add(type);
|
||||
}
|
||||
@@ -86,15 +89,17 @@ namespace Umbraco.Core.DependencyInjection
|
||||
/// Inserts a type into the collection.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to insert.</typeparam>
|
||||
/// <param name="index">The optional index.</param>
|
||||
/// <returns>The builder.</returns>
|
||||
public TBuilder Insert<T>()
|
||||
/// <remarks>Throws if the index is out of range.</remarks>
|
||||
public TBuilder Insert<T>(int index = 0)
|
||||
where T : TItem
|
||||
{
|
||||
Configure(types =>
|
||||
{
|
||||
var type = typeof (T);
|
||||
if (types.Contains(type)) types.Remove(type);
|
||||
types.Insert(0, type);
|
||||
types.Insert(index, type);
|
||||
});
|
||||
return This;
|
||||
}
|
||||
@@ -169,5 +174,26 @@ namespace Umbraco.Core.DependencyInjection
|
||||
});
|
||||
return This;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the collection contains a type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to look for.</typeparam>
|
||||
/// <returns>A value indicating whether the collection contains the type.</returns>
|
||||
public bool Has<T>()
|
||||
where T : TItem
|
||||
{
|
||||
return HasBase<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all types in the collection.
|
||||
/// </summary>
|
||||
/// <returns>The buidler.</returns>
|
||||
public TBuilder Clear()
|
||||
{
|
||||
Configure(types => types.Clear());
|
||||
return This;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using LightInject;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// A many objects resolver that uses IoC
|
||||
/// </summary>
|
||||
/// <typeparam name="TResolver"></typeparam>
|
||||
/// <typeparam name="TResolved"></typeparam>
|
||||
public abstract class ContainerManyObjectsResolver<TResolver, TResolved> : ManyObjectsResolverBase<TResolver, TResolved>
|
||||
where TResolved : class
|
||||
where TResolver : ResolverBase
|
||||
{
|
||||
private readonly IServiceContainer _container;
|
||||
|
||||
//TODO: Get rid of these - pretty sure all tests will still fail with these pass throughs, need to update
|
||||
// all tests that use resolvers to use a real container - then update most tests that are not integration tests to not use any resolvers!
|
||||
#region Constructors used for test - ONLY so that a container is not required and will just revert to using the normal ManyObjectsResolverBase
|
||||
[Obsolete("Used for tests only - should remove")]
|
||||
internal ContainerManyObjectsResolver(ILogger logger, IEnumerable<Type> types, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: base(logger, types, scope)
|
||||
{
|
||||
}
|
||||
[Obsolete("Used for tests only - should remove")]
|
||||
internal ContainerManyObjectsResolver(IServiceProvider serviceProvider, ILogger logger, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: base(serviceProvider, logger, scope)
|
||||
{
|
||||
}
|
||||
[Obsolete("Used for tests only - should remove")]
|
||||
internal ContainerManyObjectsResolver(IServiceProvider serviceProvider, ILogger logger, HttpContextBase httpContext)
|
||||
: base(serviceProvider, logger, httpContext)
|
||||
{
|
||||
}
|
||||
[Obsolete("Used for tests only - should remove")]
|
||||
internal ContainerManyObjectsResolver(IServiceProvider serviceProvider, ILogger logger, IEnumerable<Type> value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: base(serviceProvider, logger, value, scope)
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for use with IoC
|
||||
/// </summary>
|
||||
/// <param name="container"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="types"></param>
|
||||
/// <param name="scope"></param>
|
||||
internal ContainerManyObjectsResolver(IServiceContainer container, ILogger logger, IEnumerable<Type> types, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: base(logger, types, scope)
|
||||
{
|
||||
if (container == null) throw new ArgumentNullException(nameof(container));
|
||||
_container = container;
|
||||
Resolution.Frozen += Resolution_Frozen;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When resolution is frozen add all the types to the container
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
void Resolution_Frozen(object sender, EventArgs e)
|
||||
{
|
||||
var prefix = GetType().FullName + "_";
|
||||
var i = 0;
|
||||
foreach (var type in InstanceTypes)
|
||||
{
|
||||
var name = $"{prefix}{i++:00000}";
|
||||
_container.Register(typeof(TResolved), type, name, GetLifetime(LifetimeScope));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert the ObjectLifetimeScope to ILifetime
|
||||
/// </summary>
|
||||
/// <param name="scope"></param>
|
||||
/// <returns></returns>
|
||||
private static ILifetime GetLifetime(ObjectLifetimeScope scope)
|
||||
{
|
||||
switch (scope)
|
||||
{
|
||||
case ObjectLifetimeScope.HttpRequest:
|
||||
return new PerRequestLifeTime();
|
||||
case ObjectLifetimeScope.Application:
|
||||
return new PerContainerLifetime();
|
||||
//case ObjectLifetimeScope.Transient:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the instances from IoC
|
||||
/// </summary>
|
||||
/// <returns>A list of objects of type <typeparamref name="TResolved"/>.</returns>
|
||||
protected override IEnumerable<TResolved> CreateInstances()
|
||||
{
|
||||
//NOTE: we ignore scope because objects are registered under this scope and not build based on the scope.
|
||||
|
||||
var prefix = GetType().FullName + "_";
|
||||
|
||||
// GetAllInstances could return more than what *this* resolver has registered,
|
||||
// and there is no guarantee instances will be in the right order - have to do
|
||||
// it differently
|
||||
|
||||
var services = _container.AvailableServices
|
||||
.Where(x => x.ServiceName.StartsWith(prefix))
|
||||
.OrderBy(x => x.ServiceName);
|
||||
|
||||
var values = services
|
||||
.Select(x => _container.GetInstance<TResolved>(x.ServiceName))
|
||||
.ToArray();
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,642 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// The base class for all many-objects resolvers.
|
||||
/// </summary>
|
||||
/// <typeparam name="TResolver">The type of the concrete resolver class.</typeparam>
|
||||
/// <typeparam name="TResolved">The type of the resolved objects.</typeparam>
|
||||
public abstract class ManyObjectsResolverBase<TResolver, TResolved> : ResolverBase<TResolver>
|
||||
where TResolved : class
|
||||
where TResolver : ResolverBase
|
||||
{
|
||||
private Lazy<IEnumerable<TResolved>> _applicationInstances;
|
||||
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
||||
private readonly string _httpContextKey;
|
||||
private readonly List<Type> _instanceTypes;
|
||||
private IEnumerable<TResolved> _sortedValues;
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Hack: This is purely here to allow for the container resolver to be used, we'll need to refactor all of this slowly till we're
|
||||
/// happy with the outcome
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="types"></param>
|
||||
/// <param name="scope"></param>
|
||||
internal ManyObjectsResolverBase(ILogger logger, IEnumerable<Type> types, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
if (types == null) throw new ArgumentNullException(nameof(types));
|
||||
CanResolveBeforeFrozen = false;
|
||||
_instanceTypes = types.ToList();
|
||||
LifetimeScope = scope;
|
||||
Logger = logger;
|
||||
|
||||
if (scope == ObjectLifetimeScope.Application)
|
||||
InitializeAppInstances();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hack: This is purely here to allow for the lazy container resolver to be used, we'll need to refactor all of this slowly till we're
|
||||
/// happy with the outcome
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="scope"></param>
|
||||
internal ManyObjectsResolverBase(ILogger logger, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: this(logger, new List<Type>(), scope)
|
||||
{ }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects,
|
||||
/// and an optional lifetime scope.
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application.</param>
|
||||
/// <remarks>If <paramref name="scope"/> is per HttpRequest then there must be a current HttpContext.</remarks>
|
||||
/// <exception cref="InvalidOperationException"><paramref name="scope"/> is per HttpRequest but the current HttpContext is null.</exception>
|
||||
protected ManyObjectsResolverBase(IServiceProvider serviceProvider, ILogger logger, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
{
|
||||
if (serviceProvider == null) throw new ArgumentNullException(nameof(serviceProvider));
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
CanResolveBeforeFrozen = false;
|
||||
|
||||
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);
|
||||
_httpContextKey = GetType().FullName;
|
||||
}
|
||||
|
||||
ServiceProvider = serviceProvider;
|
||||
Logger = logger;
|
||||
LifetimeScope = scope;
|
||||
|
||||
_instanceTypes = new List<Type>();
|
||||
|
||||
if (scope == ObjectLifetimeScope.Application)
|
||||
InitializeAppInstances();
|
||||
}
|
||||
|
||||
/// <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="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="httpContext">The HttpContextBase corresponding to the HttpRequest.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="httpContext"/> is <c>null</c>.</exception>
|
||||
protected ManyObjectsResolverBase(IServiceProvider serviceProvider, ILogger logger, HttpContextBase httpContext)
|
||||
{
|
||||
if (serviceProvider == null) throw new ArgumentNullException(nameof(serviceProvider));
|
||||
if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
|
||||
CanResolveBeforeFrozen = false;
|
||||
Logger = logger;
|
||||
LifetimeScope = ObjectLifetimeScope.HttpRequest;
|
||||
_httpContextKey = GetType().FullName;
|
||||
ServiceProvider = serviceProvider;
|
||||
CurrentHttpContext = httpContext;
|
||||
_instanceTypes = new List<Type>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of object types,
|
||||
/// and an optional lifetime scope.
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="value">The list of object types.</param>
|
||||
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application.</param>
|
||||
/// <remarks>If <paramref name="scope"/> is per HttpRequest then there must be a current HttpContext.</remarks>
|
||||
/// <exception cref="InvalidOperationException"><paramref name="scope"/> is per HttpRequest but the current HttpContext is null.</exception>
|
||||
protected ManyObjectsResolverBase(IServiceProvider serviceProvider, ILogger logger, IEnumerable<Type> value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: this(serviceProvider, logger, scope)
|
||||
{
|
||||
_instanceTypes = value.ToList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void InitializeAppInstances()
|
||||
{
|
||||
_applicationInstances = new Lazy<IEnumerable<TResolved>>(() => CreateInstances().ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the resolver can resolve objects before resolution is frozen.
|
||||
/// </summary>
|
||||
/// <remarks>This is false by default and is used for some special internal resolvers.</remarks>
|
||||
internal bool CanResolveBeforeFrozen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of types to create instances from.
|
||||
/// </summary>
|
||||
protected virtual IEnumerable<Type> InstanceTypes => _instanceTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="HttpContextBase"/> used to initialize this object, if any.
|
||||
/// </summary>
|
||||
/// <remarks>If not null, then <c>LifetimeScope</c> will be <c>ObjectLifetimeScope.HttpRequest</c>.</remarks>
|
||||
protected HttpContextBase CurrentHttpContext { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the service provider used to instantiate objects
|
||||
/// </summary>
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
|
||||
public ILogger Logger { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the lifetime scope of resolved objects.
|
||||
/// </summary>
|
||||
protected ObjectLifetimeScope LifetimeScope { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the resolved object instances, sorted by weight.
|
||||
/// </summary>
|
||||
/// <returns>The sorted resolved object instances.</returns>
|
||||
/// <remarks>
|
||||
/// <para>The order is based upon the <c>WeightedPluginAttribute</c> and <c>DefaultPluginWeight</c>.</para>
|
||||
/// <para>Weights are sorted ascendingly (lowest weights come first).</para>
|
||||
/// </remarks>
|
||||
protected IEnumerable<TResolved> GetSortedValues()
|
||||
{
|
||||
if (_sortedValues != null) return _sortedValues;
|
||||
|
||||
var values = Values.ToList();
|
||||
values.Sort((f1, f2) => GetObjectWeight(f1).CompareTo(GetObjectWeight(f2)));
|
||||
_sortedValues = values;
|
||||
return _sortedValues;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default type weight.
|
||||
/// </summary>
|
||||
/// <remarks>Determines the weight of types that do not have a <c>WeightedPluginAttribute</c> set on
|
||||
/// them, when calling <c>GetSortedValues</c>.</remarks>
|
||||
protected virtual int DefaultPluginWeight { get; set; } = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the weight of an object for user with GetSortedValues
|
||||
/// </summary>
|
||||
/// <param name="o"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual int GetObjectWeight(object o)
|
||||
{
|
||||
var type = o.GetType();
|
||||
var attr = type.GetCustomAttribute<WeightedPluginAttribute>(true);
|
||||
return attr?.Weight ?? DefaultPluginWeight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the resolved object instances.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException"><c>CanResolveBeforeFrozen</c> is false, and resolution is not frozen.</exception>
|
||||
protected IEnumerable<TResolved> Values => CreateValues(LifetimeScope);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the values collection based on the scope
|
||||
/// </summary>
|
||||
/// <param name="scope"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual IEnumerable<TResolved> CreateValues(ObjectLifetimeScope scope)
|
||||
{
|
||||
using (Resolution.Reader(CanResolveBeforeFrozen))
|
||||
{
|
||||
// note: we apply .ToArray() to the output of CreateInstance() because that is an IEnumerable that
|
||||
// comes from the PluginManager we want to be _sure_ that it's not a Linq of some sort, but the
|
||||
// instances have actually been instanciated when we return.
|
||||
|
||||
switch (LifetimeScope)
|
||||
{
|
||||
case ObjectLifetimeScope.HttpRequest:
|
||||
|
||||
// create new instances per HttpContext
|
||||
if (CurrentHttpContext.Items[_httpContextKey] == null)
|
||||
{
|
||||
var instances = CreateInstances().ToArray();
|
||||
var disposableInstances = instances.OfType<IDisposable>();
|
||||
//Ensure anything resolved that is IDisposable is disposed when the request termintates
|
||||
foreach (var disposable in disposableInstances)
|
||||
{
|
||||
CurrentHttpContext.DisposeOnPipelineCompleted(disposable);
|
||||
}
|
||||
CurrentHttpContext.Items[_httpContextKey] = instances;
|
||||
}
|
||||
return (TResolved[])CurrentHttpContext.Items[_httpContextKey];
|
||||
|
||||
case ObjectLifetimeScope.Application:
|
||||
|
||||
return _applicationInstances.Value;
|
||||
|
||||
case ObjectLifetimeScope.Transient:
|
||||
default:
|
||||
// create new instances each time
|
||||
return CreateInstances().ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates the object instances for the types contained in the types collection.
|
||||
/// </summary>
|
||||
/// <returns>A list of objects of type <typeparamref name="TResolved"/>.</returns>
|
||||
protected virtual IEnumerable<TResolved> CreateInstances()
|
||||
{
|
||||
return ServiceProvider.CreateInstances<TResolved>(InstanceTypes, Logger);
|
||||
}
|
||||
|
||||
#region Types collection manipulation
|
||||
|
||||
/// <summary>
|
||||
/// Removes a type.
|
||||
/// </summary>
|
||||
/// <param name="value">The type to remove.</param>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support removing types, or
|
||||
/// the type is not a valid type for the resolver.</exception>
|
||||
public virtual void RemoveType(Type value)
|
||||
{
|
||||
EnsureSupportsRemove();
|
||||
|
||||
using (Resolution.Configuration)
|
||||
using (var l = new UpgradeableReadLock(_lock))
|
||||
{
|
||||
EnsureCorrectType(value);
|
||||
|
||||
l.UpgradeToWriteLock();
|
||||
_instanceTypes.Remove(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to remove.</typeparam>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support removing types, or
|
||||
/// the type is not a valid type for the resolver.</exception>
|
||||
public void RemoveType<T>()
|
||||
where T : TResolved
|
||||
{
|
||||
RemoveType(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds types.
|
||||
/// </summary>
|
||||
/// <param name="types">The types to add.</param>
|
||||
/// <remarks>The types are appended at the end of the list.</remarks>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
|
||||
/// a type is not a valid type for the resolver, or a type is already in the collection of types.</exception>
|
||||
protected void AddTypes(IEnumerable<Type> types)
|
||||
{
|
||||
EnsureSupportsAdd();
|
||||
|
||||
using (Resolution.Configuration)
|
||||
using (new WriteLock(_lock))
|
||||
{
|
||||
foreach (var t in types)
|
||||
{
|
||||
EnsureCorrectType(t);
|
||||
if (_instanceTypes.Contains(t))
|
||||
{
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Type {0} is already in the collection of types.", t.FullName));
|
||||
}
|
||||
_instanceTypes.Add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a type.
|
||||
/// </summary>
|
||||
/// <param name="value">The type to add.</param>
|
||||
/// <remarks>The type is appended at the end of the list.</remarks>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
|
||||
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
|
||||
public virtual void AddType(Type value)
|
||||
{
|
||||
EnsureSupportsAdd();
|
||||
|
||||
using (Resolution.Configuration)
|
||||
using (var l = new UpgradeableReadLock(_lock))
|
||||
{
|
||||
EnsureCorrectType(value);
|
||||
if (_instanceTypes.Contains(value))
|
||||
{
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Type {0} is already in the collection of types.", value.FullName));
|
||||
}
|
||||
|
||||
l.UpgradeToWriteLock();
|
||||
_instanceTypes.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to add.</typeparam>
|
||||
/// <remarks>The type is appended at the end of the list.</remarks>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
|
||||
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
|
||||
public void AddType<T>()
|
||||
where T : TResolved
|
||||
{
|
||||
AddType(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the list of types
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support clearing types.</exception>
|
||||
public virtual void Clear()
|
||||
{
|
||||
EnsureSupportsClear();
|
||||
|
||||
using (Resolution.Configuration)
|
||||
using (new WriteLock(_lock))
|
||||
{
|
||||
_instanceTypes.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WARNING! Do not use this unless you know what you are doing, clear all types registered and instances
|
||||
/// created. Typically only used if a resolver is no longer used in an application and memory is to be GC'd
|
||||
/// </summary>
|
||||
internal void ResetCollections()
|
||||
{
|
||||
using (new WriteLock(_lock))
|
||||
{
|
||||
_instanceTypes.Clear();
|
||||
_sortedValues = null;
|
||||
_applicationInstances = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a type at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The zero-based index at which the type should be inserted.</param>
|
||||
/// <param name="value">The type to insert.</param>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is out of range.</exception>
|
||||
public virtual void InsertType(int index, Type value)
|
||||
{
|
||||
EnsureSupportsInsert();
|
||||
|
||||
using (Resolution.Configuration)
|
||||
using (var l = new UpgradeableReadLock(_lock))
|
||||
{
|
||||
EnsureCorrectType(value);
|
||||
if (_instanceTypes.Contains(value))
|
||||
{
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Type {0} is already in the collection of types.", value.FullName));
|
||||
}
|
||||
|
||||
l.UpgradeToWriteLock();
|
||||
_instanceTypes.Insert(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a type at the beginning of the list.
|
||||
/// </summary>
|
||||
/// <param name="value">The type to insert.</param>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
|
||||
public virtual void InsertType(Type value)
|
||||
{
|
||||
InsertType(0, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a type at the specified index.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to insert.</typeparam>
|
||||
/// <param name="index">The zero-based index at which the type should be inserted.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is out of range.</exception>
|
||||
public void InsertType<T>(int index)
|
||||
where T : TResolved
|
||||
{
|
||||
InsertType(index, typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a type at the beginning of the list.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to insert.</typeparam>
|
||||
public void InsertType<T>()
|
||||
where T : TResolved
|
||||
{
|
||||
InsertType(0, typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a type before a specified, already existing type.
|
||||
/// </summary>
|
||||
/// <param name="existingType">The existing type before which to insert.</param>
|
||||
/// <param name="value">The type to insert.</param>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// one of the types is not a valid type for the resolver, or the existing type is not in the collection,
|
||||
/// or the new type is already in the collection of types.</exception>
|
||||
public virtual void InsertTypeBefore(Type existingType, Type value)
|
||||
{
|
||||
EnsureSupportsInsert();
|
||||
|
||||
using (Resolution.Configuration)
|
||||
using (var l = new UpgradeableReadLock(_lock))
|
||||
{
|
||||
EnsureCorrectType(existingType);
|
||||
EnsureCorrectType(value);
|
||||
if (_instanceTypes.Contains(existingType) == false)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Type {0} is not in the collection of types.", existingType.FullName));
|
||||
}
|
||||
if (_instanceTypes.Contains(value))
|
||||
{
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Type {0} is already in the collection of types.", value.FullName));
|
||||
}
|
||||
int index = _instanceTypes.IndexOf(existingType);
|
||||
|
||||
l.UpgradeToWriteLock();
|
||||
_instanceTypes.Insert(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a type before a specified, already existing type.
|
||||
/// </summary>
|
||||
/// <typeparam name="TExisting">The existing type before which to insert.</typeparam>
|
||||
/// <typeparam name="T">The type to insert.</typeparam>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// one of the types is not a valid type for the resolver, or the existing type is not in the collection,
|
||||
/// or the new type is already in the collection of types.</exception>
|
||||
public void InsertTypeBefore<TExisting, T>()
|
||||
where TExisting : TResolved
|
||||
where T : TResolved
|
||||
{
|
||||
InsertTypeBefore(typeof(TExisting), typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the specified type is already in the collection of types.
|
||||
/// </summary>
|
||||
/// <param name="value">The type to look for.</param>
|
||||
/// <returns>A value indicating whether the type is already in the collection of types.</returns>
|
||||
public virtual bool ContainsType(Type value)
|
||||
{
|
||||
using (new ReadLock(_lock))
|
||||
{
|
||||
return _instanceTypes.Contains(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the types in the collection of types.
|
||||
/// </summary>
|
||||
/// <returns>The types in the collection of types.</returns>
|
||||
/// <remarks>Returns an enumeration, the list cannot be modified.</remarks>
|
||||
public virtual IEnumerable<Type> GetTypes()
|
||||
{
|
||||
Type[] types;
|
||||
using (new ReadLock(_lock))
|
||||
{
|
||||
types = _instanceTypes.ToArray();
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the specified type is already in the collection of types.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to look for.</typeparam>
|
||||
/// <returns>A value indicating whether the type is already in the collection of types.</returns>
|
||||
public bool ContainsType<T>()
|
||||
where T : TResolved
|
||||
{
|
||||
return ContainsType(typeof(T));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns a WriteLock to use when modifying collections
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected WriteLock GetWriteLock()
|
||||
{
|
||||
return new WriteLock(_lock);
|
||||
}
|
||||
|
||||
#region Type utilities
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that a type is a valid type for the resolver.
|
||||
/// </summary>
|
||||
/// <param name="value">The type to test.</param>
|
||||
/// <exception cref="InvalidOperationException">the type is not a valid type for the resolver.</exception>
|
||||
protected virtual void EnsureCorrectType(Type value)
|
||||
{
|
||||
if (TypeHelper.IsTypeAssignableFrom<TResolved>(value) == false)
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Type {0} is not an acceptable type for resolver {1}.", value.FullName, GetType().FullName));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Types collection manipulation support
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the resolver supports removing types.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">The resolver does not support removing types.</exception>
|
||||
protected void EnsureSupportsRemove()
|
||||
{
|
||||
if (SupportsRemove == false)
|
||||
throw new InvalidOperationException("This resolver does not support removing types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the resolver supports clearing types.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">The resolver does not support clearing types.</exception>
|
||||
protected void EnsureSupportsClear()
|
||||
{
|
||||
if (SupportsClear == false)
|
||||
throw new InvalidOperationException("This resolver does not support clearing types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the resolver supports adding types.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">The resolver does not support adding types.</exception>
|
||||
protected void EnsureSupportsAdd()
|
||||
{
|
||||
if (SupportsAdd == false)
|
||||
throw new InvalidOperationException("This resolver does not support adding new types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the resolver supports inserting types.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">The resolver does not support inserting types.</exception>
|
||||
protected void EnsureSupportsInsert()
|
||||
{
|
||||
if (SupportsInsert == false)
|
||||
throw new InvalidOperationException("This resolver does not support inserting new types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the resolver supports adding types.
|
||||
/// </summary>
|
||||
protected virtual bool SupportsAdd
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the resolver supports inserting types.
|
||||
/// </summary>
|
||||
protected virtual bool SupportsInsert
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the resolver supports clearing types.
|
||||
/// </summary>
|
||||
protected virtual bool SupportsClear
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the resolver supports removing types.
|
||||
/// </summary>
|
||||
protected virtual bool SupportsRemove
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the relative weight of a resolved object type.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||
internal class WeightedPluginAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WeightedPluginAttribute"/> class with a weight.
|
||||
/// </summary>
|
||||
/// <param name="weight">The object type weight.</param>
|
||||
public WeightedPluginAttribute(int weight)
|
||||
{
|
||||
Weight = weight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the weight of the object type.
|
||||
/// </summary>
|
||||
public int Weight { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -306,7 +306,6 @@
|
||||
<Compile Include="Models\ContentTypeAvailableCompositionsResults.cs" />
|
||||
<Compile Include="Models\EntityContainer.cs" />
|
||||
<Compile Include="Models\Rdbms\LockDto.cs" />
|
||||
<Compile Include="ObjectResolution\ContainerManyObjectsResolver.cs" />
|
||||
<Compile Include="Models\Identity\IdentityModelMappings.cs" />
|
||||
<Compile Include="Models\Identity\IdentityUser.cs" />
|
||||
<Compile Include="Models\Identity\IdentityUserClaim.cs" />
|
||||
@@ -1119,7 +1118,6 @@
|
||||
<Compile Include="Models\Rdbms\UserDto.cs" />
|
||||
<Compile Include="Models\Rdbms\UserTypeDto.cs" />
|
||||
<Compile Include="NameValueCollectionExtensions.cs" />
|
||||
<Compile Include="ObjectResolution\WeightedPluginAttribute.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\DatePickerValueConverter.cs" />
|
||||
<Compile Include="ExpressionExtensions.cs" />
|
||||
<Compile Include="Models\PublishedContent\IPublishedContent.cs" />
|
||||
@@ -1141,7 +1139,6 @@
|
||||
<Compile Include="Logging\LoggingTaskExtension.cs" />
|
||||
<Compile Include="Logging\LogHelper.cs" />
|
||||
<Compile Include="ObjectExtensions.cs" />
|
||||
<Compile Include="ObjectResolution\ManyObjectsResolverBase.cs" />
|
||||
<Compile Include="ObjectResolution\ObjectLifetimeScope.cs" />
|
||||
<Compile Include="ObjectResolution\Resolution.cs" />
|
||||
<Compile Include="ObjectResolution\ResolverBase.cs" />
|
||||
|
||||
475
src/Umbraco.Tests/Resolvers/CollectionBuildersTests.cs
Normal file
475
src/Umbraco.Tests/Resolvers/CollectionBuildersTests.cs
Normal file
@@ -0,0 +1,475 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
|
||||
namespace Umbraco.Tests.Resolvers
|
||||
{
|
||||
[TestFixture]
|
||||
public class CollectionBuildersTests
|
||||
{
|
||||
private ServiceContainer _container;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Current.Reset();
|
||||
|
||||
_container = new ServiceContainer();
|
||||
_container.ConfigureUmbracoCore();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Current.Reset();
|
||||
|
||||
_container.Dispose();
|
||||
_container = null;
|
||||
}
|
||||
|
||||
#region Test objects
|
||||
|
||||
public abstract class Resolved
|
||||
{ }
|
||||
|
||||
public class Resolved1 : Resolved
|
||||
{ }
|
||||
|
||||
[Weight(5)] // default is 10
|
||||
public class Resolved2 : Resolved
|
||||
{ }
|
||||
|
||||
public class Resolved3 : Resolved
|
||||
{ }
|
||||
|
||||
public class Resolved4 // not! : Resolved
|
||||
{ }
|
||||
|
||||
private class TestCollectionBuilder : OrderedCollectionBuilderBase<TestCollectionBuilder, TestCollection, Resolved>
|
||||
{
|
||||
public TestCollectionBuilder(IServiceContainer container)
|
||||
: base(container)
|
||||
{ }
|
||||
|
||||
protected override TestCollectionBuilder This => this;
|
||||
}
|
||||
|
||||
private class TestCollectionBuilderTransient : OrderedCollectionBuilderBase<TestCollectionBuilderTransient, TestCollection, Resolved>
|
||||
{
|
||||
public TestCollectionBuilderTransient(IServiceContainer container)
|
||||
: base(container)
|
||||
{ }
|
||||
|
||||
protected override TestCollectionBuilderTransient This => this;
|
||||
|
||||
protected override ILifetime CollectionLifetime => null; // transient
|
||||
}
|
||||
|
||||
private class TestCollectionBuilderScope : OrderedCollectionBuilderBase<TestCollectionBuilderScope, TestCollection, Resolved>
|
||||
{
|
||||
public TestCollectionBuilderScope(IServiceContainer container)
|
||||
: base(container)
|
||||
{ }
|
||||
|
||||
protected override TestCollectionBuilderScope This => this;
|
||||
|
||||
protected override ILifetime CollectionLifetime => new PerScopeLifetime();
|
||||
}
|
||||
|
||||
private class TestCollectionBuilderWeighted : WeightedCollectionBuilderBase<TestCollectionBuilderWeighted, TestCollection, Resolved>
|
||||
{
|
||||
public TestCollectionBuilderWeighted(IServiceContainer container)
|
||||
: base(container)
|
||||
{ }
|
||||
|
||||
protected override TestCollectionBuilderWeighted This => this;
|
||||
}
|
||||
|
||||
private class TestCollection : BuilderCollectionBase<Resolved>
|
||||
{
|
||||
public TestCollection(IEnumerable<Resolved> items)
|
||||
: base(items)
|
||||
{ }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[Test]
|
||||
public void ContainsTypes()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>();
|
||||
|
||||
Assert.IsTrue(builder.Has<Resolved1>());
|
||||
Assert.IsTrue(builder.Has<Resolved2>());
|
||||
Assert.IsFalse(builder.Has<Resolved3>());
|
||||
//Assert.IsFalse(col.ContainsType<Resolved4>()); // does not compile
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
AssertCollection(col, typeof(Resolved1), typeof(Resolved2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Clear()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>();
|
||||
|
||||
builder.Clear();
|
||||
Assert.IsFalse(builder.Has<Resolved1>());
|
||||
Assert.IsFalse(builder.Has<Resolved2>());
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
AssertCollection(col);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ClearOnceResolved()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>();
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
builder.Clear();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Append()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container);
|
||||
builder.Append<Resolved1>();
|
||||
builder.Append<Resolved2>();
|
||||
|
||||
Assert.IsTrue(builder.Has<Resolved1>());
|
||||
Assert.IsTrue(builder.Has<Resolved2>());
|
||||
Assert.IsFalse(builder.Has<Resolved3>());
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
AssertCollection(col, typeof(Resolved1), typeof(Resolved2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void AppendOnceResolved()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container);
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
builder.Append<Resolved1>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AppendDuplicate()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container);
|
||||
builder.Append<Resolved1>();
|
||||
builder.Append<Resolved1>();
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
AssertCollection(col, typeof(Resolved1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void AppendInvalid()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container);
|
||||
//builder.Append<Resolved4>(); // does not compile
|
||||
builder.Append(new[] { typeof(Resolved4) }); // throws
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Remove()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>()
|
||||
.Remove<Resolved2>();
|
||||
|
||||
Assert.IsTrue(builder.Has<Resolved1>());
|
||||
Assert.IsFalse(builder.Has<Resolved2>());
|
||||
Assert.IsFalse(builder.Has<Resolved3>());
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
AssertCollection(col, typeof(Resolved1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveAbsent()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>()
|
||||
.Remove<Resolved3>();
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
AssertCollection(col, typeof(Resolved1), typeof(Resolved2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void RemoveOnceResolved()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>();
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
builder.Remove<Resolved2>(); // throws
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Insert()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>()
|
||||
.Insert<Resolved3>();
|
||||
|
||||
Assert.IsTrue(builder.Has<Resolved1>());
|
||||
Assert.IsTrue(builder.Has<Resolved2>());
|
||||
Assert.IsTrue(builder.Has<Resolved3>());
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
AssertCollection(col, typeof(Resolved3), typeof(Resolved1), typeof(Resolved2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void InsertOnceResolved()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>();
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
builder.Insert<Resolved3>(); // throws
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanInsertDuplicate()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>()
|
||||
.Insert<Resolved2>();
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
AssertCollection(col, typeof(Resolved2), typeof(Resolved1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InsertInEmpty()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container);
|
||||
builder.Insert<Resolved2>();
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
AssertCollection(col, typeof(Resolved2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void InsertAtWrongIndex1()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>();
|
||||
|
||||
builder.Insert<Resolved3>(99); // throws
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void InsertAtWrongIndex2()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>();
|
||||
|
||||
builder.Insert<Resolved3>(-1); // throws
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InsertBefore()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>()
|
||||
.InsertBefore<Resolved2, Resolved3>();
|
||||
|
||||
Assert.IsTrue(builder.Has<Resolved1>());
|
||||
Assert.IsTrue(builder.Has<Resolved2>());
|
||||
Assert.IsTrue(builder.Has<Resolved3>());
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
AssertCollection(col, typeof(Resolved1), typeof(Resolved3), typeof(Resolved2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void InsertBeforeOnceResolved()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>();
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
builder.InsertBefore<Resolved2, Resolved3>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InsertBeforeDuplicate()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>()
|
||||
.InsertBefore<Resolved1, Resolved2>();
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
AssertCollection(col, typeof(Resolved2), typeof(Resolved1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void InsertBeforeAbsent()
|
||||
{
|
||||
var builder = TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.InsertBefore<Resolved2, Resolved3>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ScopeIsApplication()
|
||||
{
|
||||
TestCollectionBuilder.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>();
|
||||
|
||||
// CreateCollection creates a new collection each time
|
||||
// but the container manages the scope, so to test the scope
|
||||
// the collection must come from the container
|
||||
|
||||
var col1 = _container.GetInstance<TestCollection>();
|
||||
AssertCollection(col1, typeof(Resolved1), typeof(Resolved2));
|
||||
|
||||
var col2 = _container.GetInstance<TestCollection>();
|
||||
AssertCollection(col2, typeof(Resolved1), typeof(Resolved2));
|
||||
|
||||
AssertSameCollection(col1, col2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ScopeIsTransient()
|
||||
{
|
||||
TestCollectionBuilderTransient.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>();
|
||||
|
||||
// CreateCollection creates a new collection each time
|
||||
// but the container manages the scope, so to test the scope
|
||||
// the collection must come from the container
|
||||
|
||||
var col1 = _container.GetInstance<TestCollection>();
|
||||
AssertCollection(col1, typeof(Resolved1), typeof(Resolved2));
|
||||
|
||||
var col2 = _container.GetInstance<TestCollection>();
|
||||
AssertCollection(col1, typeof(Resolved1), typeof(Resolved2));
|
||||
|
||||
AssertNotSameCollection(col1, col2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OrderOfTypes()
|
||||
{
|
||||
var builder = TestCollectionBuilderTransient.Register(_container)
|
||||
.Append<Resolved3>()
|
||||
.Insert<Resolved1>()
|
||||
.InsertBefore<Resolved3, Resolved2>();
|
||||
|
||||
var col1 = builder.CreateCollection();
|
||||
AssertCollection(col1, typeof(Resolved1), typeof(Resolved2), typeof(Resolved3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ScopeIsScope()
|
||||
{
|
||||
TestCollectionBuilderScope.Register(_container)
|
||||
.Append<Resolved1>()
|
||||
.Append<Resolved2>();
|
||||
|
||||
// CreateCollection creates a new collection each time
|
||||
// but the container manages the scope, so to test the scope
|
||||
// the collection must come from the container
|
||||
|
||||
var scope1 = _container.BeginScope();
|
||||
|
||||
var col1A = _container.GetInstance<TestCollection>();
|
||||
AssertCollection(col1A, typeof(Resolved1), typeof(Resolved2));
|
||||
var col1B = _container.GetInstance<TestCollection>();
|
||||
AssertCollection(col1B, typeof(Resolved1), typeof(Resolved2));
|
||||
|
||||
AssertSameCollection(col1A, col1B);
|
||||
|
||||
_container.EndCurrentScope();
|
||||
var scope2 = _container.BeginScope();
|
||||
|
||||
var col2 = _container.GetInstance<TestCollection>();
|
||||
AssertCollection(col2, typeof(Resolved1), typeof(Resolved2));
|
||||
|
||||
AssertNotSameCollection(col1A, col2);
|
||||
|
||||
_container.EndCurrentScope();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Weights()
|
||||
{
|
||||
var builder = TestCollectionBuilderWeighted.Register(_container)
|
||||
.Add<Resolved1>()
|
||||
.Add<Resolved2>();
|
||||
|
||||
var col = builder.CreateCollection();
|
||||
AssertCollection(col, typeof(Resolved2), typeof(Resolved1));
|
||||
}
|
||||
|
||||
private static void AssertCollection(IEnumerable<Resolved> col, params Type[] expected)
|
||||
{
|
||||
var colA = col.ToArray();
|
||||
Assert.AreEqual(expected.Length, colA.Length);
|
||||
for (var i = 0; i < expected.Length; i++)
|
||||
Assert.IsInstanceOf(expected[i], colA[i]);
|
||||
}
|
||||
|
||||
private static void AssertSameCollection(IEnumerable<Resolved> col1, IEnumerable<Resolved> col2)
|
||||
{
|
||||
Assert.AreSame(col1, col2);
|
||||
|
||||
var col1A = col1.ToArray();
|
||||
var col2A = col2.ToArray();
|
||||
|
||||
Assert.AreEqual(col1A.Length, col2A.Length);
|
||||
for (var i = 0; i < col1A.Length; i++)
|
||||
Assert.AreSame(col1A[i], col2A[i]);
|
||||
}
|
||||
|
||||
private static void AssertNotSameCollection(IEnumerable<Resolved> col1, IEnumerable<Resolved> col2)
|
||||
{
|
||||
Assert.AreNotSame(col1, col2);
|
||||
|
||||
var col1A = col1.ToArray();
|
||||
var col2A = col2.ToArray();
|
||||
|
||||
Assert.AreEqual(col1A.Length, col2A.Length);
|
||||
for (var i = 0; i < col1A.Length; i++)
|
||||
Assert.AreNotSame(col1A[i], col2A[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,409 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Moq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Umbraco.Tests.Resolvers
|
||||
{
|
||||
[TestFixture]
|
||||
public class ManyResolverTests
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
ManyResolver.Reset();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
ManyResolver.Reset();
|
||||
}
|
||||
|
||||
#region Resolvers and Resolved
|
||||
|
||||
public abstract class Resolved
|
||||
{ }
|
||||
|
||||
public class Resolved1 : Resolved
|
||||
{ }
|
||||
|
||||
[WeightedPlugin(5)] // default is 10
|
||||
public class Resolved2 : Resolved
|
||||
{ }
|
||||
|
||||
public class Resolved3 : Resolved
|
||||
{ }
|
||||
|
||||
public class Resolved4 // not! : Resolved
|
||||
{ }
|
||||
|
||||
public sealed class ManyResolver : ManyObjectsResolverBase<ManyResolver, Resolved>
|
||||
{
|
||||
public ManyResolver(IServiceProvider serviceProvider, ILogger logger)
|
||||
: base(serviceProvider, logger)
|
||||
{ }
|
||||
|
||||
public ManyResolver(IServiceProvider serviceProvider, ILogger logger, IEnumerable<Type> value)
|
||||
: base(serviceProvider, logger, value)
|
||||
{ }
|
||||
|
||||
public ManyResolver(IServiceProvider serviceProvider, ILogger logger, IEnumerable<Type> value, ObjectLifetimeScope scope)
|
||||
: base(serviceProvider, logger, value, scope)
|
||||
{ }
|
||||
|
||||
public ManyResolver(IServiceProvider serviceProvider, ILogger logger, HttpContextBase httpContext)
|
||||
: base(serviceProvider, logger, httpContext)
|
||||
{ }
|
||||
|
||||
public IEnumerable<Resolved> SortedResolvedObjects { get { return GetSortedValues(); } }
|
||||
public IEnumerable<Resolved> ResolvedObjects { get { return Values; } }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Test ManyResolver types collection manipulation
|
||||
|
||||
[Test]
|
||||
public void ManyResolverContainsTypes()
|
||||
{
|
||||
var resolver = new ManyResolver(
|
||||
new ActivatorServiceProvider(), Mock.Of<ILogger>(),
|
||||
new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
|
||||
Assert.IsTrue(resolver.ContainsType<Resolved1>());
|
||||
Assert.IsTrue(resolver.ContainsType<Resolved2>());
|
||||
Assert.IsFalse(resolver.ContainsType<Resolved3>());
|
||||
//Assert.IsFalse(resolver.ContainsType<Resolved4>()); // does not compile
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ManyResolverCanClearBeforeFreeze()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>());
|
||||
resolver.AddType<Resolved1>();
|
||||
resolver.AddType<Resolved2>();
|
||||
resolver.Clear();
|
||||
Assert.IsFalse(resolver.ContainsType<Resolved1>());
|
||||
Assert.IsFalse(resolver.ContainsType<Resolved2>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ManyResolverCannotClearOnceFrozen()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>());
|
||||
resolver.AddType<Resolved1>();
|
||||
resolver.AddType<Resolved2>();
|
||||
Resolution.Freeze();
|
||||
resolver.Clear();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ManyResolverCanAddTypeBeforeFreeze()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>());
|
||||
resolver.AddType<Resolved1>();
|
||||
resolver.AddType<Resolved2>();
|
||||
|
||||
Assert.IsTrue(resolver.ContainsType<Resolved1>());
|
||||
Assert.IsTrue(resolver.ContainsType<Resolved2>());
|
||||
Assert.IsFalse(resolver.ContainsType<Resolved3>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ManyResolverCannotAddTypeOnceFrozen()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>());
|
||||
Resolution.Freeze();
|
||||
resolver.AddType<Resolved1>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ManyResolverCannotAddTypeAgain()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>());
|
||||
resolver.AddType<Resolved1>();
|
||||
resolver.AddType<Resolved1>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ManyResolverCannotAddInvalidType()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>());
|
||||
//resolver.AddType<Resolved4>(); // does not compile
|
||||
resolver.AddType(typeof(Resolved4)); // throws
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ManyResolverCanRemoveTypeBeforeFreeze()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
resolver.RemoveType<Resolved2>();
|
||||
|
||||
Assert.IsTrue(resolver.ContainsType<Resolved1>());
|
||||
Assert.IsFalse(resolver.ContainsType<Resolved2>());
|
||||
Assert.IsFalse(resolver.ContainsType<Resolved3>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ManyResolverCanRemoveAbsentType()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
resolver.RemoveType<Resolved3>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ManyResolverCannotRemoveInvalidType()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
//resolver.RemoveType<Resolved4>(); // does not compile
|
||||
resolver.RemoveType(typeof(Resolved4)); // throws
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ManyResolverCannotRemoveTypeOnceFrozen()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
Resolution.Freeze();
|
||||
resolver.RemoveType<Resolved2>(); // throws
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ManyResolverCanInsertTypeBeforeFreeze()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
resolver.InsertType<Resolved3>(0);
|
||||
|
||||
Assert.IsTrue(resolver.ContainsType<Resolved1>());
|
||||
Assert.IsTrue(resolver.ContainsType<Resolved2>());
|
||||
Assert.IsTrue(resolver.ContainsType<Resolved3>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ManyResolverCannotInsertTypeOnceFrozen()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
Resolution.Freeze();
|
||||
resolver.InsertType<Resolved3>(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ManyResolverCannotInsertTypeAgain()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
resolver.InsertType<Resolved2>(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ManyResolverCanInsertInEmptyList()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>());
|
||||
resolver.InsertType<Resolved2>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ManyResolverCannotInsertInvalidType()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
//resolver.InsertType<Resolved4>(0); // does not compile
|
||||
resolver.InsertType(0, typeof(Resolved4)); // throws
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ManyResolverCannotInsertTypeAtWrongIndex()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
resolver.InsertType(99, typeof(Resolved3)); // throws
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
[Test]
|
||||
public void ManyResolverCanInsertBeforeTypeBeforeFreeze()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
resolver.InsertTypeBefore<Resolved2, Resolved3>();
|
||||
|
||||
Assert.IsTrue(resolver.ContainsType<Resolved1>());
|
||||
Assert.IsTrue(resolver.ContainsType<Resolved2>());
|
||||
Assert.IsTrue(resolver.ContainsType<Resolved3>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ManyResolverCannotInsertBeforeTypeOnceFrozen()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
Resolution.Freeze();
|
||||
resolver.InsertTypeBefore<Resolved2, Resolved3>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ManyResolverCannotInsertBeforeTypeAgain()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
resolver.InsertTypeBefore<Resolved2, Resolved1>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ManyResolverCannotInsertBeforeAbsentType()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1) });
|
||||
resolver.InsertTypeBefore<Resolved2, Resolved3>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ManyResolverCannotInsertBeforeInvalidType()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
//resolver.InsertTypeBefore<Resolved2, Resolved4>(); // does not compile
|
||||
resolver.InsertTypeBefore(typeof(Resolved2), typeof(Resolved4)); // throws
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Test ManyResolver resolution
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void ManyResolverCannotGetValuesBeforeFreeze()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
var values = resolver.ResolvedObjects;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ManyResolverCannotGetValuesBeforeFreezeUnless()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
resolver.CanResolveBeforeFrozen = true;
|
||||
var values = resolver.ResolvedObjects;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ManyResolverCanGetValuesOnceFrozen()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
Resolution.Freeze();
|
||||
var values = resolver.ResolvedObjects;
|
||||
|
||||
Assert.AreEqual(2, values.Count());
|
||||
Assert.IsInstanceOf<Resolved1>(values.ElementAt(0));
|
||||
Assert.IsInstanceOf<Resolved2>(values.ElementAt(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ManyResolverDefaultLifetimeScopeIsApplication()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
Resolution.Freeze();
|
||||
var values = resolver.ResolvedObjects;
|
||||
|
||||
Assert.AreEqual(2, values.Count());
|
||||
Assert.IsInstanceOf<Resolved1>(values.ElementAt(0));
|
||||
Assert.IsInstanceOf<Resolved2>(values.ElementAt(1));
|
||||
|
||||
var values2 = resolver.ResolvedObjects;
|
||||
Assert.AreEqual(2, values2.Count());
|
||||
Assert.AreSame(values.ElementAt(0), values2.ElementAt(0));
|
||||
Assert.AreSame(values.ElementAt(1), values2.ElementAt(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ManyResolverTransientLifetimeScope()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) }, ObjectLifetimeScope.Transient);
|
||||
Resolution.Freeze();
|
||||
var values = resolver.ResolvedObjects;
|
||||
|
||||
Assert.AreEqual(2, values.Count());
|
||||
Assert.IsInstanceOf<Resolved1>(values.ElementAt(0));
|
||||
Assert.IsInstanceOf<Resolved2>(values.ElementAt(1));
|
||||
|
||||
var values2 = resolver.ResolvedObjects;
|
||||
Assert.AreEqual(2, values2.Count());
|
||||
Assert.AreNotSame(values.ElementAt(0), values2.ElementAt(0));
|
||||
Assert.AreNotSame(values.ElementAt(1), values2.ElementAt(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ManyResolverDefaultOrderOfTypes()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>());
|
||||
resolver.AddType<Resolved3>();
|
||||
resolver.InsertType<Resolved1>(0);
|
||||
resolver.InsertTypeBefore<Resolved3, Resolved2>();
|
||||
Resolution.Freeze();
|
||||
var values = resolver.ResolvedObjects;
|
||||
|
||||
Assert.AreEqual(3, values.Count());
|
||||
Assert.IsInstanceOf<Resolved1>(values.ElementAt(0));
|
||||
Assert.IsInstanceOf<Resolved2>(values.ElementAt(1));
|
||||
Assert.IsInstanceOf<Resolved3>(values.ElementAt(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ManyResolverHttpRequestLifetimeScope()
|
||||
{
|
||||
var httpContextFactory = new FakeHttpContextFactory("~/Home");
|
||||
var httpContext = httpContextFactory.HttpContext;
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), httpContext);
|
||||
|
||||
resolver.AddType<Resolved1>();
|
||||
resolver.AddType<Resolved2>();
|
||||
Resolution.Freeze();
|
||||
|
||||
var values = resolver.ResolvedObjects;
|
||||
Assert.AreEqual(2, values.Count());
|
||||
Assert.IsInstanceOf<Resolved1>(values.ElementAt(0));
|
||||
Assert.IsInstanceOf<Resolved2>(values.ElementAt(1));
|
||||
|
||||
var values2 = resolver.ResolvedObjects;
|
||||
Assert.AreEqual(2, values2.Count());
|
||||
Assert.AreSame(values.ElementAt(0), values2.ElementAt(0));
|
||||
Assert.AreSame(values.ElementAt(1), values2.ElementAt(1));
|
||||
|
||||
httpContextFactory.HttpContext.Items.Clear(); // new context
|
||||
|
||||
var values3 = resolver.ResolvedObjects;
|
||||
Assert.AreEqual(2, values3.Count());
|
||||
Assert.AreNotSame(values.ElementAt(0), values3.ElementAt(0));
|
||||
Assert.AreNotSame(values.ElementAt(1), values3.ElementAt(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ManyResolverWeightedResolution()
|
||||
{
|
||||
var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of<ILogger>(), new Type[] { typeof(Resolved1), typeof(Resolved2) });
|
||||
Resolution.Freeze();
|
||||
|
||||
var values = resolver.SortedResolvedObjects;
|
||||
Assert.AreEqual(2, values.Count());
|
||||
Assert.IsInstanceOf<Resolved2>(values.ElementAt(0));
|
||||
Assert.IsInstanceOf<Resolved1>(values.ElementAt(1));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -498,7 +498,7 @@
|
||||
<Compile Include="ObjectExtensionsTests.cs" />
|
||||
<Compile Include="Cache\PublishedCache\PublishedContentCacheTests.cs" />
|
||||
<Compile Include="Resolvers\LazyCollectionBuilderTests.cs" />
|
||||
<Compile Include="Resolvers\ManyResolverTests.cs" />
|
||||
<Compile Include="Resolvers\CollectionBuildersTests.cs" />
|
||||
<Compile Include="Resolvers\SingleResolverTests.cs" />
|
||||
<Compile Include="Resolvers\ResolutionTests.cs" />
|
||||
<Compile Include="Routing\ContentFinderByAliasWithDomainsTests.cs" />
|
||||
|
||||
Reference in New Issue
Block a user