z4kn4fein / stashbox

A lightweight, fast, and portable dependency injection framework for .NET-based solutions.
https://z4kn4fein.github.io/stashbox
MIT License
141 stars 10 forks source link

Call interception #89

Closed reservoir-dogs closed 4 years ago

reservoir-dogs commented 4 years ago

I use Stashbox (Stashbox.Extensions.Hosting 2.9.0) with interception, it works great except in this case :

Http call -> Controller -> ProxyLevel2Service -> Level2Service -> 2 dependencies : Dependency 1 -> ProxyLevel2bService -> Level2bService -> ProxyLevel3Service -> Level3Service -> Level4Service Dependency 2 -> ProxyLevel3Service -> Level3Service -> Level4Service

To reproduce use my repo : https://github.com/reservoir-dogs/InterceptionWithStashbox

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddScoped<ILevel2Service, Level2Service>();
            services.AddScoped<ILevel2bService, Level2bService>();
            services.AddScoped<ILevel3Service, Level3Service>();
            services.AddScoped<ILevel4Service, Level4Service>();
        }

        public void ConfigureContainer(IStashboxContainer container)
        {
            var proxyBuilder = new DefaultProxyBuilder();

            container.Register<IInterceptor, NoInterceptor>();
            container.RegisterDecorator<ILevel2Service>(proxyBuilder.CreateInterfaceProxyTypeWithTargetInterface(typeof(ILevel2Service), Array.Empty<Type>(), ProxyGenerationOptions.Default));
            container.RegisterDecorator<ILevel2bService>(proxyBuilder.CreateInterfaceProxyTypeWithTargetInterface(typeof(ILevel2bService), Array.Empty<Type>(), ProxyGenerationOptions.Default));
            container.RegisterDecorator<ILevel3Service>(proxyBuilder.CreateInterfaceProxyTypeWithTargetInterface(typeof(ILevel3Service), Array.Empty<Type>(), ProxyGenerationOptions.Default));
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }

If I remove Dependency 1 or 2, call works. If I remove ConfigureContainer(...), call works. If I check with Stashbox.Extensions.Hosting (2.8.2), call works. Else I have this exception :

System.InvalidOperationException: variable '' of type 'Library.ILevel4Service' referenced from scope '', but it is not defined
   at System.Linq.Expressions.Compiler.VariableBinder.Reference(ParameterExpression node, VariableStorageKind storage)
   at System.Linq.Expressions.Compiler.VariableBinder.VisitParameter(ParameterExpression node)
   at System.Linq.Expressions.ParameterExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitNew(NewExpression node)
   at System.Linq.Expressions.NewExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitNew(NewExpression node)
   at System.Linq.Expressions.NewExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitNew(NewExpression node)
   at System.Linq.Expressions.NewExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
   at System.Linq.Expressions.Compiler.VariableBinder.VisitLambda[T](Expression`1 node)
   at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda)
   at System.Linq.Expressions.LambdaExpression.Compile()
   at System.Linq.Expressions.ExpressionExtensions.CompileDelegate(Expression expression, ResolutionContext resolutionContext, ContainerConfiguration containerConfiguration)
   at Stashbox.Lifetime.FactoryLifetimeDescriptor.GetNewFactoryDelegate(ExpressionBuilder expressionBuilder, ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType)
   at Stashbox.Lifetime.FactoryLifetimeDescriptor.GetFactoryDelegateForRegistration(ExpressionBuilder expressionBuilder, ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType)
   at Stashbox.Lifetime.FactoryLifetimeDescriptor.BuildLifetimeAppliedExpression(ExpressionBuilder expressionBuilder, ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType)
   at Stashbox.Lifetime.LifetimeDescriptor.ApplyLifetime(ExpressionBuilder expressionBuilder, ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType)
   at Stashbox.Expressions.ExpressionBuilder.BuildExpressionAndApplyLifetime(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType)
   at Stashbox.Resolution.ResolutionStrategy.BuildExpressionForTopLevelRequest(Type type, Object name, ResolutionContext resolutionContext)
   at Stashbox.ResolutionScope.Activate(ResolutionContext resolutionContext, Type type, Object name)
   at Stashbox.ResolutionScope.Resolve(Type typeFrom, Boolean nullResultAllowed, Object[] dependencyOverrides)
   at Stashbox.ResolutionScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
   at lambda_method(Closure , IServiceProvider , Object[] )
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass4_0.<CreateActivator>b__0(ControllerContext controllerContext)
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
z4kn4fein commented 4 years ago

The fix is released in v3.1.2

reservoir-dogs commented 4 years ago

I tested it and it works! Thanks