2018-07-20 15:45:01 +02:00
|
|
|
|
using System;
|
2018-10-25 15:29:29 +02:00
|
|
|
|
using System.Collections.Concurrent;
|
2018-07-20 16:36:46 +02:00
|
|
|
|
using System.Collections.Generic;
|
2018-07-21 10:47:29 +02:00
|
|
|
|
using System.Linq;
|
2018-07-20 09:49:05 +02:00
|
|
|
|
|
2018-07-20 16:39:39 +02:00
|
|
|
|
namespace Umbraco.Core.Composing
|
2018-07-20 09:49:05 +02:00
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Provides extension methods to the <see cref="IContainer"/> class.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static class ContainerExtensions
|
|
|
|
|
|
{
|
2018-10-25 15:29:29 +02:00
|
|
|
|
private static readonly ConcurrentDictionary<Type, Dictionary<string, Func<object, object>>> ArgumentPropertyGetters
|
|
|
|
|
|
= new ConcurrentDictionary<Type, Dictionary<string, Func<object, object>>>();
|
|
|
|
|
|
|
2018-07-20 09:49:05 +02:00
|
|
|
|
/// <summary>
|
2018-10-25 15:29:29 +02:00
|
|
|
|
/// Gets an instance of a service.
|
2018-07-20 09:49:05 +02:00
|
|
|
|
/// </summary>
|
2018-10-25 15:29:29 +02:00
|
|
|
|
/// <typeparam name="T">The type of the service.</typeparam>
|
2018-07-20 09:49:05 +02:00
|
|
|
|
/// <param name="container">The container.</param>
|
|
|
|
|
|
/// <returns>An instance of the specified type.</returns>
|
|
|
|
|
|
/// <remarks>Throws an exception if the container failed to get an instance of the specified type.</remarks>
|
|
|
|
|
|
public static T GetInstance<T>(this IContainer container)
|
|
|
|
|
|
=> (T) container.GetInstance(typeof(T));
|
|
|
|
|
|
|
2018-09-02 22:09:37 +02:00
|
|
|
|
/// <summary>
|
2018-10-25 15:29:29 +02:00
|
|
|
|
/// Gets an instance of a named service.
|
2018-09-02 22:09:37 +02:00
|
|
|
|
/// </summary>
|
2018-10-25 15:29:29 +02:00
|
|
|
|
/// <typeparam name="T">The type of the service.</typeparam>
|
2018-09-02 22:09:37 +02:00
|
|
|
|
/// <param name="container">The container.</param>
|
2018-10-25 15:29:29 +02:00
|
|
|
|
/// <param name="name">The name of the service.</param>
|
2018-09-02 22:09:37 +02:00
|
|
|
|
/// <returns>An instance of the specified type and name.</returns>
|
|
|
|
|
|
/// <remarks>Throws an exception if the container failed to get an instance of the specified type.</remarks>
|
|
|
|
|
|
public static T GetInstance<T>(this IContainer container, string name)
|
|
|
|
|
|
=> (T) container.GetInstance(typeof(T), name);
|
|
|
|
|
|
|
2018-08-29 18:50:08 +02:00
|
|
|
|
/// <summary>
|
2018-10-25 15:29:29 +02:00
|
|
|
|
/// Tries to get an instance of a service.
|
2018-08-29 18:50:08 +02:00
|
|
|
|
/// </summary>
|
2018-10-25 15:29:29 +02:00
|
|
|
|
/// <typeparam name="T">The type of the service.</typeparam>
|
2018-08-29 18:50:08 +02:00
|
|
|
|
/// <returns>An instance of the specified type, or null.</returns>
|
|
|
|
|
|
/// <remarks>Returns null if the container does not know how to get an instance
|
|
|
|
|
|
/// of the specified type. Throws an exception if the container does know how
|
|
|
|
|
|
/// to get an instance of the specified type, but failed to do so.</remarks>
|
|
|
|
|
|
public static T TryGetInstance<T>(this IContainer container)
|
|
|
|
|
|
=> (T) container.TryGetInstance(typeof(T));
|
|
|
|
|
|
|
2018-07-23 09:21:55 +02:00
|
|
|
|
/// <summary>
|
2018-10-25 15:29:29 +02:00
|
|
|
|
/// Gets registrations for a service.
|
2018-07-23 09:21:55 +02:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="TService">The type of the service.</typeparam>
|
|
|
|
|
|
/// <returns>The registrations for the service.</returns>
|
2018-07-20 16:36:46 +02:00
|
|
|
|
public static IEnumerable<Registration> GetRegistered<TService>(this IContainer container)
|
|
|
|
|
|
=> container.GetRegistered(typeof(TService));
|
|
|
|
|
|
|
2018-07-23 09:21:55 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Creates an instance with arguments.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T">The type of the instance.</typeparam>
|
|
|
|
|
|
/// <param name="container">The container.</param>
|
|
|
|
|
|
/// <param name="args">Arguments.</param>
|
|
|
|
|
|
/// <returns>An instance of the specified type.</returns>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// <para>Throws an exception if the container failed to get an instance of the specified type.</para>
|
|
|
|
|
|
/// <para>The arguments are used as dependencies by the container.</para>
|
|
|
|
|
|
/// </remarks>
|
2018-09-02 22:09:37 +02:00
|
|
|
|
public static T CreateInstance<T>(this IContainer container, IDictionary<string, object> args)
|
2018-07-23 09:21:55 +02:00
|
|
|
|
=> (T) container.CreateInstance(typeof(T), args);
|
|
|
|
|
|
|
2018-10-25 15:29:29 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Creates an instance with arguments.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T">The type of the instance.</typeparam>
|
|
|
|
|
|
/// <param name="container">The container.</param>
|
|
|
|
|
|
/// <param name="args">Arguments.</param>
|
|
|
|
|
|
/// <returns>An instance of the specified type.</returns>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// <para>Throws an exception if the container failed to get an instance of the specified type.</para>
|
|
|
|
|
|
/// <para>The arguments are used as dependencies by the container.</para>
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public static T CreateInstance<T>(this IContainer container, object args)
|
|
|
|
|
|
{
|
|
|
|
|
|
var typeOfArgs = args.GetType();
|
|
|
|
|
|
var getters = ArgumentPropertyGetters.GetOrAdd(typeOfArgs, type =>
|
|
|
|
|
|
args.GetType()
|
|
|
|
|
|
.GetProperties()
|
|
|
|
|
|
.ToDictionary(x => x.Name, x => ReflectionUtilities.EmitMethodUnsafe<Func<object, object>>(x.GetMethod)));
|
|
|
|
|
|
|
|
|
|
|
|
var argsDictionary = new Dictionary<string, object>();
|
|
|
|
|
|
foreach (var (name, getter) in getters)
|
|
|
|
|
|
argsDictionary[name] = getter(args);
|
|
|
|
|
|
|
|
|
|
|
|
return (T) container.CreateInstance(typeof(T), argsDictionary);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-07-23 09:21:55 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Registers a service with an implementation type.
|
|
|
|
|
|
/// </summary>
|
2018-07-20 15:45:01 +02:00
|
|
|
|
public static void Register<TService, TImplementing>(this IContainer container, Lifetime lifetime = Lifetime.Transient)
|
|
|
|
|
|
=> container.Register(typeof(TService), typeof(TImplementing), lifetime);
|
|
|
|
|
|
|
2018-07-23 09:21:55 +02:00
|
|
|
|
/// <summary>
|
2018-10-25 15:29:29 +02:00
|
|
|
|
/// Registers a named service with an implementation type.
|
2018-07-23 09:21:55 +02:00
|
|
|
|
/// </summary>
|
2018-07-20 15:45:01 +02:00
|
|
|
|
public static void Register<TService, TImplementing>(this IContainer container, string name, Lifetime lifetime = Lifetime.Transient)
|
|
|
|
|
|
=> container.Register(typeof(TService), typeof(TImplementing), name, lifetime);
|
|
|
|
|
|
|
2018-09-02 22:09:37 +02:00
|
|
|
|
/// <summary>
|
2018-10-25 15:29:29 +02:00
|
|
|
|
/// Registers a named service with an implementation factory.
|
2018-09-02 22:09:37 +02:00
|
|
|
|
/// </summary>
|
2018-10-25 15:29:29 +02:00
|
|
|
|
public static void Register<TService>(this IContainer container, string name, Func<IContainer, TService> factory, Lifetime lifetime = Lifetime.Transient)
|
2018-09-02 22:09:37 +02:00
|
|
|
|
=> container.Register(factory, name, lifetime);
|
|
|
|
|
|
|
2018-07-23 09:21:55 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Registers a service as its own implementation.
|
|
|
|
|
|
/// </summary>
|
2018-07-20 15:45:01 +02:00
|
|
|
|
public static void Register<TService>(this IContainer container, Lifetime lifetime = Lifetime.Transient)
|
|
|
|
|
|
=> container.Register(typeof(TService), lifetime);
|
|
|
|
|
|
|
2018-07-23 09:21:55 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Registers a singleton service as its own implementation.
|
|
|
|
|
|
/// </summary>
|
2018-07-20 15:45:01 +02:00
|
|
|
|
public static void RegisterSingleton<TService>(this IContainer container)
|
|
|
|
|
|
=> container.Register(typeof(TService), Lifetime.Singleton);
|
|
|
|
|
|
|
2018-07-23 09:21:55 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Registers a singleton service with an implementation type.
|
|
|
|
|
|
/// </summary>
|
2018-07-20 15:45:01 +02:00
|
|
|
|
public static void RegisterSingleton<TService, TImplementing>(this IContainer container)
|
|
|
|
|
|
=> container.Register(typeof(TService), typeof(TImplementing), Lifetime.Singleton);
|
|
|
|
|
|
|
2018-07-23 09:21:55 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Registers a singleton service with an implementation factory.
|
|
|
|
|
|
/// </summary>
|
2018-07-20 15:45:01 +02:00
|
|
|
|
public static void RegisterSingleton<TService>(this IContainer container, Func<IContainer, TService> factory)
|
|
|
|
|
|
=> container.Register(factory, Lifetime.Singleton);
|
|
|
|
|
|
|
2018-09-09 22:46:14 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Registers a named singleton service with an implementation factory.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static void RegisterSingleton<TService>(this IContainer container, string name, Func<IContainer, TService> factory)
|
|
|
|
|
|
=> container.Register(factory, name, Lifetime.Singleton);
|
|
|
|
|
|
|
2018-07-23 09:21:55 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Registers a service with an implementing instance.
|
|
|
|
|
|
/// </summary>
|
2018-07-20 15:45:01 +02:00
|
|
|
|
public static void RegisterInstance<TService>(this IContainer container, TService instance)
|
|
|
|
|
|
=> container.RegisterInstance(typeof(TService), instance);
|
|
|
|
|
|
|
2018-07-23 09:21:55 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Registers a base type for auto-registration.
|
|
|
|
|
|
/// </summary>
|
2018-07-20 15:45:01 +02:00
|
|
|
|
public static void RegisterAuto<TServiceBase>(this IContainer container)
|
|
|
|
|
|
=> container.RegisterAuto(typeof(TServiceBase));
|
2018-07-21 10:47:29 +02:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2018-10-25 15:29:29 +02:00
|
|
|
|
/// Registers and instantiates a collection builder.
|
2018-07-21 10:47:29 +02:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="TBuilder">The type of the collection builder.</typeparam>
|
|
|
|
|
|
/// <returns>A collection builder of the specified type.</returns>
|
|
|
|
|
|
public static TBuilder RegisterCollectionBuilder<TBuilder>(this IContainer container)
|
|
|
|
|
|
{
|
|
|
|
|
|
// make sure it's not already registered
|
|
|
|
|
|
// we just don't want to support re-registering collection builders
|
|
|
|
|
|
if (container.GetRegistered<TBuilder>().Any())
|
|
|
|
|
|
throw new InvalidOperationException("Collection builders should be registered only once.");
|
|
|
|
|
|
|
2018-09-02 22:09:37 +02:00
|
|
|
|
// register the builder
|
2018-10-25 15:29:29 +02:00
|
|
|
|
// use a factory so we don't have to self-register the container
|
|
|
|
|
|
container.RegisterSingleton(factory => factory.CreateInstance<TBuilder>(new Dictionary<string, object> {{ "container", container }} ));
|
2018-07-21 10:47:29 +02:00
|
|
|
|
|
2018-07-23 09:21:55 +02:00
|
|
|
|
// initialize and return the builder
|
|
|
|
|
|
return container.GetInstance<TBuilder>();
|
2018-07-21 10:47:29 +02:00
|
|
|
|
}
|
2018-07-20 09:49:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|