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

[WIP] Future Concept #437

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion DependencyInjection.sln
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D26F6F80-63EE-4081-A814-EF3DBABE24D9}"
EndProject
Expand All @@ -21,6 +21,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.DependencyInjection.Specification.Tests", "src\Microsoft.Extensions.DependencyInjection.Specification.Tests\Microsoft.Extensions.DependencyInjection.Specification.Tests.xproj", "{B9395B0F-E8E3-4913-BABF-E71A76F21231}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.DependencyInjection.Ordered", "src\Microsoft.Extensions.DependencyInjection.Ordered\Microsoft.Extensions.DependencyInjection.Ordered.xproj", "{0706ED60-FD66-49B0-836F-2B28C24C543E}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.DependencyInjection.Adapters", "src\Microsoft.Extensions.DependencyInjection.Adapters\Microsoft.Extensions.DependencyInjection.Adapters.xproj", "{8FBC451A-CC96-48DA-AE54-446348BAE7C4}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.DependencyInjection.Adapters.Tests", "test\Microsoft.Extensions.DependencyInjection.Adapters.Tests\Microsoft.Extensions.DependencyInjection.Adapters.Tests.xproj", "{D251C968-6606-4F24-9E47-D98254A9563D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -75,6 +81,42 @@ Global
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Release|x86.ActiveCfg = Release|Any CPU
{B9395B0F-E8E3-4913-BABF-E71A76F21231}.Release|x86.Build.0 = Release|Any CPU
{0706ED60-FD66-49B0-836F-2B28C24C543E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0706ED60-FD66-49B0-836F-2B28C24C543E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0706ED60-FD66-49B0-836F-2B28C24C543E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{0706ED60-FD66-49B0-836F-2B28C24C543E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{0706ED60-FD66-49B0-836F-2B28C24C543E}.Debug|x86.ActiveCfg = Debug|Any CPU
{0706ED60-FD66-49B0-836F-2B28C24C543E}.Debug|x86.Build.0 = Debug|Any CPU
{0706ED60-FD66-49B0-836F-2B28C24C543E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0706ED60-FD66-49B0-836F-2B28C24C543E}.Release|Any CPU.Build.0 = Release|Any CPU
{0706ED60-FD66-49B0-836F-2B28C24C543E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{0706ED60-FD66-49B0-836F-2B28C24C543E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{0706ED60-FD66-49B0-836F-2B28C24C543E}.Release|x86.ActiveCfg = Release|Any CPU
{0706ED60-FD66-49B0-836F-2B28C24C543E}.Release|x86.Build.0 = Release|Any CPU
{8FBC451A-CC96-48DA-AE54-446348BAE7C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8FBC451A-CC96-48DA-AE54-446348BAE7C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FBC451A-CC96-48DA-AE54-446348BAE7C4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{8FBC451A-CC96-48DA-AE54-446348BAE7C4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{8FBC451A-CC96-48DA-AE54-446348BAE7C4}.Debug|x86.ActiveCfg = Debug|Any CPU
{8FBC451A-CC96-48DA-AE54-446348BAE7C4}.Debug|x86.Build.0 = Debug|Any CPU
{8FBC451A-CC96-48DA-AE54-446348BAE7C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FBC451A-CC96-48DA-AE54-446348BAE7C4}.Release|Any CPU.Build.0 = Release|Any CPU
{8FBC451A-CC96-48DA-AE54-446348BAE7C4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{8FBC451A-CC96-48DA-AE54-446348BAE7C4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{8FBC451A-CC96-48DA-AE54-446348BAE7C4}.Release|x86.ActiveCfg = Release|Any CPU
{8FBC451A-CC96-48DA-AE54-446348BAE7C4}.Release|x86.Build.0 = Release|Any CPU
{D251C968-6606-4F24-9E47-D98254A9563D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D251C968-6606-4F24-9E47-D98254A9563D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D251C968-6606-4F24-9E47-D98254A9563D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{D251C968-6606-4F24-9E47-D98254A9563D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{D251C968-6606-4F24-9E47-D98254A9563D}.Debug|x86.ActiveCfg = Debug|Any CPU
{D251C968-6606-4F24-9E47-D98254A9563D}.Debug|x86.Build.0 = Debug|Any CPU
{D251C968-6606-4F24-9E47-D98254A9563D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D251C968-6606-4F24-9E47-D98254A9563D}.Release|Any CPU.Build.0 = Release|Any CPU
{D251C968-6606-4F24-9E47-D98254A9563D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{D251C968-6606-4F24-9E47-D98254A9563D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{D251C968-6606-4F24-9E47-D98254A9563D}.Release|x86.ActiveCfg = Release|Any CPU
{D251C968-6606-4F24-9E47-D98254A9563D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -84,5 +126,8 @@ Global
{20201277-5461-49EF-811B-63ED3CD274EF} = {88B347C1-CCEC-4827-9564-FFF07C9BF7C7}
{4E959D3B-2E0D-4296-B22C-D428DED294F0} = {D26F6F80-63EE-4081-A814-EF3DBABE24D9}
{B9395B0F-E8E3-4913-BABF-E71A76F21231} = {D26F6F80-63EE-4081-A814-EF3DBABE24D9}
{0706ED60-FD66-49B0-836F-2B28C24C543E} = {D26F6F80-63EE-4081-A814-EF3DBABE24D9}
{8FBC451A-CC96-48DA-AE54-446348BAE7C4} = {D26F6F80-63EE-4081-A814-EF3DBABE24D9}
{D251C968-6606-4F24-9E47-D98254A9563D} = {88B347C1-CCEC-4827-9564-FFF07C9BF7C7}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: missing (c)

using System.Collections.Generic;

namespace Microsoft.Extensions.DependencyInjection
{
public class EnumerableServiceDescriptor : ServiceDescriptor
{
public EnumerableServiceDescriptor(Type serviceType) : base(serviceType, ServiceLifetime.Transient)
{
}

public IList<ServiceDescriptor> Descriptors { get; } = new List<ServiceDescriptor>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ public static IServiceCollection Add(
{
throw new ArgumentNullException(nameof(descriptor));
}

collection.Add(descriptor);
return collection;
}
Expand Down Expand Up @@ -76,7 +75,6 @@ public static void TryAdd(
{
throw new ArgumentNullException(nameof(collection));
}

if (descriptor == null)
{
throw new ArgumentNullException(nameof(descriptor));
Expand Down Expand Up @@ -422,94 +420,6 @@ public static void TryAddSingleton<TService>(
services.TryAdd(ServiceDescriptor.Singleton(implementationFactory));
}

/// <summary>
/// Adds a <see cref="ServiceDescriptor"/> if an existing descriptor with the same
/// <see cref="ServiceDescriptor.ServiceType"/> and an implementation that does not already exist
/// in <paramref name="services."/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <param name="descriptor">The <see cref="ServiceDescriptor"/>.</param>
/// <remarks>
/// Use <see cref="TryAddEnumerable(IServiceCollection, ServiceDescriptor)"/> when registing a service implementation of a
/// service type that
/// supports multiple registrations of the same service type. Using
/// <see cref="Add(IServiceCollection, ServiceDescriptor)"/> is not idempotent and can add
/// duplicate
/// <see cref="ServiceDescriptor"/> instances if called twice. Using
/// <see cref="TryAddEnumerable(IServiceCollection, ServiceDescriptor)"/> will prevent registration
/// of multiple implementation types.
/// </remarks>
public static void TryAddEnumerable(
this IServiceCollection services,
ServiceDescriptor descriptor)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}

if (descriptor == null)
{
throw new ArgumentNullException(nameof(descriptor));
}

var implementationType = descriptor.GetImplementationType();

if (implementationType == typeof(object) ||
implementationType == descriptor.ServiceType)
{
throw new ArgumentException(
Resources.FormatTryAddIndistinguishableTypeToEnumerable(
implementationType,
descriptor.ServiceType),
nameof(descriptor));
}

if (!services.Any(d =>
d.ServiceType == descriptor.ServiceType &&
d.GetImplementationType() == implementationType))
{
services.Add(descriptor);
}
}

/// <summary>
/// Adds the specified <see cref="ServiceDescriptor"/>s if an existing descriptor with the same
/// <see cref="ServiceDescriptor.ServiceType"/> and an implementation that does not already exist
/// in <paramref name="services."/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <param name="descriptors">The <see cref="ServiceDescriptor"/>s.</param>
/// <remarks>
/// Use <see cref="TryAddEnumerable(IServiceCollection, ServiceDescriptor)"/> when registing a service
/// implementation of a service type that
/// supports multiple registrations of the same service type. Using
/// <see cref="Add(IServiceCollection, ServiceDescriptor)"/> is not idempotent and can add
/// duplicate
/// <see cref="ServiceDescriptor"/> instances if called twice. Using
/// <see cref="TryAddEnumerable(IServiceCollection, ServiceDescriptor)"/> will prevent registration
/// of multiple implementation types.
/// </remarks>
public static void TryAddEnumerable(
this IServiceCollection services,
IEnumerable<ServiceDescriptor> descriptors)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}

if (descriptors == null)
{
throw new ArgumentNullException(nameof(descriptors));
}

foreach (var d in descriptors)
{
services.TryAddEnumerable(d);
}
}

/// <summary>
/// Removes the first service in <see cref="IServiceCollection"/> with the same service type
/// as <paramref name="descriptor"/> and adds <paramef name="descriptor"/> to the collection.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) .NET Foundation. 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.Diagnostics;

namespace Microsoft.Extensions.DependencyInjection
{
[DebuggerDisplay("Lifetime = {Lifetime}, ServiceType = {ServiceType}, ImplementationFactory = {ImplementationFactory}")]
public class FactoryServiceDescriptor : ServiceDescriptor
{
/// <summary>
/// Initializes a new instance of <see cref="FactoryServiceDescriptor"/> 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="lifetime">The <see cref="ServiceLifetime"/> of the service.</param>
public FactoryServiceDescriptor(Type serviceType, Func<IServiceProvider, object> factory,
ServiceLifetime lifetime)
: base(serviceType, lifetime)
{
if (serviceType == null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason you're checking this in some descriptors, but not in EnumerableServiceDescriptor and OrderedEnumerableServiceDescriptor? Shouldn't thisnull check just be moved up to the base class? I don't believe you ever want ServiceType to be null....

{
throw new ArgumentNullException(nameof(serviceType));
}

if (factory == null)
{
throw new ArgumentNullException(nameof(factory));
}

ImplementationFactory = factory;
}

/// <inheritdoc />
public Func<IServiceProvider, object> ImplementationFactory { get; }
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. 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.Extensions.DependencyInjection
Expand All @@ -11,4 +12,14 @@ namespace Microsoft.Extensions.DependencyInjection
public interface IServiceCollection : IList<ServiceDescriptor>
{
}

public interface IServicesEditor: IList<ServiceDescriptor>
{
Type ServiceType { get; }
}

public interface IServicesEditor<in T> : IServicesEditor
{
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) .NET Foundation. 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.Diagnostics;

namespace Microsoft.Extensions.DependencyInjection
{
[DebuggerDisplay("Lifetime = {Lifetime}, ServiceType = {ServiceType}, ImplementationInstance = {ImplementationInstance}")]
public class InstanceServiceDescriptor : ServiceDescriptor
{
/// <summary>
/// Initializes a new instance of <see cref="InstanceServiceDescriptor"/> with the specified <paramref name="instance"/>
/// as a <see cref="ServiceLifetime.Singleton"/>.
/// </summary>
/// <param name="serviceType">The <see cref="Type"/> of the service.</param>
/// <param name="instance">The instance implementing the service.</param>
public InstanceServiceDescriptor(Type serviceType, object instance)
: base(serviceType, ServiceLifetime.Singleton)
{
if (serviceType == null)
{
throw new ArgumentNullException(nameof(serviceType));
}

if (instance == null)
{
throw new ArgumentNullException(nameof(instance));
}

ImplementationInstance = instance;
}

/// <inheritdoc />
public object ImplementationInstance { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) .NET Foundation. 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;
using System.Diagnostics;
using System.Linq;
using Microsoft.Extensions.DependencyInjection.Abstractions;
using Microsoft.Extensions.DependencyInjection.Extensions;

namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionEnumerableExtensions
{
public static IServicesEditor<TService> AddEnumerable<TService>(this IServiceCollection services)
where TService : class
{
return new ServiceEditor<TService>(GetEnumerableDescriptor(services, typeof(TService)).Descriptors);
}

public static IServicesEditor AddEnumerable(this IServiceCollection services, Type serviceType)
{
return new ServiceEditor<object>(GetEnumerableDescriptor(services, serviceType).Descriptors, serviceType);
}

private static EnumerableServiceDescriptor GetEnumerableDescriptor(
this IServiceCollection collection,
Type serviceType)
{
var descriptor = (EnumerableServiceDescriptor)
collection.FirstOrDefault(d =>
d.GetType() == typeof(EnumerableServiceDescriptor) &&
d.ServiceType == serviceType);
if (descriptor == null)
{
descriptor = new EnumerableServiceDescriptor(serviceType);
collection.Add(descriptor);
}
return descriptor;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ public static IServiceCollection AddSingleton(
throw new ArgumentNullException(nameof(implementationInstance));
}

var serviceDescriptor = new ServiceDescriptor(serviceType, implementationInstance);
var serviceDescriptor = ServiceDescriptor.Singleton(serviceType, implementationInstance);
services.Add(serviceDescriptor);
return services;
}
Expand Down Expand Up @@ -654,8 +654,7 @@ private static IServiceCollection Add(
Type implementationType,
ServiceLifetime lifetime)
{
var descriptor = new ServiceDescriptor(serviceType, implementationType, lifetime);
collection.Add(descriptor);
collection.Add(new TypeServiceDescriptor(serviceType, implementationType, lifetime));
return collection;
}

Expand All @@ -665,8 +664,7 @@ private static IServiceCollection Add(
Func<IServiceProvider, object> implementationFactory,
ServiceLifetime lifetime)
{
var descriptor = new ServiceDescriptor(serviceType, implementationFactory, lifetime);
collection.Add(descriptor);
collection.Add(new FactoryServiceDescriptor(serviceType, implementationFactory, lifetime));
return collection;
}
}
Expand Down
Loading