-
-
Notifications
You must be signed in to change notification settings - Fork 794
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
Prevent proxy types from being generated for an interface #739
Comments
@bclothier: TBH I haven't studied your code in great detail, I will start by offering a guess at what might go wrong: COM type hierarchies often don't make much use of subclassing. Co-classes often implement a whole bunch of interfaces that aren't related to one another through subtyping / inheritance; each of those interfaces describes one aspect of the co-class and you use Specifically, if you have a COM interface You can tell Moq which additional (unrelated) interfaces the proxy should implement before you ask it for the mock object (proxy) through calls to var mock = new Mock<TDefaultInterface>();
mock.As<TAdditionalInterface1>();
mock.As<TAdditionalInterface2>();
...
var mocked = mock.Object; Have you tried this? I might be completely off with the above, in which case I'll take a closer look. But using Btw. if you're not using any other capabilities of Moq beyond |
Hi, in fact, yes. It is covered in this commit. Even so, casts doesnt seem to always work. I partially put it off in an earlier commit but that was not a complete fix. I may try modifying the cache to cache the final closed type but I worry that may devolve into a whack-a-mole game. Regarding the last comment, the intention is to provide a COM compatible wrapper of Moq, exposing Setup, Returns, and Callback. |
@bclothier - OK. In this case I am not super-sure whether I can be of much help, as I don't have much experience with how .NET exposes .NET objects to COM (CCWs). I can run some experiments during the next few days, but hopefully someone else can chime in and help you out before that. If you're ready to dig into this more deeply, perhaps it would be good to run some experiments first by peeling the Moq layer away and see how it works when you create a DynamicProxy proxy directly and try to call |
OK, I've been doing some reading up on the DynamicProxy to understand how it works. I did come across this tidbit which suggests that if using |
Ok, I have an update - following your suggestion to set up a MCVE, I quickly found that the unit tests I wrote in a test solution was passing using strong-typed version. It still even passes even using reflection (as I was in my code originally). Still passes even with the wrapper object. In the end, it turns out that it's not even Moq nor DynamicProxy at the play. It's all caused by this seemingly unrelated code:
Basically, this covers the case where we do not get a type because the PIA isn't in GAC or whatever reasons. In that situation, we get a generic In that case, the type returned looks and acts like the actual COM interface that we're wanting but it's not the same interop type; trying to do a equality test or comparing hash code between the returned type vs. the PIA's I apologize; I got misled by the whole proxying affair, thinking it was a problem with how it was represnted. In end, this was a X-Y problem. For that reason, I'll close that issue now. |
@bclothier: No need to apologize, glad to hear you figured this one out! |
I'm developing a mocking framework based on Moq for use in VBA (ref #rubberduck-vba/Rubberduck/pull/4681).
I'm running into a problem where proxies cannot be cast to their interfaces. From what I understand, that might be due to the fact that dynamic proxies don't actually implement the COM interfaces but create a substitute type with similar names & properties, which then cause problems in testing the mocking framework because I cannot cast it to the COM interface's interop type.
All mocks are using interfaces discovered via runtime as per this code, so I believe it falls into this conditional branch in Moq:
https://github.com/moq/moq4/blob/670123672fbc30d92971bcb83860c5a25b4e3ec6/src/Moq/ProxyFactories/CastleProxyFactory.cs#L62-L67
I'm not sure I fully understand the ramifications but from what I observed, this seems to create a proxy type that has a similar interface but do not in fact implement the original interfaces they were created for. My reading of Castle's DynamicProxy seems to suggest that creating one without a target will cause this behavior. Here's some code (adapted from this unit test) to demonstrate the issue:
The last line fails with an error:
Obviously that makes the test more complicated than it should be. However, this isn't a test-only issue. On the VBA side, we can get this error:
If we look at the mocked object, we can see that the 2nd proxy type was generated:
So code would work as long only one proxy type was generated but if 2nd proxy type for same COM interface gets created, we get the errors.
Is it possible for Moq to provide a means to explicitly control how proxy types should be created and to actually implement the interfaces as opposed to creating a mirror interface that can't be converted into the original interface? Or is this an issue with the Castle's implementation of the DynamicProxy?
The text was updated successfully, but these errors were encountered: