internal static object TryDecorateRegistration( Service service, IComponentRegistration registration, object instance, IComponentContext context, IEnumerable <Parameter> parameters) { if (service is DecoratorService || !(service is IServiceWithType serviceWithType) || registration is ExternalComponentRegistration) { return(instance); } var decoratorRegistrations = context.ComponentRegistry.DecoratorsFor(serviceWithType); if (decoratorRegistrations.Count == 0) { return(instance); } var serviceType = serviceWithType.ServiceType; var resolveParameters = parameters as Parameter[] ?? parameters.ToArray(); var instanceType = instance.GetType(); var decoratorContext = DecoratorContext.Create(instanceType, serviceType, instance); var decoratorCount = decoratorRegistrations.Count; for (var index = 0; index < decoratorCount; index++) { var decoratorRegistration = decoratorRegistrations[index]; 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 = new Parameter[resolveParameters.Length + 2]; for (var i = 0; i < resolveParameters.Length; i++) { invokeParameters[i] = resolveParameters[i]; } invokeParameters[invokeParameters.Length - 2] = serviceParameter; invokeParameters[invokeParameters.Length - 1] = contextParameter; var resolveRequest = new ResolveRequest(decoratorService, decoratorRegistration, invokeParameters); instance = context.ResolveComponent(resolveRequest); if (index < decoratorCount - 1) { decoratorContext = decoratorContext.UpdateContext(instance); } } return(instance); }
internal static object TryDecorateRegistration( 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); } 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() }) .ToArray(); if (decorators.Length == 0) { return(instance); } var serviceType = decorators[0].Service.ServiceType; var resolveParameters = parameters as Parameter[] ?? parameters.ToArray(); var decoratorContext = DecoratorContext.Create(instanceType, serviceType, instance); foreach (var decorator in decorators) { if (!decorator.Service.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(decorator.Registration, invokeParameters); decoratorContext = decoratorContext.UpdateContext(instance); } return(instance); }
/// <inheritdoc/> public void Execute(ResolveRequestContext context, Action <ResolveRequestContext> next) { // Go down the pipeline first, need that instance. next(context); // Don't do this if we didn't activate an instance (for example because of decorator instance sharing). if (context.Instance is null) { return; } // Check if decoration is disabled. if (context.Registration.Options.HasOption(RegistrationOptions.DisableDecoration)) { return; } if (!(context.Operation is IDependencyTrackingResolveOperation dependencyTrackingResolveOperation)) { // Skipping decorator middleware, since IResolveOperation is not IDependencyTrackingResolveOperation // Which contains required functionality EnterNewDependencyDetectionBlock return; } // This middleware is only ever added to IServiceWithType pipelines, so this cast will always succeed. var swt = (IServiceWithType)context.Service; var serviceType = swt.ServiceType; if (context.DecoratorContext is null) { context.DecoratorContext = DecoratorContext.Create(context.Instance.GetType(), serviceType, context.Instance); } else { // Update the context with the previous decorator's output. // Doing this here, rather than in the decorator middleware that resulted in the instance // means we do not need to needlessly update the decorator context on the final decorator. context.DecoratorContext = context.DecoratorContext.UpdateContext(context.Instance); } if (!_decoratorService.Condition(context.DecoratorContext)) { return; } var serviceParameter = new TypedParameter(serviceType, context.DecoratorContext.CurrentInstance); var contextParameter = new TypedParameter(typeof(IDecoratorContext), context.DecoratorContext); Parameter[] resolveParameters; var parameterCount = context.Parameters.Count(); if (parameterCount == 0) { resolveParameters = new Parameter[] { serviceParameter, contextParameter }; } else { resolveParameters = new Parameter[parameterCount + 2]; var idx = 0; foreach (var existing in context.Parameters) { resolveParameters[idx] = existing; idx++; } resolveParameters[idx++] = serviceParameter; resolveParameters[idx++] = contextParameter; } // We're going to define a service registration that does not contain any service // pipeline additions. // Adding a service pipeline middleware to a decorator service is not valid anyway. var resolveRequest = new ResolveRequest( _decoratorService, new ServiceRegistration(ServicePipelines.DefaultServicePipeline, _decoratorRegistration), resolveParameters, context.Registration); using (dependencyTrackingResolveOperation.EnterNewDependencyDetectionBlock()) { var decoratedInstance = context.ResolveComponent(resolveRequest); context.Instance = decoratedInstance; } }