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

Commit

Permalink
Refactoring ServiceCollection
Browse files Browse the repository at this point in the history
* Remove use of IConfiguration from ServiceCollection
* Removing the Add* methods from IServiceCollection that don't accept an
  IServiceDescriptor

Fixes #116 #117
  • Loading branch information
pranavkm committed Oct 17, 2014
1 parent e0a956c commit 8eb26fc
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 69 deletions.
28 changes: 13 additions & 15 deletions src/Microsoft.Framework.DependencyInjection/IServiceCollection.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;

namespace Microsoft.Framework.DependencyInjection
{
/// <summary>
/// Specifies the contract for a collection of service descriptors.
/// </summary>
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public interface IServiceCollection : IEnumerable<IServiceDescriptor>
{
/// <summary>
/// Adds the <paramref name="descriptor"/> to this instance.
/// </summary>
/// <param name="descriptor">The <see cref="IServiceDescriptor"/> to add.</param>
/// <returns>A reference to the current instance of <see cref="IServiceCollection"/>.</returns>
IServiceCollection Add(IServiceDescriptor descriptor);

/// <summary>
/// Adds a sequence of <see cref="IServiceDescriptor"/> to this instance.
/// </summary>
/// <param name="descriptor">The <see cref="IEnumerable{T}"/> or <see cref="IServiceDescriptor"/>s to add.</param>
/// <returns>A reference to the current instance of <see cref="IServiceCollection"/>.</returns>
IServiceCollection Add(IEnumerable<IServiceDescriptor> descriptors);

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);
}
}
61 changes: 7 additions & 54 deletions src/Microsoft.Framework.DependencyInjection/ServiceCollection.cs
Original file line number Diff line number Diff line change
@@ -1,80 +1,33 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections;
using System.Collections.Generic;
using Microsoft.Framework.ConfigurationModel;

namespace Microsoft.Framework.DependencyInjection
{
/// <summary>
/// Default implementation of <see cref="IServiceCollection"/>.
/// </summary>
public class ServiceCollection : IServiceCollection
{
private readonly List<IServiceDescriptor> _descriptors;
private readonly ServiceDescriber _describe;

public ServiceCollection()
: this(new Configuration())
{
}

public ServiceCollection(IConfiguration configuration)
{
_descriptors = new List<IServiceDescriptor>();
_describe = new ServiceDescriber(configuration);
}
private readonly List<IServiceDescriptor> _descriptors = new List<IServiceDescriptor>();

/// <inheritdoc />
public IServiceCollection Add(IServiceDescriptor descriptor)
{
_descriptors.Add(descriptor);
return this;
}

/// <inheritdoc />
public IServiceCollection Add(IEnumerable<IServiceDescriptor> descriptors)
{
_descriptors.AddRange(descriptors);
return this;
}

public IServiceCollection AddTransient(Type service, Type implementationType)
{
Add(_describe.Transient(service, 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));
return this;
}

public IServiceCollection AddInstance(Type service, object implementationInstance)
{
Add(_describe.Instance(service, implementationInstance));
return this;
}

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

/// <inheritdoc />
public IEnumerator<IServiceDescriptor> GetEnumerator()
{
return _descriptors.GetEnumerator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,42 @@ namespace Microsoft.Framework.DependencyInjection
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddTransient([NotNull] this IServiceCollection collection, Type service, Type implementationType)
{
return Add(collection, service, implementationType, LifecycleKind.Transient);
}

public static IServiceCollection AddTransient([NotNull] this IServiceCollection collection, Type service, Func<IServiceProvider, object> implementationFactory)
{
return Add(collection, service, implementationFactory, LifecycleKind.Transient);
}

public static IServiceCollection AddScoped([NotNull] this IServiceCollection collection, Type service, Type implementationType)
{
return Add(collection, service, implementationType, LifecycleKind.Scoped);
}

public static IServiceCollection AddScoped([NotNull] this IServiceCollection collection, Type service, Func<IServiceProvider, object> implementationFactory)
{
return Add(collection, service, implementationFactory, LifecycleKind.Scoped);
}

public static IServiceCollection AddSingleton([NotNull] this IServiceCollection collection, Type service, Type implementationType)
{
return Add(collection, service, implementationType, LifecycleKind.Singleton);
}

public static IServiceCollection AddSingleton([NotNull] this IServiceCollection collection, Type service, Func<IServiceProvider, object> implementationFactory)
{
return Add(collection, service, implementationFactory, LifecycleKind.Singleton);
}

public static IServiceCollection AddInstance([NotNull] this IServiceCollection collection, Type service, object implementationInstance)
{
var serviceDescriptor = new ServiceDescriptor(service, implementationInstance);
return collection.Add(serviceDescriptor);
}

public static IServiceCollection AddTransient<TService, TImplementation>([NotNull]this IServiceCollection services)
{
return services.AddTransient(typeof(TService), typeof(TImplementation));
Expand Down Expand Up @@ -74,5 +110,23 @@ public static IServiceCollection AddInstance<TService>([NotNull]this IServiceCol
{
return services.AddInstance(typeof(TService), implementationInstance);
}

private static IServiceCollection Add(IServiceCollection collection,
Type service,
Type implementationType,
LifecycleKind lifeCycle)
{
var descriptor = new ServiceDescriptor(service, implementationType, lifeCycle);
return collection.Add(descriptor);
}

private static IServiceCollection Add(IServiceCollection collection,
Type service,
Func<IServiceProvider, object> implementationFactory,
LifecycleKind lifeCycle)
{
var descriptor = new ServiceDescriptor(service, implementationFactory, lifeCycle);
return collection.Add(descriptor);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.Framework.DependencyInjection.Tests.Fakes;
using Xunit;

namespace Microsoft.Framework.DependencyInjection
{
public class ServiceCollectionExtensionTest
{
private static readonly Func<IServiceProvider, object> _factory = _ => new object();
private static readonly FakeService _instance = new FakeService();

public static TheoryData AddImplementationTypeData
{
get
{
var serviceType = typeof(IFakeService);
var implementationType = typeof(FakeService);
return new TheoryData<Action<IServiceCollection>, Type, Type, LifecycleKind>
{
{ collection => collection.AddTransient(serviceType, implementationType), serviceType, implementationType, LifecycleKind.Transient },
{ collection => collection.AddTransient<IFakeService, FakeService>(), serviceType, implementationType, LifecycleKind.Transient },
{ collection => collection.AddTransient<IFakeService>(), serviceType, serviceType, LifecycleKind.Transient },
{ collection => collection.AddTransient(implementationType), implementationType, implementationType, LifecycleKind.Transient },

{ collection => collection.AddScoped(serviceType, implementationType), serviceType, implementationType, LifecycleKind.Scoped },
{ collection => collection.AddScoped<IFakeService, FakeService>(), serviceType, implementationType, LifecycleKind.Scoped },
{ collection => collection.AddScoped<IFakeService>(), serviceType, serviceType, LifecycleKind.Scoped },
{ collection => collection.AddScoped(implementationType), implementationType, implementationType, LifecycleKind.Scoped },

{ collection => collection.AddSingleton(serviceType, implementationType), serviceType, implementationType, LifecycleKind.Singleton },
{ collection => collection.AddSingleton<IFakeService, FakeService>(), serviceType, implementationType, LifecycleKind.Singleton },
{ collection => collection.AddSingleton<IFakeService>(), serviceType, serviceType, LifecycleKind.Singleton },
{ collection => collection.AddSingleton(implementationType), implementationType, implementationType, LifecycleKind.Singleton },
};
}
}

[Theory]
[MemberData(nameof(AddImplementationTypeData))]
public void Add_WithType_AddsServiceWithRightLifecyle(Action<IServiceCollection> addTypeAction,
Type expectedServiceType,
Type expectedImplementationType,
LifecycleKind lifeCycle)
{
// Arrange
var collection = new ServiceCollection();

// Act
addTypeAction(collection);

// Assert
var descriptor = Assert.Single(collection);
Assert.Equal(expectedServiceType, descriptor.ServiceType);
Assert.Equal(expectedImplementationType, descriptor.ImplementationType);
Assert.Equal(lifeCycle, descriptor.Lifecycle);
}

public static TheoryData AddImplementationFactoryData
{
get
{
var serviceType = typeof(IFakeService);

return new TheoryData<Action<IServiceCollection>, LifecycleKind>
{
{ collection => collection.AddTransient<IFakeService>(_factory), LifecycleKind.Transient },
{ collection => collection.AddTransient(serviceType, _factory), LifecycleKind.Transient },

{ collection => collection.AddScoped<IFakeService>(_factory), LifecycleKind.Scoped },
{ collection => collection.AddScoped(serviceType, _factory), LifecycleKind.Scoped },

{ collection => collection.AddSingleton<IFakeService>(_factory), LifecycleKind.Singleton },
{ collection => collection.AddSingleton(serviceType, _factory), LifecycleKind.Singleton },
};
}
}

[Theory]
[MemberData(nameof(AddImplementationFactoryData))]
public void Add_WithFactory_AddsServiceWithRightLifecyle(Action<IServiceCollection> addAction,
LifecycleKind lifeCycle)
{
// Arrange
var collection = new ServiceCollection();

// Act
addAction(collection);

// Assert
var descriptor = Assert.Single(collection);
Assert.Equal(typeof(IFakeService), descriptor.ServiceType);
Assert.Same(_factory, descriptor.ImplementationFactory);
Assert.Equal(lifeCycle, descriptor.Lifecycle);
}

public static TheoryData AddInstanceData
{
get
{
return new TheoryData<Action<IServiceCollection>>
{
{ collection => collection.AddInstance<IFakeService>(_instance) },
{ collection => collection.AddInstance(typeof(IFakeService), _instance) },
};
}
}

[Theory]
[MemberData(nameof(AddInstanceData))]
public void AddInstance_AddsWithSingletonLifecycle(Action<IServiceCollection> addAction)
{
// Arrange
var collection = new ServiceCollection();

// Act
addAction(collection);

// Assert
var descriptor = Assert.Single(collection);
Assert.Equal(typeof(IFakeService), descriptor.ServiceType);
Assert.Same(_instance, descriptor.ImplementationInstance);
Assert.Equal(LifecycleKind.Singleton, descriptor.Lifecycle);
}
}
}

0 comments on commit 8eb26fc

Please sign in to comment.