diff --git a/src/Umbraco.Core/DependencyInjection/CollectionBuilderBase.cs b/src/Umbraco.Core/DependencyInjection/CollectionBuilderBase.cs index 4a8c2ccf8a..b19b220620 100644 --- a/src/Umbraco.Core/DependencyInjection/CollectionBuilderBase.cs +++ b/src/Umbraco.Core/DependencyInjection/CollectionBuilderBase.cs @@ -171,5 +171,18 @@ namespace Umbraco.Core.DependencyInjection if (_collectionCtor == null) throw new InvalidOperationException("Collection auto-creation is not possible."); return _collectionCtor(CreateItems()); } + + /// + /// Gets a value indicating whether the collection contains a type. + /// + /// The type to look for. + /// A value indicating whether the collection contains the type. + /// 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. + protected bool HasBase() + where T : TItem + { + return _types.Contains(typeof (T)); + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/DependencyInjection/OrderedCollectionBuilderBase.cs b/src/Umbraco.Core/DependencyInjection/OrderedCollectionBuilderBase.cs index 96d0a85762..55bf274af9 100644 --- a/src/Umbraco.Core/DependencyInjection/OrderedCollectionBuilderBase.cs +++ b/src/Umbraco.Core/DependencyInjection/OrderedCollectionBuilderBase.cs @@ -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. /// /// The type to insert. + /// The optional index. /// The builder. - public TBuilder Insert() + /// Throws if the index is out of range. + public TBuilder Insert(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; } + + /// + /// Gets a value indicating whether the collection contains a type. + /// + /// The type to look for. + /// A value indicating whether the collection contains the type. + public bool Has() + where T : TItem + { + return HasBase(); + } + + /// + /// Clears all types in the collection. + /// + /// The buidler. + public TBuilder Clear() + { + Configure(types => types.Clear()); + return This; + } } } diff --git a/src/Umbraco.Core/ObjectResolution/ContainerManyObjectsResolver.cs b/src/Umbraco.Core/ObjectResolution/ContainerManyObjectsResolver.cs deleted file mode 100644 index 2454a8f2c9..0000000000 --- a/src/Umbraco.Core/ObjectResolution/ContainerManyObjectsResolver.cs +++ /dev/null @@ -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 -{ - /// - /// A many objects resolver that uses IoC - /// - /// - /// - public abstract class ContainerManyObjectsResolver : ManyObjectsResolverBase - 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 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 value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application) - : base(serviceProvider, logger, value, scope) - { - } - #endregion - - /// - /// Constructor for use with IoC - /// - /// - /// - /// - /// - internal ContainerManyObjectsResolver(IServiceContainer container, ILogger logger, IEnumerable types, ObjectLifetimeScope scope = ObjectLifetimeScope.Application) - : base(logger, types, scope) - { - if (container == null) throw new ArgumentNullException(nameof(container)); - _container = container; - Resolution.Frozen += Resolution_Frozen; - } - - /// - /// When resolution is frozen add all the types to the container - /// - /// - /// - 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)); - } - } - - /// - /// Convert the ObjectLifetimeScope to ILifetime - /// - /// - /// - 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; - } - } - - /// - /// Creates the instances from IoC - /// - /// A list of objects of type . - protected override IEnumerable 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(x.ServiceName)) - .ToArray(); - - return values; - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs deleted file mode 100644 index ca9243bc8a..0000000000 --- a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs +++ /dev/null @@ -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 -{ - /// - /// The base class for all many-objects resolvers. - /// - /// The type of the concrete resolver class. - /// The type of the resolved objects. - public abstract class ManyObjectsResolverBase : ResolverBase - where TResolved : class - where TResolver : ResolverBase - { - private Lazy> _applicationInstances; - private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); - private readonly string _httpContextKey; - private readonly List _instanceTypes; - private IEnumerable _sortedValues; - - #region Constructors - - /// - /// 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 - /// - /// - /// - /// - internal ManyObjectsResolverBase(ILogger logger, IEnumerable 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(); - } - - /// - /// 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 - /// - /// - /// - internal ManyObjectsResolverBase(ILogger logger, ObjectLifetimeScope scope = ObjectLifetimeScope.Application) - : this(logger, new List(), scope) - { } - - - /// - /// Initializes a new instance of the class with an empty list of objects, - /// and an optional lifetime scope. - /// - /// - /// - /// The lifetime scope of instantiated objects, default is per Application. - /// If is per HttpRequest then there must be a current HttpContext. - /// is per HttpRequest but the current HttpContext is null. - 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(); - - if (scope == ObjectLifetimeScope.Application) - InitializeAppInstances(); - } - - /// - /// Initializes a new instance of the class with an empty list of objects, - /// with creation of objects based on an HttpRequest lifetime scope. - /// - /// - /// - /// The HttpContextBase corresponding to the HttpRequest. - /// is null. - 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(); - } - - /// - /// Initializes a new instance of the class with an initial list of object types, - /// and an optional lifetime scope. - /// - /// - /// - /// The list of object types. - /// The lifetime scope of instantiated objects, default is per Application. - /// If is per HttpRequest then there must be a current HttpContext. - /// is per HttpRequest but the current HttpContext is null. - protected ManyObjectsResolverBase(IServiceProvider serviceProvider, ILogger logger, IEnumerable value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application) - : this(serviceProvider, logger, scope) - { - _instanceTypes = value.ToList(); - } - - #endregion - - private void InitializeAppInstances() - { - _applicationInstances = new Lazy>(() => CreateInstances().ToArray()); - } - - /// - /// Gets or sets a value indicating whether the resolver can resolve objects before resolution is frozen. - /// - /// This is false by default and is used for some special internal resolvers. - internal bool CanResolveBeforeFrozen { get; set; } - - /// - /// Gets the list of types to create instances from. - /// - protected virtual IEnumerable InstanceTypes => _instanceTypes; - - /// - /// Gets or sets the used to initialize this object, if any. - /// - /// If not null, then LifetimeScope will be ObjectLifetimeScope.HttpRequest. - protected HttpContextBase CurrentHttpContext { get; } - - /// - /// Returns the service provider used to instantiate objects - /// - public IServiceProvider ServiceProvider { get; } - - public ILogger Logger { get; } - - /// - /// Gets or sets the lifetime scope of resolved objects. - /// - protected ObjectLifetimeScope LifetimeScope { get; } - - /// - /// Gets the resolved object instances, sorted by weight. - /// - /// The sorted resolved object instances. - /// - /// The order is based upon the WeightedPluginAttribute and DefaultPluginWeight. - /// Weights are sorted ascendingly (lowest weights come first). - /// - protected IEnumerable GetSortedValues() - { - if (_sortedValues != null) return _sortedValues; - - var values = Values.ToList(); - values.Sort((f1, f2) => GetObjectWeight(f1).CompareTo(GetObjectWeight(f2))); - _sortedValues = values; - return _sortedValues; - } - - /// - /// Gets or sets the default type weight. - /// - /// Determines the weight of types that do not have a WeightedPluginAttribute set on - /// them, when calling GetSortedValues. - protected virtual int DefaultPluginWeight { get; set; } = 10; - - /// - /// Returns the weight of an object for user with GetSortedValues - /// - /// - /// - protected virtual int GetObjectWeight(object o) - { - var type = o.GetType(); - var attr = type.GetCustomAttribute(true); - return attr?.Weight ?? DefaultPluginWeight; - } - - /// - /// Gets the resolved object instances. - /// - /// CanResolveBeforeFrozen is false, and resolution is not frozen. - protected IEnumerable Values => CreateValues(LifetimeScope); - - /// - /// Creates the values collection based on the scope - /// - /// - /// - protected virtual IEnumerable 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(); - //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(); - } - } - } - - /// - /// Instantiates the object instances for the types contained in the types collection. - /// - /// A list of objects of type . - protected virtual IEnumerable CreateInstances() - { - return ServiceProvider.CreateInstances(InstanceTypes, Logger); - } - - #region Types collection manipulation - - /// - /// Removes a type. - /// - /// The type to remove. - /// the resolver does not support removing types, or - /// the type is not a valid type for the resolver. - public virtual void RemoveType(Type value) - { - EnsureSupportsRemove(); - - using (Resolution.Configuration) - using (var l = new UpgradeableReadLock(_lock)) - { - EnsureCorrectType(value); - - l.UpgradeToWriteLock(); - _instanceTypes.Remove(value); - } - } - - /// - /// Removes a type. - /// - /// The type to remove. - /// the resolver does not support removing types, or - /// the type is not a valid type for the resolver. - public void RemoveType() - where T : TResolved - { - RemoveType(typeof(T)); - } - - /// - /// Adds types. - /// - /// The types to add. - /// The types are appended at the end of the list. - /// 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. - protected void AddTypes(IEnumerable 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); - } - } - } - - /// - /// Adds a type. - /// - /// The type to add. - /// The type is appended at the end of the list. - /// 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. - 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); - } - } - - /// - /// Adds a type. - /// - /// The type to add. - /// The type is appended at the end of the list. - /// 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. - public void AddType() - where T : TResolved - { - AddType(typeof(T)); - } - - /// - /// Clears the list of types - /// - /// the resolver does not support clearing types. - public virtual void Clear() - { - EnsureSupportsClear(); - - using (Resolution.Configuration) - using (new WriteLock(_lock)) - { - _instanceTypes.Clear(); - } - } - - /// - /// 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 - /// - internal void ResetCollections() - { - using (new WriteLock(_lock)) - { - _instanceTypes.Clear(); - _sortedValues = null; - _applicationInstances = null; - } - } - - /// - /// Inserts a type at the specified index. - /// - /// The zero-based index at which the type should be inserted. - /// The type to insert. - /// 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. - /// is out of range. - 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); - } - } - - /// - /// Inserts a type at the beginning of the list. - /// - /// The type to insert. - /// 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. - public virtual void InsertType(Type value) - { - InsertType(0, value); - } - - /// - /// Inserts a type at the specified index. - /// - /// The type to insert. - /// The zero-based index at which the type should be inserted. - /// is out of range. - public void InsertType(int index) - where T : TResolved - { - InsertType(index, typeof(T)); - } - - /// - /// Inserts a type at the beginning of the list. - /// - /// The type to insert. - public void InsertType() - where T : TResolved - { - InsertType(0, typeof(T)); - } - - /// - /// Inserts a type before a specified, already existing type. - /// - /// The existing type before which to insert. - /// The type to insert. - /// 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. - 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); - } - } - - /// - /// Inserts a type before a specified, already existing type. - /// - /// The existing type before which to insert. - /// The type to insert. - /// 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. - public void InsertTypeBefore() - where TExisting : TResolved - where T : TResolved - { - InsertTypeBefore(typeof(TExisting), typeof(T)); - } - - /// - /// Returns a value indicating whether the specified type is already in the collection of types. - /// - /// The type to look for. - /// A value indicating whether the type is already in the collection of types. - public virtual bool ContainsType(Type value) - { - using (new ReadLock(_lock)) - { - return _instanceTypes.Contains(value); - } - } - - /// - /// Gets the types in the collection of types. - /// - /// The types in the collection of types. - /// Returns an enumeration, the list cannot be modified. - public virtual IEnumerable GetTypes() - { - Type[] types; - using (new ReadLock(_lock)) - { - types = _instanceTypes.ToArray(); - } - return types; - } - - /// - /// Returns a value indicating whether the specified type is already in the collection of types. - /// - /// The type to look for. - /// A value indicating whether the type is already in the collection of types. - public bool ContainsType() - where T : TResolved - { - return ContainsType(typeof(T)); - } - - #endregion - - /// - /// Returns a WriteLock to use when modifying collections - /// - /// - protected WriteLock GetWriteLock() - { - return new WriteLock(_lock); - } - - #region Type utilities - - /// - /// Ensures that a type is a valid type for the resolver. - /// - /// The type to test. - /// the type is not a valid type for the resolver. - protected virtual void EnsureCorrectType(Type value) - { - if (TypeHelper.IsTypeAssignableFrom(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 - - /// - /// Ensures that the resolver supports removing types. - /// - /// The resolver does not support removing types. - protected void EnsureSupportsRemove() - { - if (SupportsRemove == false) - throw new InvalidOperationException("This resolver does not support removing types"); - } - - /// - /// Ensures that the resolver supports clearing types. - /// - /// The resolver does not support clearing types. - protected void EnsureSupportsClear() - { - if (SupportsClear == false) - throw new InvalidOperationException("This resolver does not support clearing types"); - } - - /// - /// Ensures that the resolver supports adding types. - /// - /// The resolver does not support adding types. - protected void EnsureSupportsAdd() - { - if (SupportsAdd == false) - throw new InvalidOperationException("This resolver does not support adding new types"); - } - - /// - /// Ensures that the resolver supports inserting types. - /// - /// The resolver does not support inserting types. - protected void EnsureSupportsInsert() - { - if (SupportsInsert == false) - throw new InvalidOperationException("This resolver does not support inserting new types"); - } - - /// - /// Gets a value indicating whether the resolver supports adding types. - /// - protected virtual bool SupportsAdd - { - get { return true; } - } - - /// - /// Gets a value indicating whether the resolver supports inserting types. - /// - protected virtual bool SupportsInsert - { - get { return true; } - } - - /// - /// Gets a value indicating whether the resolver supports clearing types. - /// - protected virtual bool SupportsClear - { - get { return true; } - } - - /// - /// Gets a value indicating whether the resolver supports removing types. - /// - protected virtual bool SupportsRemove - { - get { return true; } - } - - #endregion - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/ObjectResolution/WeightedPluginAttribute.cs b/src/Umbraco.Core/ObjectResolution/WeightedPluginAttribute.cs deleted file mode 100644 index 323142bd4c..0000000000 --- a/src/Umbraco.Core/ObjectResolution/WeightedPluginAttribute.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -namespace Umbraco.Core.ObjectResolution -{ - /// - /// Indicates the relative weight of a resolved object type. - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] - internal class WeightedPluginAttribute : Attribute - { - /// - /// Initializes a new instance of the class with a weight. - /// - /// The object type weight. - public WeightedPluginAttribute(int weight) - { - Weight = weight; - } - - /// - /// Gets or sets the weight of the object type. - /// - public int Weight { get; private set; } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 8ceb9d7bbf..8c32f10f94 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -306,7 +306,6 @@ - @@ -1119,7 +1118,6 @@ - @@ -1141,7 +1139,6 @@ - diff --git a/src/Umbraco.Tests/Resolvers/CollectionBuildersTests.cs b/src/Umbraco.Tests/Resolvers/CollectionBuildersTests.cs new file mode 100644 index 0000000000..4fbf66aa96 --- /dev/null +++ b/src/Umbraco.Tests/Resolvers/CollectionBuildersTests.cs @@ -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 + { + public TestCollectionBuilder(IServiceContainer container) + : base(container) + { } + + protected override TestCollectionBuilder This => this; + } + + private class TestCollectionBuilderTransient : OrderedCollectionBuilderBase + { + public TestCollectionBuilderTransient(IServiceContainer container) + : base(container) + { } + + protected override TestCollectionBuilderTransient This => this; + + protected override ILifetime CollectionLifetime => null; // transient + } + + private class TestCollectionBuilderScope : OrderedCollectionBuilderBase + { + public TestCollectionBuilderScope(IServiceContainer container) + : base(container) + { } + + protected override TestCollectionBuilderScope This => this; + + protected override ILifetime CollectionLifetime => new PerScopeLifetime(); + } + + private class TestCollectionBuilderWeighted : WeightedCollectionBuilderBase + { + public TestCollectionBuilderWeighted(IServiceContainer container) + : base(container) + { } + + protected override TestCollectionBuilderWeighted This => this; + } + + private class TestCollection : BuilderCollectionBase + { + public TestCollection(IEnumerable items) + : base(items) + { } + } + + #endregion + + [Test] + public void ContainsTypes() + { + var builder = TestCollectionBuilder.Register(_container) + .Append() + .Append(); + + Assert.IsTrue(builder.Has()); + Assert.IsTrue(builder.Has()); + Assert.IsFalse(builder.Has()); + //Assert.IsFalse(col.ContainsType()); // does not compile + + var col = builder.CreateCollection(); + AssertCollection(col, typeof(Resolved1), typeof(Resolved2)); + } + + [Test] + public void Clear() + { + var builder = TestCollectionBuilder.Register(_container) + .Append() + .Append(); + + builder.Clear(); + Assert.IsFalse(builder.Has()); + Assert.IsFalse(builder.Has()); + + var col = builder.CreateCollection(); + AssertCollection(col); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ClearOnceResolved() + { + var builder = TestCollectionBuilder.Register(_container) + .Append() + .Append(); + + var col = builder.CreateCollection(); + builder.Clear(); + } + + [Test] + public void Append() + { + var builder = TestCollectionBuilder.Register(_container); + builder.Append(); + builder.Append(); + + Assert.IsTrue(builder.Has()); + Assert.IsTrue(builder.Has()); + Assert.IsFalse(builder.Has()); + + 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(); + } + + [Test] + public void AppendDuplicate() + { + var builder = TestCollectionBuilder.Register(_container); + builder.Append(); + builder.Append(); + + var col = builder.CreateCollection(); + AssertCollection(col, typeof(Resolved1)); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void AppendInvalid() + { + var builder = TestCollectionBuilder.Register(_container); + //builder.Append(); // does not compile + builder.Append(new[] { typeof(Resolved4) }); // throws + } + + [Test] + public void Remove() + { + var builder = TestCollectionBuilder.Register(_container) + .Append() + .Append() + .Remove(); + + Assert.IsTrue(builder.Has()); + Assert.IsFalse(builder.Has()); + Assert.IsFalse(builder.Has()); + + var col = builder.CreateCollection(); + AssertCollection(col, typeof(Resolved1)); + } + + [Test] + public void RemoveAbsent() + { + var builder = TestCollectionBuilder.Register(_container) + .Append() + .Append() + .Remove(); + + var col = builder.CreateCollection(); + AssertCollection(col, typeof(Resolved1), typeof(Resolved2)); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void RemoveOnceResolved() + { + var builder = TestCollectionBuilder.Register(_container) + .Append() + .Append(); + + var col = builder.CreateCollection(); + builder.Remove(); // throws + } + + [Test] + public void Insert() + { + var builder = TestCollectionBuilder.Register(_container) + .Append() + .Append() + .Insert(); + + Assert.IsTrue(builder.Has()); + Assert.IsTrue(builder.Has()); + Assert.IsTrue(builder.Has()); + + 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() + .Append(); + + var col = builder.CreateCollection(); + builder.Insert(); // throws + } + + [Test] + public void CanInsertDuplicate() + { + var builder = TestCollectionBuilder.Register(_container) + .Append() + .Append() + .Insert(); + + var col = builder.CreateCollection(); + AssertCollection(col, typeof(Resolved2), typeof(Resolved1)); + } + + [Test] + public void InsertInEmpty() + { + var builder = TestCollectionBuilder.Register(_container); + builder.Insert(); + + var col = builder.CreateCollection(); + AssertCollection(col, typeof(Resolved2)); + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void InsertAtWrongIndex1() + { + var builder = TestCollectionBuilder.Register(_container) + .Append() + .Append(); + + builder.Insert(99); // throws + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void InsertAtWrongIndex2() + { + var builder = TestCollectionBuilder.Register(_container) + .Append() + .Append(); + + builder.Insert(-1); // throws + } + + [Test] + public void InsertBefore() + { + var builder = TestCollectionBuilder.Register(_container) + .Append() + .Append() + .InsertBefore(); + + Assert.IsTrue(builder.Has()); + Assert.IsTrue(builder.Has()); + Assert.IsTrue(builder.Has()); + + 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() + .Append(); + + var col = builder.CreateCollection(); + builder.InsertBefore(); + } + + [Test] + public void InsertBeforeDuplicate() + { + var builder = TestCollectionBuilder.Register(_container) + .Append() + .Append() + .InsertBefore(); + + var col = builder.CreateCollection(); + AssertCollection(col, typeof(Resolved2), typeof(Resolved1)); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void InsertBeforeAbsent() + { + var builder = TestCollectionBuilder.Register(_container) + .Append() + .InsertBefore(); + } + + [Test] + public void ScopeIsApplication() + { + TestCollectionBuilder.Register(_container) + .Append() + .Append(); + + // 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(); + AssertCollection(col1, typeof(Resolved1), typeof(Resolved2)); + + var col2 = _container.GetInstance(); + AssertCollection(col2, typeof(Resolved1), typeof(Resolved2)); + + AssertSameCollection(col1, col2); + } + + [Test] + public void ScopeIsTransient() + { + TestCollectionBuilderTransient.Register(_container) + .Append() + .Append(); + + // 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(); + AssertCollection(col1, typeof(Resolved1), typeof(Resolved2)); + + var col2 = _container.GetInstance(); + AssertCollection(col1, typeof(Resolved1), typeof(Resolved2)); + + AssertNotSameCollection(col1, col2); + } + + [Test] + public void OrderOfTypes() + { + var builder = TestCollectionBuilderTransient.Register(_container) + .Append() + .Insert() + .InsertBefore(); + + var col1 = builder.CreateCollection(); + AssertCollection(col1, typeof(Resolved1), typeof(Resolved2), typeof(Resolved3)); + } + + [Test] + public void ScopeIsScope() + { + TestCollectionBuilderScope.Register(_container) + .Append() + .Append(); + + // 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(); + AssertCollection(col1A, typeof(Resolved1), typeof(Resolved2)); + var col1B = _container.GetInstance(); + AssertCollection(col1B, typeof(Resolved1), typeof(Resolved2)); + + AssertSameCollection(col1A, col1B); + + _container.EndCurrentScope(); + var scope2 = _container.BeginScope(); + + var col2 = _container.GetInstance(); + AssertCollection(col2, typeof(Resolved1), typeof(Resolved2)); + + AssertNotSameCollection(col1A, col2); + + _container.EndCurrentScope(); + } + + [Test] + public void Weights() + { + var builder = TestCollectionBuilderWeighted.Register(_container) + .Add() + .Add(); + + var col = builder.CreateCollection(); + AssertCollection(col, typeof(Resolved2), typeof(Resolved1)); + } + + private static void AssertCollection(IEnumerable 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 col1, IEnumerable 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 col1, IEnumerable 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]); + } + } +} diff --git a/src/Umbraco.Tests/Resolvers/ManyResolverTests.cs b/src/Umbraco.Tests/Resolvers/ManyResolverTests.cs deleted file mode 100644 index 4cf1c3b56f..0000000000 --- a/src/Umbraco.Tests/Resolvers/ManyResolverTests.cs +++ /dev/null @@ -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 - { - public ManyResolver(IServiceProvider serviceProvider, ILogger logger) - : base(serviceProvider, logger) - { } - - public ManyResolver(IServiceProvider serviceProvider, ILogger logger, IEnumerable value) - : base(serviceProvider, logger, value) - { } - - public ManyResolver(IServiceProvider serviceProvider, ILogger logger, IEnumerable value, ObjectLifetimeScope scope) - : base(serviceProvider, logger, value, scope) - { } - - public ManyResolver(IServiceProvider serviceProvider, ILogger logger, HttpContextBase httpContext) - : base(serviceProvider, logger, httpContext) - { } - - public IEnumerable SortedResolvedObjects { get { return GetSortedValues(); } } - public IEnumerable ResolvedObjects { get { return Values; } } - } - - #endregion - - #region Test ManyResolver types collection manipulation - - [Test] - public void ManyResolverContainsTypes() - { - var resolver = new ManyResolver( - new ActivatorServiceProvider(), Mock.Of(), - new Type[] { typeof(Resolved1), typeof(Resolved2) }); - - Assert.IsTrue(resolver.ContainsType()); - Assert.IsTrue(resolver.ContainsType()); - Assert.IsFalse(resolver.ContainsType()); - //Assert.IsFalse(resolver.ContainsType()); // does not compile - } - - [Test] - public void ManyResolverCanClearBeforeFreeze() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of()); - resolver.AddType(); - resolver.AddType(); - resolver.Clear(); - Assert.IsFalse(resolver.ContainsType()); - Assert.IsFalse(resolver.ContainsType()); - } - - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ManyResolverCannotClearOnceFrozen() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of()); - resolver.AddType(); - resolver.AddType(); - Resolution.Freeze(); - resolver.Clear(); - } - - [Test] - public void ManyResolverCanAddTypeBeforeFreeze() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of()); - resolver.AddType(); - resolver.AddType(); - - Assert.IsTrue(resolver.ContainsType()); - Assert.IsTrue(resolver.ContainsType()); - Assert.IsFalse(resolver.ContainsType()); - } - - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ManyResolverCannotAddTypeOnceFrozen() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of()); - Resolution.Freeze(); - resolver.AddType(); - } - - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ManyResolverCannotAddTypeAgain() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of()); - resolver.AddType(); - resolver.AddType(); - } - - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ManyResolverCannotAddInvalidType() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of()); - //resolver.AddType(); // does not compile - resolver.AddType(typeof(Resolved4)); // throws - } - - [Test] - public void ManyResolverCanRemoveTypeBeforeFreeze() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - resolver.RemoveType(); - - Assert.IsTrue(resolver.ContainsType()); - Assert.IsFalse(resolver.ContainsType()); - Assert.IsFalse(resolver.ContainsType()); - } - - [Test] - public void ManyResolverCanRemoveAbsentType() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - resolver.RemoveType(); - } - - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ManyResolverCannotRemoveInvalidType() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - //resolver.RemoveType(); // does not compile - resolver.RemoveType(typeof(Resolved4)); // throws - } - - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ManyResolverCannotRemoveTypeOnceFrozen() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - Resolution.Freeze(); - resolver.RemoveType(); // throws - } - - [Test] - public void ManyResolverCanInsertTypeBeforeFreeze() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - resolver.InsertType(0); - - Assert.IsTrue(resolver.ContainsType()); - Assert.IsTrue(resolver.ContainsType()); - Assert.IsTrue(resolver.ContainsType()); - } - - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ManyResolverCannotInsertTypeOnceFrozen() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - Resolution.Freeze(); - resolver.InsertType(0); - } - - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ManyResolverCannotInsertTypeAgain() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - resolver.InsertType(0); - } - - [Test] - public void ManyResolverCanInsertInEmptyList() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of()); - resolver.InsertType(); - } - - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ManyResolverCannotInsertInvalidType() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - //resolver.InsertType(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(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - resolver.InsertType(99, typeof(Resolved3)); // throws - } - - // - - [Test] - public void ManyResolverCanInsertBeforeTypeBeforeFreeze() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - resolver.InsertTypeBefore(); - - Assert.IsTrue(resolver.ContainsType()); - Assert.IsTrue(resolver.ContainsType()); - Assert.IsTrue(resolver.ContainsType()); - } - - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ManyResolverCannotInsertBeforeTypeOnceFrozen() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - Resolution.Freeze(); - resolver.InsertTypeBefore(); - } - - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ManyResolverCannotInsertBeforeTypeAgain() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - resolver.InsertTypeBefore(); - } - - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ManyResolverCannotInsertBeforeAbsentType() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), new Type[] { typeof(Resolved1) }); - resolver.InsertTypeBefore(); - } - - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ManyResolverCannotInsertBeforeInvalidType() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - //resolver.InsertTypeBefore(); // 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(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - var values = resolver.ResolvedObjects; - } - - [Test] - public void ManyResolverCannotGetValuesBeforeFreezeUnless() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), 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(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - Resolution.Freeze(); - var values = resolver.ResolvedObjects; - - Assert.AreEqual(2, values.Count()); - Assert.IsInstanceOf(values.ElementAt(0)); - Assert.IsInstanceOf(values.ElementAt(1)); - } - - [Test] - public void ManyResolverDefaultLifetimeScopeIsApplication() - { - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - Resolution.Freeze(); - var values = resolver.ResolvedObjects; - - Assert.AreEqual(2, values.Count()); - Assert.IsInstanceOf(values.ElementAt(0)); - Assert.IsInstanceOf(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(), new Type[] { typeof(Resolved1), typeof(Resolved2) }, ObjectLifetimeScope.Transient); - Resolution.Freeze(); - var values = resolver.ResolvedObjects; - - Assert.AreEqual(2, values.Count()); - Assert.IsInstanceOf(values.ElementAt(0)); - Assert.IsInstanceOf(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()); - resolver.AddType(); - resolver.InsertType(0); - resolver.InsertTypeBefore(); - Resolution.Freeze(); - var values = resolver.ResolvedObjects; - - Assert.AreEqual(3, values.Count()); - Assert.IsInstanceOf(values.ElementAt(0)); - Assert.IsInstanceOf(values.ElementAt(1)); - Assert.IsInstanceOf(values.ElementAt(2)); - } - - [Test] - public void ManyResolverHttpRequestLifetimeScope() - { - var httpContextFactory = new FakeHttpContextFactory("~/Home"); - var httpContext = httpContextFactory.HttpContext; - var resolver = new ManyResolver(new ActivatorServiceProvider(), Mock.Of(), httpContext); - - resolver.AddType(); - resolver.AddType(); - Resolution.Freeze(); - - var values = resolver.ResolvedObjects; - Assert.AreEqual(2, values.Count()); - Assert.IsInstanceOf(values.ElementAt(0)); - Assert.IsInstanceOf(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(), new Type[] { typeof(Resolved1), typeof(Resolved2) }); - Resolution.Freeze(); - - var values = resolver.SortedResolvedObjects; - Assert.AreEqual(2, values.Count()); - Assert.IsInstanceOf(values.ElementAt(0)); - Assert.IsInstanceOf(values.ElementAt(1)); - } - - #endregion - } -} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index d3915c1403..6bd785cca8 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -498,7 +498,7 @@ - +