Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WindsorContainer UsingFactoryMethod broken on upgrade to 4.8.0+ #608

Closed
Jevonius opened this issue Mar 26, 2018 · 3 comments
Closed

WindsorContainer UsingFactoryMethod broken on upgrade to 4.8.0+ #608

Jevonius opened this issue Mar 26, 2018 · 3 comments

Comments

@Jevonius
Copy link

Jevonius commented Mar 26, 2018

Hi,

I'm in the process of updating Nuget packages in our solution and have come across a problem updating to newer versions of Moq (4.8.0+). For background, we were running on 4.7.99 and jumped to 4.8.2, but I've narrowed the issue down to the move from 4.7.145 -> 4.8.0.

Code such as the following:

using Castle.Core.Logging;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using Moq;
...
	var container = new WindsorContainer();
	container.Register(Component.For<ILogger>().UsingFactoryMethod(() => new Mock<ILogger>().Object));
	var logger = container.Resolve<ILogger>();

Generates the exception:

System.NotSupportedException: Can not apply commission concerns to component Late bound Castle.Core.Logging.ILogger because it appears to be a target-less proxy. Currently those are not supported.

I've dug into the Castle and Moq source as much as I can, but it's a bit beyond me without spending significantly more time on it. The exception is being thrown in Castle.MicroKernel.ComponentActivator.AbstractComponentActivator.ApplyCommissionConcerns.

There are a couple of ways I can work around the issue - change the registration to .Instance(new Mock<ILogger>().Object) for example, or use the UsingFactoryMethod overload and setting managedExternally to true, but the first potentially causes slightly different behaviour to our 'real' code, and I don't fully understand the impact of the second - plus it means finding and remembering to do this everywhere we want to use a Mock object in this way.

I'm not entirely sure which change caused this behaviour - I thought at first it was related to #476 but the issue doesn't exist in v4.8.0-rc1, so #550 seems like a more likely candidate.

@stakx
Copy link
Contributor

stakx commented Mar 26, 2018

@Jevonius:

the issue doesn't exist in v4.8.0-rc1

This might be related to #551, which the changelog entry for 4.8.0 only mentions indirectly (emphasis added):

Same as 4.8.0-rc1 (see below), plus some significant speed improvements.

PR #551 changed the way how Moq creates DynamicProxy proxy objects for interface types. Moq used DynamicProxy's proxyGenerator.CreateClassProxy up until and including 4.8.0-rc1, but that PR changed interface proxy creation to use the CreateInterfaceProxyWithoutTarget method instead, which is much more efficient and nearly doubles Moq's performance for interface mock creation. For that reason, it is very unlikely that we'll revert the change.

Apart from that, your issue appears to be one with Castle—the error message clearly isn't coming from Moq.

I am not familiar with the Castle APIs that you are using.

I suggest you do either of the following:

  • If you're not in a rush, upgrade your code to Moq 5 (https://github.com/moq/moq) which is close to getting published. Moq 5 is no longer based on DynamicProxy nor any other dynamic proxying library, so I could imagine this problem will just go away.

  • Alternatively, ask over at the Castle.Core repo about the error message you're seeing. Ideally, you'd provide them with repro code where Moq has been taken out of the picture but since I don't know Castle Logging nor Windsor, I can't say whether that would make sense in this case.

  • If you just want to resolve this quickly, downgrade to Moq 4.7.145. You won't have a few new features such as improved support for by-ref parameters, but it's otherwise a very stable version.

@stakx
Copy link
Contributor

stakx commented Mar 26, 2018

Oh btw. I think you can approximate what previous versions of Moq did by changing your code to this:

.UsingFactoryMethod(() => new Mock<object>().As<ILogger>().Object))

This might make your code work with Moq 4.8.x, if it worked previously with Moq 4.7.x.

@Jevonius
Copy link
Author

I suspect you're probably right about the issue being related to #551 - the exception being thrown does sound closely tied to CreateInterfaceProxyWithoutTarget. I took it as a Moq issue as it broke while with the same version of Castle components, but I agree it is more of an issue with Castle - odd/frustrating that they allow you to create an object in DynamicProxy that you can't then use properly in Windsor!

I'll discuss with my team whether we settle on one of the workarounds (your suggestion works, thank you), stick with 4.7.145, or give 5 a test - will keep an eye out for that either way.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants