Skip to content
This repository was archived by the owner on Nov 2, 2018. It is now read-only.

Commit

Permalink
Adding support for service factories in IServiceDescriptor
Browse files Browse the repository at this point in the history
Fixes #104
  • Loading branch information
pranavkm committed Oct 9, 2014
1 parent 578d84d commit d68599f
Show file tree
Hide file tree
Showing 18 changed files with 413 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ private static void Register(
.ConfigureLifecycle(descriptor.Lifecycle);
}
}
else if (descriptor.ImplementationFactory != null)
{
var registration = RegistrationBuilder.ForDelegate(descriptor.ServiceType, (context, parameters) =>
{
var serviceProvider = context.Resolve<IServiceProvider>();
return descriptor.ImplementationFactory(serviceProvider);
})
.ConfigureLifecycle(descriptor.Lifecycle)
.CreateRegistration();

builder.RegisterComponent(registration);
}
else
{
builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ public override void Load()
{
binding = Bind(descriptor.ServiceType).To(descriptor.ImplementationType);
}
else if (descriptor.ImplementationFactory != null)
{
binding = Bind(descriptor.ServiceType).ToMethod(context =>
{
var serviceProvider = context.Kernel.Get<IServiceProvider>();
return descriptor.ImplementationFactory(serviceProvider);
});
}
else
{
binding = Bind(descriptor.ServiceType).ToConstant(descriptor.ImplementationInstance);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,16 @@ public interface IServiceCollection : IEnumerable<IServiceDescriptor>

IServiceCollection AddTransient(Type service, Type implementationType);

IServiceCollection AddTransient(Type service, Func<IServiceProvider, object> implementationFactory);

IServiceCollection AddScoped(Type service, Type implementationType);

IServiceCollection AddScoped(Type service, Func<IServiceProvider, object> implementationFactory);

IServiceCollection AddSingleton(Type service, Type implementationType);

IServiceCollection AddSingleton(Type service, Func<IServiceProvider, object> implementationFactory);

IServiceCollection AddInstance(Type service, object implementationInstance);
}
}
31 changes: 29 additions & 2 deletions src/Microsoft.Framework.DependencyInjection/IServiceDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,41 @@

namespace Microsoft.Framework.DependencyInjection
{
/// <summary>
/// Secifies the contract for a type that contains information about a service.
/// </summary>
/// <remarks>
/// <see cref="ImplementationType"/>, <see cref="ImplementationInstance"/>, amd <see cref="ImplementationFactory"/> specify the source
/// for the service instance. Only one of them should ever be non-null for a given <see cref="IServiceDescriptor"/> instance.
/// </remarks>
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public interface IServiceDescriptor
{
/// <summary>
/// Gets the <see cref="LifecycleKind"/> of the service.
/// </summary>
LifecycleKind Lifecycle { get; }

/// <summary>
/// Gets the <see cref="Type"/> of the service.
/// </summary>
Type ServiceType { get; }
Type ImplementationType { get; } // nullable
object ImplementationInstance { get; } // nullable

/// <summary>
/// Gets the <see cref="ImplementationType"/> of the service.
/// </summary>
Type ImplementationType { get; }

/// <summary>
/// Gets the instance implementing the service.
/// </summary>
object ImplementationInstance { get; }

/// <summary>
/// Gets the factory used for creating service instances.
/// </summary>
Func<IServiceProvider, object> ImplementationFactory { get; }
}
}
15 changes: 15 additions & 0 deletions src/Microsoft.Framework.DependencyInjection/ServiceCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,22 @@ public IServiceCollection AddTransient(Type service, Type implementationType)
return this;
}

public IServiceCollection AddTransient(Type service, Func<IServiceProvider, object> implementationFactory)
{
return Add(_describe.Transient(service, implementationFactory));
}

public IServiceCollection AddScoped(Type service, Type implementationType)
{
Add(_describe.Scoped(service, implementationType));
return this;
}

public IServiceCollection AddScoped(Type service, Func<IServiceProvider, object> implementationFactory)
{
return Add(_describe.Scoped(service, implementationFactory));
}

public IServiceCollection AddSingleton(Type service, Type implementationType)
{
Add(_describe.Singleton(service, implementationType));
Expand All @@ -60,6 +70,11 @@ public IServiceCollection AddInstance(Type service, object implementationInstanc
return this;
}

public IServiceCollection AddSingleton(Type service, Func<IServiceProvider, object> implementationFactory)
{
return Add(_describe.Singleton(service, implementationFactory));
}

public IEnumerator<IServiceDescriptor> GetEnumerator()
{
return _descriptors.GetEnumerator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Linq;
using System.Reflection;

namespace Microsoft.Framework.DependencyInjection
{
Expand All @@ -24,6 +22,12 @@ public static IServiceCollection AddTransient<TService>([NotNull]this IServiceCo
return services.AddTransient(typeof(TService));
}

public static IServiceCollection AddTransient<TService>([NotNull] this IServiceCollection services,
[NotNull] Func<IServiceProvider, object> implementationFactory)
{
return services.AddTransient(typeof(TService), implementationFactory);
}

public static IServiceCollection AddScoped<TService, TImplementation>([NotNull]this IServiceCollection services)
{
return services.AddScoped(typeof(TService), typeof(TImplementation));
Expand All @@ -34,6 +38,12 @@ public static IServiceCollection AddScoped([NotNull]this IServiceCollection serv
return services.AddScoped(serviceType, serviceType);
}

public static IServiceCollection AddScoped<TService>([NotNull] this IServiceCollection services,
[NotNull] Func<IServiceProvider, object> implementationFactory)
{
return services.AddScoped(typeof(TService), implementationFactory);
}

public static IServiceCollection AddScoped<TService>([NotNull]this IServiceCollection services)
{
return services.AddScoped(typeof(TService));
Expand All @@ -54,6 +64,12 @@ public static IServiceCollection AddSingleton<TService>([NotNull]this IServiceCo
return services.AddSingleton(typeof(TService));
}

public static IServiceCollection AddSingleton<TService>([NotNull] this IServiceCollection services,
[NotNull] Func<IServiceProvider, object> implementationFactory)
{
return services.AddSingleton(typeof(TService), implementationFactory);
}

public static IServiceCollection AddInstance<TService>([NotNull]this IServiceCollection services, TService implementationInstance)
{
return services.AddInstance(typeof(TService), implementationInstance);
Expand Down
100 changes: 64 additions & 36 deletions src/Microsoft.Framework.DependencyInjection/ServiceDescriber.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ public ServiceDescriptor Transient(Type service, Type implementationType)
return Describe(service, implementationType, LifecycleKind.Transient);
}

public ServiceDescriptor Transient<TService>(Func<IServiceProvider, object> implementationFactory)
{
return Describe(typeof(TService), implementationFactory, LifecycleKind.Transient);
}

public ServiceDescriptor Transient(Type service, Func<IServiceProvider, object> implementationFactory)
{
return Describe(service, implementationFactory, LifecycleKind.Transient);
}

public ServiceDescriptor Scoped<TService, TImplementation>()
{
return Describe<TService, TImplementation>(LifecycleKind.Scoped);
Expand All @@ -40,6 +50,16 @@ public ServiceDescriptor Scoped(Type service, Type implementationType)
return Describe(service, implementationType, LifecycleKind.Scoped);
}

public ServiceDescriptor Scoped<TService>(Func<IServiceProvider, object> implementationFactory)
{
return Describe(typeof(TService), implementationFactory, LifecycleKind.Scoped);
}

public ServiceDescriptor Scoped(Type service, Func<IServiceProvider, object> implementationFactory)
{
return Describe(service, implementationFactory, LifecycleKind.Scoped);
}

public ServiceDescriptor Singleton<TService, TImplementation>()
{
return Describe<TService, TImplementation>(LifecycleKind.Singleton);
Expand All @@ -50,68 +70,76 @@ public ServiceDescriptor Singleton(Type service, Type implementationType)
return Describe(service, implementationType, LifecycleKind.Singleton);
}

public ServiceDescriptor Singleton<TService>(Func<IServiceProvider, object> implementationFactory)
{
return Describe(typeof(TService), implementationFactory, LifecycleKind.Singleton);
}

public ServiceDescriptor Singleton(Type serviceType, Func<IServiceProvider, object> implementationFactory)
{
return Describe(serviceType, implementationFactory, LifecycleKind.Singleton);
}

public ServiceDescriptor Instance<TService>(object implementationInstance)
{
return Instance(typeof(TService), implementationInstance);
}

public ServiceDescriptor Instance(Type service, object implementationInstance)
public ServiceDescriptor Instance(Type serviceType, object implementationInstance)
{
return Describe(
service,
null, // implementationType
implementationInstance,
LifecycleKind.Singleton);
var implementationType = GetRemappedImplementationType(serviceType);
if (implementationType != null)
{
return new ServiceDescriptor(serviceType, implementationType, LifecycleKind.Singleton);
}

return new ServiceDescriptor(serviceType, implementationInstance);
}

private ServiceDescriptor Describe<TService, TImplementation>(LifecycleKind lifecycle)
{
return Describe(
typeof(TService),
typeof(TImplementation),
null, // implementationInstance
lifecycle);
lifecycle: lifecycle);
}

private ServiceDescriptor Describe(
Type serviceType,
Type implementationType,
LifecycleKind lifecycle)
public ServiceDescriptor Describe(Type serviceType, Type implementationType, LifecycleKind lifecycle)
{
return Describe(
serviceType,
implementationType,
null, // implementationInstance
lifecycle);
implementationType = GetRemappedImplementationType(serviceType) ?? implementationType;

return new ServiceDescriptor(serviceType, implementationType, lifecycle);
}

public ServiceDescriptor Describe(
Type serviceType,
Type implementationType,
object implementationInstance,
LifecycleKind lifecycle)
public ServiceDescriptor Describe(Type serviceType, Func<IServiceProvider, object> implementationFactory, LifecycleKind lifecycle)
{
var implementationType = GetRemappedImplementationType(serviceType);
if (implementationType != null)
{
return new ServiceDescriptor(serviceType, implementationType, lifecycle);
}

return new ServiceDescriptor(serviceType, implementationFactory, lifecycle);
}

private Type GetRemappedImplementationType(Type serviceType)
{
// Allow the user to change the implementation source via configuration.
var serviceTypeName = serviceType.FullName;
var implementationTypeName = _configuration.Get(serviceTypeName);
if (!String.IsNullOrEmpty(implementationTypeName))
if (!string.IsNullOrEmpty(implementationTypeName))
{
try
var type = Type.GetType(implementationTypeName, throwOnError: false);
if (type == null)
{
implementationType = Type.GetType(implementationTypeName);
}
catch (Exception ex)
{
throw new Exception(string.Format("TODO: unable to locate implementation {0} for service {1}", implementationTypeName, serviceTypeName), ex);
var message = string.Format("TODO: unable to locate implementation {0} for service {1}", implementationTypeName, serviceTypeName);
throw new InvalidOperationException(message);
}

return type;
}

return new ServiceDescriptor
{
ServiceType = serviceType,
ImplementationType = implementationType,
ImplementationInstance = implementationInstance,
Lifecycle = lifecycle
};
return null;
}
}
}
60 changes: 55 additions & 5 deletions src/Microsoft.Framework.DependencyInjection/ServiceDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,61 @@ namespace Microsoft.Framework.DependencyInjection
{
public class ServiceDescriptor : IServiceDescriptor
{
public LifecycleKind Lifecycle { get; set; }
public Type ServiceType { get; set; }
/// <summary>
/// Initializes a new instance of <see cref="ServiceDescriptor"/> with the specified <paramref name="implementationType"/>.
/// </summary>
/// <param name="serviceType">The <see cref="Type"/> of the service.</param>
/// <param name="implementationType">The <see cref="Type"/> implementing the service.</param>
/// <param name="lifecycle">The <see cref="LifecycleKind"/> of the service.</param>
public ServiceDescriptor(Type serviceType, Type implementationType, LifecycleKind lifecycle)
: this(serviceType, lifecycle)
{
ImplementationType = implementationType;
}

// Exactly one of the two following properties should be set
public Type ImplementationType { get; set; } // nullable
public object ImplementationInstance { get; set; } // nullable
/// <summary>
/// Initializes a new instance of <see cref="ServiceDescriptor"/> with the specified <paramref name="instance"/>
/// as a <see cref="LifecycleKind.Singleton"/>.
/// </summary>
/// <param name="serviceType">The <see cref="Type"/> of the service.</param>
/// <param name="instance">The instance implementing the service.</param>
public ServiceDescriptor(Type serviceType, object instance)
: this(serviceType, LifecycleKind.Singleton)
{
ImplementationInstance = instance;
}

/// <summary>
/// Initializes a new instance of <see cref="ServiceDescriptor"/> with the specified <paramref name="factory"/>.
/// </summary>
/// <param name="serviceType">The <see cref="Type"/> of the service.</param>
/// <param name="factory">A factory used for creating service instances.</param>
/// <param name="lifecycle">The <see cref="LifecycleKind"/> of the service.</param>
public ServiceDescriptor(Type serviceType, Func<IServiceProvider, object> factory, LifecycleKind lifecycle)
: this(serviceType, lifecycle)
{
ImplementationFactory = factory;
}

private ServiceDescriptor(Type serviceType, LifecycleKind lifecycle)
{
Lifecycle = lifecycle;
ServiceType = serviceType;
}

/// <inheritdoc />
public LifecycleKind Lifecycle { get; private set; }

/// <inheritdoc />
public Type ServiceType { get; private set; }

/// <inheritdoc />
public Type ImplementationType { get; private set; }

/// <inheritdoc />
public object ImplementationInstance { get; private set; }

/// <inheritdoc />
public Func<IServiceProvider, object> ImplementationFactory { get; private set; }
}
}
Loading

0 comments on commit d68599f

Please sign in to comment.