Skip to content

Commit

Permalink
Merge pull request #6 from autofac/develop
Browse files Browse the repository at this point in the history
Merge latest code
  • Loading branch information
RaymondHuy authored Sep 3, 2019
2 parents 095331e + 5ae6bf4 commit f9707e0
Show file tree
Hide file tree
Showing 26 changed files with 408 additions and 120 deletions.
10 changes: 7 additions & 3 deletions src/Autofac/Builder/RegistrationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ public static IComponentRegistration CreateRegistration<TLimit, TActivatorData,
builder.RegistrationData,
builder.ActivatorData.Activator,
builder.RegistrationData.Services.ToArray(),
builder.RegistrationStyle.Target);
builder.RegistrationStyle.Target,
builder.RegistrationStyle.IsAdapterForIndividualComponent);
}

/// <summary>
Expand Down Expand Up @@ -162,6 +163,7 @@ public static IComponentRegistration CreateRegistration(
/// <param name="activator">Activator.</param>
/// <param name="services">Services provided by the registration.</param>
/// <param name="target">Optional; target registration.</param>
/// <param name="isAdapterForIndividualComponent">Optional; whether the registration is a 1:1 adapters on top of another component.</param>
/// <returns>An IComponentRegistration.</returns>
/// <exception cref="System.ArgumentNullException">
/// Thrown if <paramref name="activator" /> or <paramref name="data" /> is <see langword="null" />.
Expand All @@ -171,7 +173,8 @@ public static IComponentRegistration CreateRegistration(
RegistrationData data,
IInstanceActivator activator,
Service[] services,
IComponentRegistration target)
IComponentRegistration target,
bool isAdapterForIndividualComponent = false)
{
if (activator == null) throw new ArgumentNullException(nameof(activator));
if (data == null) throw new ArgumentNullException(nameof(data));
Expand Down Expand Up @@ -216,7 +219,8 @@ public static IComponentRegistration CreateRegistration(
data.Ownership,
services,
data.Metadata,
target);
target,
isAdapterForIndividualComponent);
}

foreach (var p in data.PreparingHandlers)
Expand Down
6 changes: 6 additions & 0 deletions src/Autofac/Builder/SingleRegistrationStyle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,11 @@ public class SingleRegistrationStyle
/// Gets or sets the component upon which this registration is based.
/// </summary>
public IComponentRegistration Target { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the registration is a 1:1 adapters on top
/// of another component (e.g., Meta, Func, or Owned).
/// </summary>
public bool IsAdapterForIndividualComponent { get; set; }
}
}
6 changes: 6 additions & 0 deletions src/Autofac/Core/IComponentRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ public interface IComponentRegistration : IDisposable
/// </summary>
IComponentRegistration Target { get; }

/// <summary>
/// Gets a value indicating whether the registration is a 1:1 adapter on top
/// of another component (e.g., Meta, Func, or Owned).
/// </summary>
bool IsAdapterForIndividualComponent { get; }

/// <summary>
/// Fired when a new instance is required, prior to activation.
/// Can be used to provide Autofac with additional parameters, used during activation.
Expand Down
7 changes: 0 additions & 7 deletions src/Autofac/Core/IComponentRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,6 @@ public interface IComponentRegistry : IDisposable
/// <returns>Registrations supporting <paramref name="service"/>.</returns>
IEnumerable<IComponentRegistration> RegistrationsFor(Service service);

/// <summary>
/// Selects all available decorator registrations that can be applied to the specified registration.
/// </summary>
/// <param name="registration">The registration for which decorator registrations are sought.</param>
/// <returns>Decorator registrations applicable to <paramref name="registration"/>.</returns>
IEnumerable<IComponentRegistration> DecoratorsFor(IComponentRegistration registration);

/// <summary>
/// Fired whenever a component is registered - either explicitly or via a
/// <see cref="IRegistrationSource"/>.
Expand Down
9 changes: 8 additions & 1 deletion src/Autofac/Core/Registration/ComponentRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public ComponentRegistration(
Ownership = ownership;
Services = Enforce.ArgumentElementNotNull(services, nameof(services));
Metadata = metadata;
IsAdapterForIndividualComponent = false;
}

