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

System.TypeLoadException with EfficientDynamoDb IUpdateEntityRequestBuilder<TEntity> #866

Open
baynezy opened this issue Feb 24, 2025 · 15 comments

Comments

@baynezy
Copy link

baynezy commented Feb 24, 2025

Describe the bug
I am trying to create a mock of IUpdateEntityRequestBuilder<TEntity>. When I do this I get a System.TypeLoadException

To Reproduce

  1. Create new project
  2. Install EfficientDynamoDb via NuGet
  3. Attempt to create a mock of IUpdateEntityRequestBuilder<TEntity>. E.g. var builderMock = Substitute.For<IUpdateEntityRequestBuilder<object>>();
  4. Run code

Please make sure you are using NSubstitute.Analyzers and that it does not pick up any problems with the reproduction code. The analyzers can help detect the cause of many issues.

Expected behaviour
I expect that the mock would be created successfully.

Environment:

  • NSubstitute version: 5.3.0
  • NSubstitute.Analyzers version: CSharp 1.0.17
  • Platform: xunit test project, .net 8, Windows 11

Additional context
Is this because IUpdateEntityRequestBuilder<TEntity> extends IUpdateItemBuilder<IUpdateEntityRequestBuilder<TEntity>> which has an internal method?

internal TUpdateRequestBuilder Create(UpdateBase update, BuilderNodeType nodeType);
@304NotModified
Copy link
Contributor

304NotModified commented Feb 24, 2025

Could you please post the full exception details included the innerexceptions?

@baynezy
Copy link
Author

baynezy commented Feb 25, 2025

@304NotModified - sure.

System.TypeLoadException
Method 'Create' in type 'Castle.Proxies.ObjectProxy' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
   at System.Reflection.Emit.RuntimeTypeBuilder.CreateTypeNoLock()
   at System.Reflection.Emit.RuntimeTypeBuilder.CreateTypeInfoImpl()
   at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.CreateType(TypeBuilder type)
   at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType()
   at Castle.DynamicProxy.Generators.BaseClassProxyGenerator.GenerateType(String name, INamingScope namingScope)
   at Castle.DynamicProxy.Generators.BaseProxyGenerator.<>c__DisplayClass13_0.<GetProxyType>b__0(CacheKey cacheKey)
   at Castle.Core.Internal.SynchronizedDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Castle.DynamicProxy.Generators.BaseProxyGenerator.GetProxyType()
   at Castle.DynamicProxy.DefaultProxyBuilder.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
   at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
   at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors)
   at NSubstitute.Proxies.CastleDynamicProxy.CastleDynamicProxyFactory.CreateProxyUsingCastleProxyGenerator(Type typeToProxy, Type[] additionalInterfaces, Object[] constructorArguments, IInterceptor[] interceptors, ProxyGenerationOptions proxyGenerationOptions, Boolean isPartial)
   at NSubstitute.Proxies.CastleDynamicProxy.CastleDynamicProxyFactory.GenerateTypeProxy(ICallRouter callRouter, Type typeToProxy, Type[] additionalInterfaces, Boolean isPartial, Object[] constructorArguments)
   at NSubstitute.Proxies.CastleDynamicProxy.CastleDynamicProxyFactory.GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[] additionalInterfaces, Boolean isPartial, Object[] constructorArguments)
   at NSubstitute.Core.SubstituteFactory.Create(Type[] typesToProxy, Object[] constructorArguments, Boolean callBaseByDefault, Boolean isPartial)
   at NSubstitute.Core.SubstituteFactory.Create(Type[] typesToProxy, Object[] constructorArguments)
   at NSubstitute.Substitute.For(Type[] typesToProxy, Object[] constructorArguments)
   at NSubstitute.Substitute.For[T](Object[] constructorArguments)
   at NSubstituteIssue.Class1.Example() in C:\_temp\NSubstituteIssue\NSubstituteIssue\Class1.cs:line 12
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

@304NotModified
Copy link
Contributor

304NotModified commented Feb 25, 2025

Do you know if this works in Moq? Because I'm doubting if this a NSubstitute or Castle.Core issue

@baynezy
Copy link
Author

baynezy commented Feb 25, 2025

