unitycontainer / interception

Unity.Interception package
Apache License 2.0
22 stars 17 forks source link

.NetStandard - Interception works 1 level, but not 2. #14

Closed scovel closed 5 years ago

scovel commented 6 years ago

Interception at one level works... ControllerA(IBusinessServiceA businessService)

BusinessService is injected, I see WillExecute, GetRequiredInterfaces, Invoke all run

Interception 2-deep does not work... ControllerB(IBusinessServiceB businessService) BusinessServiceB(IDal dal)

I see Will Execute, GetRequiredInterfaces for Dal, and I see the DAL constructor fire, I see the BusinessServiceB constructor fire. WillExecute and GetRequiredInterfaces fire, then I get an exception.

container.RegisterType<IBusinessServiceA, BusinessServiceA>(new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<MyInterceptionBehaviorA>()); container.RegisterType<IBusinessServiceB, BusinessServiceB>(new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<MyInterceptionBehaviorA>()); container.RegisterType<IDal, Dal>(new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<MyInterceptionBehaviorB>());

Works fine with normal registration.

container.RegisterType<IBusinessServiceA, BusinessServiceA>(); container.RegisterType<IBusinessServiceB, BusinessServiceB>(); container.RegisterType<IDal, Dal>();

Here's the exception...

warn: Microsoft.AspNetCore.Server.Kestrel[0] Overriding address(es) 'http://localhost:53382/'. Binding to endpoints defined in UseKestrel() instead. Hosting environment: Development Content root path: c:\users\scovel\Source\Repos\TestUnity\TestUnity Now listening on: http://127.0.0.1:8088 Application started. Press Ctrl+C to shut down. fail: Microsoft.AspNetCore.Server.Kestrel[13] Connection id "0HLDAT7258BVT", Request id "0HLDAT7258BVT:00000001": An unhandled exception was thrown by the application. System.InvalidOperationException: Unable to resolve service for type 'TestUnity.Implementations.IBusinessServiceB' while attempting to activ ate 'TestUnity.Controllers.ValuesControllerB'. at Microsoft.Extensions.Internal.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParamete rRequired) at lambda_method(Closure , IServiceProvider , Object[] ) at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>cDisplayClass4_0.b0(ControllerContext controll erContext) at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>cDisplayClass5_0.gCreateController|0(Con trollerContext controllerContext) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d14.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d22.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d17.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d15.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Builder.RouterMiddleware.d4.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIIndexMiddleware.d3.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.d6.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Hosting.Internal.RequestServicesContainerMiddleware.d3.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Frame`1.d__2.MoveNext()

scovel commented 6 years ago

Additional information: Getting the following exception when running with a debug unity.interception:

System.InvalidOperationException: 'You cannot have more than one dynamic module in each dynamic assembly in this version of the runtime.'

The exception is in

public partial class InterfaceInterceptorClassGenerator { private static ModuleBuilder GetModuleBuilder() { string moduleName = Guid.NewGuid().ToString("N"); #if DEBUG_SAVE_GENERATED_ASSEMBLY return AssemblyBuilder.DefineDynamicModule(moduleName, moduleName + ".dll", true); #else return AssemblyBuilder.DefineDynamicModule(moduleName); <--exception here #endif } }

ENikS commented 5 years ago

Could you provide Unit Test I could run to reproduce?

witskeeper commented 5 years ago
var container = new Unity.UnityContainer();
            container.AddNewExtension<Unity.Interception.ContainerIntegration.Interception>();
            container.RegisterType<FakeInterceptionBehavior>();

            container.RegisterType<IFakeService, FakeServcice>(new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior(typeof(FakeInterceptionBehavior)));
            container.RegisterType<IFakeService2, FakeServcice2>(new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior(typeof(FakeInterceptionBehavior)));