/// <summary>
Expand All @@ -84,6 +85,7 @@ public ComponentRegistration(
/// <param name="services">Services the component provides.</param>
/// <param name="metadata">Data associated with the component.</param>
/// <param name="target">The component registration upon which this registration is based.</param>
/// <param name="isAdapterForIndividualComponents">Whether the registration is a 1:1 adapters on top of another component.</param>
public ComponentRegistration(
Guid id,
IInstanceActivator activator,
Expand All @@ -92,12 +94,14 @@ public ComponentRegistration(
InstanceOwnership ownership,
IEnumerable<Service> services,
IDictionary<string, object> metadata,
IComponentRegistration target)
IComponentRegistration target,
bool isAdapterForIndividualComponents)
: this(id, activator, lifetime, sharing, ownership, services, metadata)
{
if (target == null) throw new ArgumentNullException(nameof(target));

_target = target;
IsAdapterForIndividualComponent = isAdapterForIndividualComponents;
}

/// <summary>
Expand Down Expand Up @@ -142,6 +146,9 @@ public ComponentRegistration(
/// </summary>
public IDictionary<string, object> Metadata { get; }

/// <inheritdoc />
public bool IsAdapterForIndividualComponent { get; }

/// <summary>
/// Fired when a new instance is required, prior to activation.
/// Can be used to provide Autofac with additional parameters, used during activation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public ComponentRegistrationLifetimeDecorator(IComponentRegistration inner, ICom

public IComponentRegistration Target => _inner.IsAdapting() ? _inner.Target : this;

public bool IsAdapterForIndividualComponent => _inner.IsAdapterForIndividualComponent;

public event EventHandler<PreparingEventArgs> Preparing
{
add => _inner.Preparing += value;
Expand Down
25 changes: 0 additions & 25 deletions src/Autofac/Core/Registration/ComponentRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,6 @@ public class ComponentRegistry : Disposable, IComponentRegistry
/// </summary>
private readonly ConcurrentDictionary<Service, ServiceRegistrationInfo> _serviceInfo = new ConcurrentDictionary<Service, ServiceRegistrationInfo>();

private readonly ConcurrentDictionary<IComponentRegistration, IEnumerable<IComponentRegistration>> _decorators
= new ConcurrentDictionary<IComponentRegistration, IEnumerable<IComponentRegistration>>();

/// <summary>
/// Initializes a new instance of the <see cref="ComponentRegistry"/> class.
/// </summary>
Expand Down Expand Up @@ -253,28 +250,6 @@ public IEnumerable<IComponentRegistration> RegistrationsFor(Service service)
}
}

/// <inheritdoc />
public IEnumerable<IComponentRegistration> DecoratorsFor(IComponentRegistration registration)
{
if (registration == null) throw new ArgumentNullException(nameof(registration));

return _decorators.GetOrAdd(registration, r =>
{
var result = new List<IComponentRegistration>();

foreach (var service in r.Services)
{
if (service is DecoratorService || !(service is IServiceWithType swt)) continue;

var decoratorService = new DecoratorService(swt.ServiceType);
var decoratorRegistrations = RegistrationsFor(decoratorService);
result.AddRange(decoratorRegistrations);
}

return result.OrderBy(d => d.GetRegistrationOrder()).ToArray();
});
}

/// <summary>
/// Fired whenever a component is registered - either explicitly or via a
/// <see cref="IRegistrationSource"/>.
Expand Down
5 changes: 0 additions & 5 deletions src/Autofac/Core/Registration/CopyOnWriteRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,6 @@ public IEnumerable<IComponentRegistration> RegistrationsFor(Service service)
return Registry.RegistrationsFor(service);
}

public IEnumerable<IComponentRegistration> DecoratorsFor(IComponentRegistration registration)
{
return Registry.DecoratorsFor(registration);
}