@304NotModified with Moq I get:

System.TypeLoadException
Method 'Create' in type 'Castle.Proxies.IUpdateEntityRequestBuilder`1Proxy' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
   at System.Reflection.Emit.RuntimeTypeBuilder.CreateTypeNoLock()
   at System.Reflection.Emit.RuntimeTypeBuilder.CreateTypeInfoImpl()
   at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.CreateType(TypeBuilder type)
   at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType()
   at Castle.DynamicProxy.Generators.BaseInterfaceProxyGenerator.GenerateType(String typeName, INamingScope namingScope)
   at Castle.DynamicProxy.Generators.BaseProxyGenerator.<>c__DisplayClass13_0.<GetProxyType>b__0(CacheKey cacheKey)
   at Castle.Core.Internal.SynchronizedDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Castle.DynamicProxy.Generators.BaseProxyGenerator.GetProxyType()
   at Castle.DynamicProxy.DefaultProxyBuilder.CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
   at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
   at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, IInterceptor[] interceptors)
   at Moq.CastleProxyFactory.CreateProxy(Type mockType, IInterceptor interceptor, Type[] interfaces, Object[] arguments) in /_/src/Moq/Interception/CastleProxyFactory.cs:line 50
   at Moq.Mock`1.InitializeInstance() in /_/src/Moq/Mock`1.cs:line 309
   at Moq.Mock`1.OnGetObject() in /_/src/Moq/Mock`1.cs:line 323
   at Moq.Mock.get_Object() in /_/src/Moq/Mock.cs:line 181
   at Moq.Mock`1.get_Object() in /_/src/Moq/Mock`1.cs:line 281
   at NSubstituteIssue.Class1.MoqExample() in C:\_temp\NSubstituteIssue\NSubstituteIssue\Class1.cs:line 19
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

@baynezy
Copy link
Author

baynezy commented Feb 25, 2025

Does this mean that I cannot mock this interface at all?

@304NotModified
Copy link
Contributor

304NotModified commented Feb 25, 2025

Not sure, it could be a bug in Castle.Core

Could you try to reproduce it with your own interface and make the interface as minimal as possible?

@baynezy
Copy link
Author

baynezy commented Feb 26, 2025

@304NotModified - It all seems to stem from having an internal method. See https://github.com/baynezy/NSubstituteIssue

@304NotModified
Copy link
Contributor

304NotModified commented Feb 26, 2025

Thanks for this nice small reproduction example! :)

I doubting about the next step. I guess we should ask this at https://github.com/castleproject/Core?

@baynezy
Copy link
Author

baynezy commented Feb 27, 2025

@304NotModified - do you have advice on how I raise that with the Castle Project? Are they going to work OK with my example? Or are they going to need a lower level investigation?

@304NotModified
Copy link
Contributor

Hi @baynezy

I tested your great example. I've noticed with even a smaller interface it's an issue.

This is OK

public interface IExample
{
    bool Check();
}

This fails

public interface IExampleWithInternal
{
    internal bool Check();
}

See baynezy/NSubstituteIssue#1

@baynezy
Copy link
Author

baynezy commented Feb 27, 2025

Thanks @304NotModified - I have merged that.

Did you have any thoughts on the best way to raise that with https://github.com/castleproject/Core ?

@304NotModified
Copy link
Contributor

304NotModified commented Feb 27, 2025

I searched for a related issue, but have found one. So I guess we have create a new issue and ask if internal methods in interfaces are supported. Unfortunately I don't know if this a issue by Moq/NSub or Castle.Core.

@304NotModified
Copy link
Contributor

304NotModified commented Feb 27, 2025

@baynezy Are you creating a new GitHub issue on https://github.com/castleproject/Core?

@baynezy
Copy link
Author

baynezy commented Feb 27, 2025

@304NotModified done castleproject/Core#695

@JasonBock
Copy link

@baynezy FWIW there's no way Castle.Core could create an implementation of this interface. As you stated, the Create() method on IUpdateEntityRequestBuilder<> via IUpdateItemBuilder<> is internal, as well as the UpdateBase parameter type, so a class can't implement the interface. Though it probably shouldn't throw a TypeLoadException :)

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

3 participants