            var service2 = container.Resolve<IFakeService2>();
            var service1 = container.Resolve<IFakeService>();
//got exception here
staal-it commented 5 years ago

Any news on this one?

I seem to be having the same problem:

Shared.DependencyInjection.Interfaces.DependencyResolutionFailedException : Resolution of the dependency failed, type = 'Shared.DependencyInjection.Unity.Interception.UnitTest.TestClasses.IMethodEntryExitLoggingTestClassWithExclude', name = '(none)'. Exception occurred while: while resolving. Exception is: InvalidOperationException - You cannot have more than one dynamic module in each dynamic assembly in this version of the runtime.

At the time of the exception, the container was: Resolving Shared.DependencyInjection.Unity.Interception.UnitTest.TestClasses.MethodEntryExitLoggingTestClass,(none) (mapped from Shared.DependencyInjection.Unity.Interception.UnitTest.TestClasses.IMethodEntryExitLoggingTestClassWithExclude, (none))

----> Unity.Exceptions.ResolutionFailedException : Resolution of the dependency failed, type = 'Shared.DependencyInjection.Unity.Interception.UnitTest.TestClasses.IMethodEntryExitLoggingTestClassWithExclude', name = '(none)'. Exception occurred while: while resolving. Exception is: InvalidOperationException - You cannot have more than one dynamic module in each dynamic assembly in this version of the runtime.

At the time of the exception, the container was: Resolving Shared.DependencyInjection.Unity.Interception.UnitTest.TestClasses.MethodEntryExitLoggingTestClass,(none) (mapped from Shared.DependencyInjection.Unity.Interception.UnitTest.TestClasses.IMethodEntryExitLoggingTestClassWithExclude, (none))

----> System.InvalidOperationException : You cannot have more than one dynamic module in each dynamic assembly in this version of the runtime. at Shared.DependencyInjection.Unity.Services.ResolveActionExecutor.Execute[T](Type typeToResolve, Func1 resolverFunc) in C:\sources\ - Shared\ - DependencyInjection\src\Unity\Services\ResolveActionExecutor.cs:line 19 at Shared.DependencyInjection.Unity.UnityDependencyContainer.Resolve[TFrom]() in C:\sources\ - Shared\ - DependencyInjection\src\Unity\UnityDependencyContainer.cs:line 124 at Shared.DependencyInjection.Unity.Interception.UnitTest.MethodEntryExitLoggingCallHandlerTest.Invoke_ExcludeOnClass_DoesNotLog() in C:\sources\ - Shared\ - DependencyInjection\src\Unity.Interception.UnitTest\MethodEntryExitLoggingCallHandlerTest.cs:line 59 --ResolutionFailedException at Unity.UnityContainer.ThrowingBuildUp(IBuilderContext context) in C:\projects\unity\Container\src\UnityContainer.Resolution.cs:line 52 at Unity.UnityContainerExtensions.Resolve[T](IUnityContainer container, ResolverOverride[] overrides) at Shared.DependencyInjection.Unity.UnityDependencyContainer.<Resolve>b__18_0[TFrom]() in C:\sources\ - Shared\ - DependencyInjection\src\Unity\UnityDependencyContainer.cs:line 124 at Shared.DependencyInjection.Unity.Services.ResolveActionExecutor.Execute[T](Type typeToResolve, Func1 resolverFunc) in C:\sources\ - Shared\ - DependencyInjection\src\Unity\Services\ResolveActionExecutor.cs:line 13 --InvalidOperationException at System.Reflection.Emit.AssemblyBuilder.DefineDynamicModuleInternalNoLock(String name, Boolean emitSymbolInfo, StackCrawlMark& stackMark) at System.Reflection.Emit.AssemblyBuilder.DefineDynamicModuleInternal(String name, Boolean emitSymbolInfo, StackCrawlMark& stackMark) at System.Reflection.Emit.AssemblyBuilder.DefineDynamicModule(String name) at Unity.Interception.Interceptors.InstanceInterceptors.InterfaceInterception.InterfaceInterceptorClassGenerator.GetModuleBuilder() at Unity.Interception.Interceptors.InstanceInterceptors.InterfaceInterception.InterfaceInterceptorClassGenerator.CreateTypeBuilder() at Unity.Interception.Interceptors.InstanceInterceptors.InterfaceInterception.InterfaceInterceptor.CreateProxy(Type t, Object target, Type[] additionalInterfaces) at Unity.Interception.Intercept.ThroughProxyWithAdditionalInterfaces(Type interceptedType, Object target, IInstanceInterceptor interceptor, IEnumerable1 interceptionBehaviors, IEnumerable1 additionalInterfaces) at Unity.Interception.ContainerIntegration.ObjectBuilder.InstanceInterceptionStrategy.PostBuildUp(IBuilderContext context) at Unity.UnityContainer.ThrowingBuildUp(IBuilderContext context) in C:\projects\unity\Container\src\UnityContainer.Resolution.cs:line 44

hecflores commented 5 years ago

After taking a look at the issue it seems to be a problem inside of the CreateTypeBuilder method of the InterfaceInterceptorClassGenerator class. In Netcore DynamicModules are only able to be initialized once but the Interceptor was initializing a new instances for every interception. The fix was to have the ModuleBuilder follow a singleton pattern to prevent it from initializing multiple times.

I have the fix ready and have provin locally but am getting a 403 when I push my branch.

@ENikS is there anything that is needed from me to become a contributor? Or am I missing something? :)

ENikS commented 5 years ago

Just submit a pull request and you are a contributor.

hecflores commented 5 years ago

I am not able to make a Pull Request because I need to push a Branch that I can do a Pull Request from.

I thought maybe you guys have a branch naming policy enabled so I tried two different branch names to do a Pull Request from and I get the same error.

Checked out issue/hectorhpflores72/14 Pushing issue/hectorhpflores72/14 Error encountered while pushing branch to the remote repository: Git failed with a fatal error. unable to access 'https://github.com/unitycontainer/interception.git/': The requested URL returned error: 403 Pushing to https://github.com/unitycontainer/interception.git

Checked out master Checked out master-issus-14 Pushing master-issus-14 Error encountered while pushing branch to the remote repository: Git failed with a fatal error. unable to access 'https://github.com/unitycontainer/interception.git/': The requested URL returned error: 403 Pushing to https://github.com/unitycontainer/interception.git

ENikS commented 5 years ago

Did you fork the repository or you are trying to push to the origin?

hecflores commented 5 years ago

I created a new branch off of the latest. Trying to push the branch so that I can open a PR off that branch for review... But when I push the branch I get permission errors.

On Mon, Nov 12, 2018 at 8:49 AM Eugene Sadovoi notifications@github.com wrote:

Did you fork the repository or you are trying to push to the origin?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/unitycontainer/interception/issues/14#issuecomment-437908614, or mute the thread https://github.com/notifications/unsubscribe-auth/AQgJiVbwWonqHizZuc-lQXi73bZyYDSpks5uuYqLgaJpZM4TkGeT .

yfital commented 5 years ago

Hey,

The solution was only semi and was fixed only for interface interception (not for virtual). I've already cloned and fix the bug for all interception types but I'm getting 403 (same as hecflores), I presume you need to open permissions for me? (branched off latest).

My solution is to move the module builder itself outside of the partial and have it receive the assembly builder, after that, it holds a concurrent dictionary which generates the dynamic module.

Let me know how I can push and i'll open the PR, Thanks.

ENikS commented 5 years ago

Are you getting 403 when creating pull request? You will not be able to write to repository directly.

yfital commented 5 years ago

No, I've created a branch from the latest and wanted to push it. Do i have to fork?

ENikS commented 5 years ago

You do need a fork to follow the GitHub workflow.

yfital commented 5 years ago

PR opened: https://github.com/unitycontainer/interception/pull/25

quintindk commented 5 years ago

thanks for this fix, works a charm.