public event EventHandler<ComponentRegisteredEventArgs> Registered
{
add => WriteRegistry.Registered += value;
Expand Down
41 changes: 41 additions & 0 deletions src/Autofac/Core/Registration/ExternalComponentRegistration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// This software is part of the Autofac IoC container
// Copyright © 2019 Autofac Contributors
// https://autofac.org
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;

namespace Autofac.Core.Registration
{
/// <summary>
/// A wrapper component registration created only to distinguish it from other adapted registrations.
/// </summary>
internal class ExternalComponentRegistration : ComponentRegistration
{
public ExternalComponentRegistration(Guid id, IInstanceActivator activator, IComponentLifetime lifetime, InstanceSharing sharing, InstanceOwnership ownership, IEnumerable<Service> services, IDictionary<string, object> metadata, IComponentRegistration target, bool isAdapterForIndividualComponent)
: base(id, activator, lifetime, sharing, ownership, services, metadata, target, isAdapterForIndividualComponent)
{
}
}
}
20 changes: 3 additions & 17 deletions src/Autofac/Core/Registration/ExternalRegistrySource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,7 @@ internal class ExternalRegistrySource : IRegistrationSource
/// </summary>
/// <param name="registry">Component registry to pull registrations from.</param>
public ExternalRegistrySource(IComponentRegistry registry)
{
if (registry == null) throw new ArgumentNullException(nameof(registry));

_registry = registry;
}
=> _registry = registry ?? throw new ArgumentNullException(nameof(registry));

/// <summary>
/// Retrieve registrations for an unregistered service, to be used
Expand Down Expand Up @@ -86,7 +82,8 @@ public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Fun
InstanceOwnership.ExternallyOwned,
new[] { service },
r.Metadata,
r));
r,
false));
}

/// <summary>
Expand All @@ -95,16 +92,5 @@ public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Fun
/// logical scope, we must return false to avoid duplicating them.
/// </summary>
public bool IsAdapterForIndividualComponents => false;

/// <summary>
/// ComponentRegistration subtyped only to distinguish it from other adapted registrations.
/// </summary>
private class ExternalComponentRegistration : ComponentRegistration
{
public ExternalComponentRegistration(Guid id, IInstanceActivator activator, IComponentLifetime lifetime, InstanceSharing sharing, InstanceOwnership ownership, IEnumerable<Service> services, IDictionary<string, object> metadata, IComponentRegistration target)
: base(id, activator, lifetime, sharing, ownership, services, metadata, target)
{
}
}
}
}
7 changes: 5 additions & 2 deletions src/Autofac/Core/Resolving/InstanceLookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ internal class InstanceLookup : IComponentContext, IInstanceLookup
{
private readonly IResolveOperation _context;
private readonly ISharingLifetimeScope _activationScope;
private readonly Service _service;
private object _newInstance;
private bool _executed;
private const string ActivatorChainExceptionData = "ActivatorChain";
Expand All @@ -49,9 +50,10 @@ public InstanceLookup(
ISharingLifetimeScope mostNestedVisibleScope,
ResolveRequest request)
{
Parameters = request.Parameters;
ComponentRegistration = request.Registration;
_context = context;
_service = request.Service;
ComponentRegistration = request.Registration;
Parameters = request.Parameters;

try
{
Expand Down Expand Up @@ -120,6 +122,7 @@ private object Activate(IEnumerable<Parameter> parameters, out object decoratorT
decoratorTarget = _newInstance = ComponentRegistration.Activator.ActivateInstance(this, resolveParameters);

_newInstance = InstanceDecorator.TryDecorateRegistration(
_service,
ComponentRegistration,
_newInstance,
_activationScope,
Expand Down
34 changes: 15 additions & 19 deletions src/Autofac/Features/Decorators/InstanceDecorator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

using System.Collections.Generic;
using System.Linq;
using Autofac.Builder;
using Autofac.Core;
using Autofac.Core.Registration;

Expand All @@ -33,45 +34,40 @@ namespace Autofac.Features.Decorators
internal static class InstanceDecorator
{
internal static object TryDecorateRegistration(
Service service,
IComponentRegistration registration,
object instance,
IComponentContext context,
IEnumerable<Parameter> parameters)
{
var instanceType = instance.GetType();

// Issue #965: Do not apply the decorator if the registration is for an adapter.
if (registration.IsAdapting()) return instance;
if (registration.Services.OfType<DecoratorService>().Any()
|| !(service is IServiceWithType serviceWithType)
|| registration is ExternalComponentRegistration) return instance;

var decoratorRegistrations = context.ComponentRegistry.DecoratorsFor(registration);

// ReSharper disable once PossibleMultipleEnumeration
if (!decoratorRegistrations.Any()) return instance;

// ReSharper disable once PossibleMultipleEnumeration
var decorators = decoratorRegistrations
.Select(r => new
{
Registration = r,
Service = r.Services.OfType<DecoratorService>().First()
})
var decoratorRegistrations = context.ComponentRegistry
.RegistrationsFor(new DecoratorService(serviceWithType.ServiceType))
.Where(r => !r.IsAdapterForIndividualComponent)
.OrderBy(d => d.GetRegistrationOrder())
.ToArray();

if (decorators.Length == 0) return instance;
if (decoratorRegistrations.Length == 0) return instance;

var serviceType = decorators[0].Service.ServiceType;
var serviceType = serviceWithType.ServiceType;
var resolveParameters = parameters as Parameter[] ?? parameters.ToArray();

var decoratorContext = DecoratorContext.Create(instanceType, serviceType, instance);

foreach (var decorator in decorators)
foreach (var decoratorRegistration in decoratorRegistrations)
{
if (!decorator.Service.Condition(decoratorContext)) continue;
var decoratorService = decoratorRegistration.Services.OfType<DecoratorService>().First();
if (!decoratorService.Condition(decoratorContext)) continue;

var serviceParameter = new TypedParameter(serviceType, instance);
var contextParameter = new TypedParameter(typeof(IDecoratorContext), decoratorContext);
var invokeParameters = resolveParameters.Concat(new Parameter[] { serviceParameter, contextParameter });
instance = context.ResolveComponent(new ResolveRequest(decorator.Service, decorator.Registration, invokeParameters));
instance = context.ResolveComponent(new ResolveRequest(decoratorService, decoratorRegistration, invokeParameters));

decoratorContext = decoratorContext.UpdateContext(instance);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Fun
.InstancePerLifetimeScope()
.ExternallyOwned()
.As(service)
.Targeting(r)
.Targeting(r, IsAdapterForIndividualComponents)
.InheritRegistrationOrderFrom(r);

return rb.CreateRegistration();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Fun
var registrationCreator = CreateLazyRegistrationMethod.MakeGenericMethod(valueType);

return registrationAccessor(valueService)
.Select(v => registrationCreator.Invoke(null, new object[] { service, valueService, v }))
.Select(v => registrationCreator.Invoke(this, new object[] { service, valueService, v }))
.Cast<IComponentRegistration>();
}

Expand All @@ -68,7 +68,7 @@ public override string ToString()
return LazyRegistrationSourceResources.LazyRegistrationSourceDescription;
}

private static IComponentRegistration CreateLazyRegistration<T>(Service providedService, Service valueService, IComponentRegistration valueRegistration)
private IComponentRegistration CreateLazyRegistration<T>(Service providedService, Service valueService, IComponentRegistration valueRegistration)
{
var rb = RegistrationBuilder.ForDelegate(
(c, p) =>
Expand All @@ -78,7 +78,7 @@ private static IComponentRegistration CreateLazyRegistration<T>(Service provided
return new Lazy<T>(() => (T)context.ResolveComponent(request));
})
.As(providedService)
.Targeting(valueRegistration)
.Targeting(valueRegistration, IsAdapterForIndividualComponents)
.InheritRegistrationOrderFrom(valueRegistration);

return rb.CreateRegistration();
Expand Down
Loading

0 comments on commit f9707e0

Please sign in to comment.