Resvolution - Prepare
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
using LightInject;
|
||||
using System.Collections.Generic;
|
||||
using LightInject;
|
||||
using Umbraco.Core.Strings;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
// must remain internal - this class is here to support the transition from singletons
|
||||
// and resolvers to injection - by providing a static access to singleton services - it
|
||||
// is initialized once with a service container, in WebBootManager.
|
||||
// is initialized once with a service container, in CoreBootManager.
|
||||
internal class Current
|
||||
{
|
||||
public static IServiceContainer Container { get; set; } // ok to set - don't be stupid
|
||||
|
||||
16
src/Umbraco.Core/DependencyInjection/IInjectCollection.cs
Normal file
16
src/Umbraco.Core/DependencyInjection/IInjectCollection.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an injected collection, ie an immutable enumeration of items.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem">The type of the items.</typeparam>
|
||||
public interface IInjectCollection<out TItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the items in the collection.
|
||||
/// </summary>
|
||||
IEnumerable<TItem> Items { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace Umbraco.Core.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an injected collection builder.
|
||||
/// </summary>
|
||||
/// <typeparam name="TCollection">The type of the collection.</typeparam>
|
||||
/// <typeparam name="TItem">The type of the items.</typeparam>
|
||||
public interface IInjectCollectionBuilder<out TCollection, TItem>
|
||||
where TCollection : IInjectCollection<TItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a collection.
|
||||
/// </summary>
|
||||
/// <returns>A collection.</returns>
|
||||
/// <remarks>The lifetime of the collection depends on how the builder was registered.</remarks>
|
||||
TCollection GetCollection();
|
||||
}
|
||||
}
|
||||
23
src/Umbraco.Core/DependencyInjection/InjectCollectionBase.cs
Normal file
23
src/Umbraco.Core/DependencyInjection/InjectCollectionBase.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for injected collections.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem">The type of the items.</typeparam>
|
||||
public abstract class InjectCollectionBase<TItem> : IInjectCollection<TItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InjectCollectionBase{TItem}"/> with items.
|
||||
/// </summary>
|
||||
/// <param name="items">The items.</param>
|
||||
protected InjectCollectionBase(IEnumerable<TItem> items)
|
||||
{
|
||||
Items = items;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<TItem> Items { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
|
||||
namespace Umbraco.Core.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for injected collection builders.
|
||||
/// </summary>
|
||||
/// <typeparam name="TCollection">The type of the collection.</typeparam>
|
||||
/// <typeparam name="TItem">The type of the items.</typeparam>
|
||||
public abstract class InjectCollectionBuilderBase<TCollection, TItem> : IInjectCollectionBuilder<TCollection, TItem>
|
||||
where TCollection : IInjectCollection<TItem>
|
||||
{
|
||||
private readonly IServiceContainer _container;
|
||||
private readonly List<Type> _types = new List<Type>();
|
||||
private readonly object _locker = new object();
|
||||
private bool _typesRegistered;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InjectCollectionBuilderBase{TCollection, TItem}"/>
|
||||
/// class with a service container.
|
||||
/// </summary>
|
||||
/// <param name="container">A service container.</param>
|
||||
protected InjectCollectionBuilderBase(IServiceContainer container)
|
||||
{
|
||||
_container = container;
|
||||
}
|
||||
|
||||
// everything could be implemented, add, insert, remove, replace, order, whatever...
|
||||
// and we could also have 'lazy' collections by supplying a types factory
|
||||
|
||||
protected void Configure(Action action)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
if (_typesRegistered) throw new InvalidOperationException();
|
||||
action();
|
||||
}
|
||||
}
|
||||
|
||||
public void Add<T>()
|
||||
where T : TItem
|
||||
{
|
||||
Configure(() =>
|
||||
{
|
||||
var type = typeof(T);
|
||||
if (!_types.Contains(type))
|
||||
_types.Add(type);
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<Type> PrepareTypes(IEnumerable<Type> types)
|
||||
{
|
||||
return types;
|
||||
}
|
||||
|
||||
private void RegisterTypes()
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
if (_typesRegistered) return;
|
||||
|
||||
var prefix = GetType().FullName + "_";
|
||||
var i = 0;
|
||||
foreach (var type in PrepareTypes(_types))
|
||||
{
|
||||
var name = $"{prefix}{i++:00000}";
|
||||
_container.Register(typeof(TItem), type, name);
|
||||
}
|
||||
|
||||
_typesRegistered = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection.
|
||||
/// </summary>
|
||||
/// <returns>A collection.</returns>
|
||||
/// <remarks>
|
||||
/// <para>Creates a new collection each time it is invoked, but only registers types once.</para>
|
||||
/// <para>Explicitely implemented in order to hide it to users.</para>
|
||||
/// </remarks>
|
||||
TCollection IInjectCollectionBuilder<TCollection, TItem>.GetCollection()
|
||||
{
|
||||
RegisterTypes(); // will do it only once
|
||||
|
||||
var prefix = GetType().FullName + "_";
|
||||
|
||||
// fixme - shouldn't we save this somewhere?
|
||||
var services = _container.AvailableServices
|
||||
.Where(x => x.ServiceName.StartsWith(prefix))
|
||||
.OrderBy(x => x.ServiceName);
|
||||
|
||||
var items = services
|
||||
.Select(x => _container.GetInstance<TItem>(x.ServiceName))
|
||||
.ToArray();
|
||||
|
||||
return CreateCollection(items);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the injected collection.
|
||||
/// </summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>An injected collection containing the items.</returns>
|
||||
protected abstract TCollection CreateCollection(IEnumerable<TItem> items);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
|
||||
namespace Umbraco.Core.DependencyInjection
|
||||
{
|
||||
public abstract class InjectLazyCollectionBuilderBase<TCollection, TItem> : InjectCollectionBuilderBase<TCollection, TItem>
|
||||
where TCollection : IInjectCollection<TItem>
|
||||
{
|
||||
private readonly List<Func<IEnumerable<Type>>> _producers = new List<Func<IEnumerable<Type>>>();
|
||||
private readonly List<Type> _excluded = new List<Type>();
|
||||
|
||||
protected InjectLazyCollectionBuilderBase(IServiceContainer container)
|
||||
: base(container)
|
||||
{ }
|
||||
|
||||
protected override IEnumerable<Type> PrepareTypes(IEnumerable<Type> types)
|
||||
{
|
||||
return types.Union(_producers.SelectMany(x => x())).Distinct().Except(_excluded);
|
||||
}
|
||||
|
||||
public void AddProducer(Func<IEnumerable<Type>> producer)
|
||||
{
|
||||
Configure(() =>
|
||||
{
|
||||
_producers.Add(producer);
|
||||
});
|
||||
}
|
||||
|
||||
public void Exclude<T>()
|
||||
{
|
||||
Configure(() =>
|
||||
{
|
||||
var type = typeof(T);
|
||||
if (!_excluded.Contains(type))
|
||||
_excluded.Add(type);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
|
||||
namespace Umbraco.Core.DependencyInjection
|
||||
{
|
||||
public abstract class InjectWeightedCollectionBuilderBase<TCollection, TItem> : InjectCollectionBuilderBase<TCollection, TItem>
|
||||
where TCollection : IInjectCollection<TItem>
|
||||
{
|
||||
protected InjectWeightedCollectionBuilderBase(IServiceContainer container)
|
||||
: base(container)
|
||||
{ }
|
||||
|
||||
protected override IEnumerable<Type> PrepareTypes(IEnumerable<Type> types)
|
||||
{
|
||||
var list = types.ToList();
|
||||
list.Sort((t1, t2) => GetWeight(t1).CompareTo(GetWeight(t2)));
|
||||
return list;
|
||||
}
|
||||
|
||||
protected virtual int DefaultWeight { get; set; } = 10;
|
||||
|
||||
protected virtual int GetWeight(Type type)
|
||||
{
|
||||
var attr = type.GetCustomAttributes(typeof(WeightAttribute), false).OfType<WeightAttribute>().SingleOrDefault();
|
||||
return attr?.Weight ?? DefaultWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,6 +162,36 @@ namespace Umbraco.Core.DependencyInjection
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Registers an injected collection.
|
||||
/// </summary>
|
||||
/// <typeparam name="TBuilder">The type of the collection builder.</typeparam>
|
||||
/// <typeparam name="TCollection">The type of the collection.</typeparam>
|
||||
/// <typeparam name="TItem">The type of the items.</typeparam>
|
||||
/// <param name="container">A container.</param>
|
||||
public static void RegisterCollection<TBuilder, TCollection, TItem>(this IServiceRegistry container)
|
||||
where TCollection : IInjectCollection<TItem>
|
||||
where TBuilder : IInjectCollectionBuilder<TCollection, TItem>
|
||||
{
|
||||
container.Register<TBuilder>(new PerContainerLifetime());
|
||||
container.Register(factory => factory.GetInstance<TBuilder>().GetCollection());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers an injected collection.
|
||||
/// </summary>
|
||||
/// <typeparam name="TBuilder">The type of the collection builder.</typeparam>
|
||||
/// <typeparam name="TCollection">The type of the collection.</typeparam>
|
||||
/// <typeparam name="TItem">The type of the items.</typeparam>
|
||||
/// <typeparam name="TLifetime">A lifetime type.</typeparam>
|
||||
/// <param name="container">A container.</param>
|
||||
public static void RegisterCollection<TBuilder, TCollection, TItem, TLifetime>(this IServiceRegistry container)
|
||||
where TCollection : IInjectCollection<TItem>
|
||||
where TBuilder : IInjectCollectionBuilder<TCollection, TItem>
|
||||
where TLifetime : ILifetime, new()
|
||||
{
|
||||
container.Register<TBuilder>(new PerContainerLifetime());
|
||||
container.Register(factory => factory.GetInstance<TBuilder>().GetCollection(), new TLifetime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
25
src/Umbraco.Core/DependencyInjection/WeightAttribute.cs
Normal file
25
src/Umbraco.Core/DependencyInjection/WeightAttribute.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the weight of pretty much anything.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
public class WeightAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WeightAttribute"/> class with a weight.
|
||||
/// </summary>
|
||||
/// <param name="weight"></param>
|
||||
public WeightAttribute(int weight)
|
||||
{
|
||||
Weight = weight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the weight value.
|
||||
/// </summary>
|
||||
public int Weight { get; }
|
||||
}
|
||||
}
|
||||
@@ -215,8 +215,15 @@
|
||||
<Compile Include="DelegateExtensions.cs" />
|
||||
<Compile Include="DependencyInjection\ConfigurationCompositionRoot.cs" />
|
||||
<Compile Include="DependencyInjection\CoreModelMappersCompositionRoot.cs" />
|
||||
<Compile Include="DependencyInjection\IInjectCollection.cs" />
|
||||
<Compile Include="DependencyInjection\IInjectCollectionBuilder.cs" />
|
||||
<Compile Include="DependencyInjection\InjectCollectionBase.cs" />
|
||||
<Compile Include="DependencyInjection\InjectCollectionBuilderBase.cs" />
|
||||
<Compile Include="DependencyInjection\InjectLazyCollectionBuilderBase.cs" />
|
||||
<Compile Include="DependencyInjection\InjectWeightedCollectionBuilderBase.cs" />
|
||||
<Compile Include="DependencyInjection\RepositoryCompositionRoot.cs" />
|
||||
<Compile Include="DependencyInjection\ServicesCompositionRoot.cs" />
|
||||
<Compile Include="DependencyInjection\WeightAttribute.cs" />
|
||||
<Compile Include="DictionaryExtensions.cs" />
|
||||
<Compile Include="Dictionary\CultureDictionaryFactoryResolver.cs" />
|
||||
<Compile Include="Dictionary\ICultureDictionaryFactory.cs" />
|
||||
@@ -1328,7 +1335,6 @@
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\" />
|
||||
<Folder Include="PublishedCache\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LightInject;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
|
||||
namespace Umbraco.Web
|
||||
@@ -32,7 +34,6 @@ namespace Umbraco.Web
|
||||
set { _umbracoContextAccessor = value; } // for tests
|
||||
}
|
||||
|
||||
|
||||
public static IFacadeAccessor FacadeAccessor
|
||||
{
|
||||
get
|
||||
@@ -44,7 +45,6 @@ namespace Umbraco.Web
|
||||
set { _facadeAccessor = value; } // for tests
|
||||
}
|
||||
|
||||
|
||||
public static UmbracoContext UmbracoContext => UmbracoContextAccessor.UmbracoContext;
|
||||
|
||||
// have to support set for now, because of 'ensure umbraco context' which can create
|
||||
|
||||
Reference in New Issue
Block a user