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

Proxies using Records with a base class broken since .NET 6 #26602

Closed
Jejuni opened this issue Nov 10, 2021 · 14 comments
Closed

Proxies using Records with a base class broken since .NET 6 #26602

Jejuni opened this issue Nov 10, 2021 · 14 comments
Labels
area-external closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported Servicing-approved type-bug
Milestone

Comments

@Jejuni
Copy link

Jejuni commented Nov 10, 2021

Description

When using a record with a base class while having lazy loading proxies enabled any usage of the DbContext will immediately crash with the following TypeLoadException:

image

This exception did not happen before .NET 6 as we've used this kind of code all over our production code base with the expected results.

Repo

A Repo to quickly demonstrate the bug can be found here:
https://github.com/Jejuni/Net6RecordEfCoreProxies

Code

Entities look like this:

public class MyEntity
{
    public Guid Id { get; set; }
    public virtual MyRecord MyRecord { get; init; }
}

public record MyRecord : MyBaseRecord
{
    public int MyInt { get; init; }
}

public record MyBaseRecord
{
}

DbContext is configured to have MyRecord be an owned entity via OwnsOne.

Crashing code:

var ctx = new TestDbContext();
ctx.Database.EnsureDeleted();
ctx.Database.EnsureCreated();

However, the exception is also thrown when MyRecord is configured explicitly or per convention as a HasOne.
The exception is not thrown when a class is used in place of a record

Exception:

System.TypeLoadException: 'Return type in method 'Castle.Proxies.MyRecordProxy.<Clone>$()' on type 
'Castle.Proxies.MyRecordProxy' from assembly 
'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' 
is not compatible with base type method 'Net6RecordEfCoreProxies.MyRecord.<Clone>$()'.'

Include provider and version information

EF Core version: 6.0.0
Database provider: Microsoft.EntityFrameworkCore.SqlServer / InMemory / Probably any other one as well
Target framework: .NET 6.0
Operating system: Windows 10
IDE: Visual Studio 2022 17.0.0

@enterprisebug
Copy link

Any update on this ;-)

@ajcvickers
Copy link
Member

Note for triage: this reproduces with with the .NET 6 SDK when targeting .NET 5 or .NET 6, regardless of the version of EF used. Could this be a compiler/SDK issue? I have not yet tried going back to the .NET 5 SDK.

/cc @Pilchie @jaredpar

Full trace:

Unhandled exception. System.TypeLoadException: Return type in method 'Castle.Proxies.MyRecordProxy.<Clone>$()' on type 'Castle.Proxies.MyRecordProxy' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not compatible with base type method 'Net6RecordEfCoreProxies.M
yRecord.<Clone>$()'.
   at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
   at System.Reflection.Emit.TypeBuilder.CreateTypeInfo()
   at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.CreateType(TypeBuilder type)
   at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType()
   at Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateType(String name, Type[] interfaces, INamingScope namingScope)
   at Castle.DynamicProxy.Generators.ClassProxyGenerator.<>c__DisplayClass1_0.<GenerateCode>b__0(String n, INamingScope s)
   at Castle.DynamicProxy.Generators.BaseProxyGenerator.<>c__DisplayClass33_0.<ObtainProxyType>b__0(CacheKey _)
   at Castle.Core.Internal.SynchronizedDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Castle.DynamicProxy.Generators.BaseProxyGenerator.ObtainProxyType(CacheKey cacheKey, Func`3 factory)
   at Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateCode(Type[] interfaces, ProxyGenerationOptions options)
   at Castle.DynamicProxy.DefaultProxyBuilder.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
   at Microsoft.EntityFrameworkCore.Proxies.Internal.ProxyFactory.CreateProxyType(ProxiesOptionsExtension options, IEntityType entityType)
   at Microsoft.EntityFrameworkCore.Proxies.Internal.ProxyBindingRewriter.ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext`1 context)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalizing(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalizing(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
   at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.get_Dependencies()
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureDeleted()
   at Program.<Main>$(String[] args) in C:\local\code\repros\Net6RecordEfCoreProxies-master\Net6RecordEfCoreProxies-master\Net6RecordEfCoreProxies\Program.cs:line 6

@Jejuni
Copy link
Author

Jejuni commented Nov 10, 2021

I feel this comes from an internal change to how the clone method works and how Castle.Proxies does its stuff.

Comparing .NET5 and 6 on sharplab.io (main for .NET6 and C# 9: Covariant(31 Jul 2020) for .NET5) the down-leveled code for records as it relates to records with inheritance looked like this:

image

C#9 / .NET5

[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public class Child : Base, IEquatable<Child>
{
    // (...) Irrelevant stuff omitted

    public override Base <Clone>$()
    {
        return new Child(this);
    }

    protected Child(Child original)
        : base(original)
    {
        <MyInt>k__BackingField = original.<MyInt>k__BackingField;
    }

    public Child()
    {
    }
}

C10 / .NET6

[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public class Child : Base, IEquatable<Child>
{
   // (...) Irrelevant stuff omitted

    [PreserveBaseOverrides]
    public new virtual Child <Clone>$()
    {
        return new Child(this);
    }

    protected Child(Child original)
        : base(original)
    {
        <MyInt>k__BackingField = original.<MyInt>k__BackingField;
    }

    public Child()
    {
    }
}

The most glaring change here is going from simply overriding and return Base in .NET5 to using new and returning the child type in .NET6.
This also aligns with the emitted exception.

@jaredpar
Copy link
Member

The C# compiler changed the emit strategy for records in .NET 6 to take advantage of covariant returns. The Clone method now always has a return type that matches the containing type. Covariant returns were added to the runtime and language in .NET 5 but records didn't take advantage of them (just ran out of time). In .NET 6 though we finished off that feature and added it to records.

@jcouv

@ajcvickers
Copy link
Member

Filed castleproject/Core#601 on the Castle Proxies repo.

@richardpawson
Copy link

"The C# compiler changed the emit strategy for records in .NET 6 to take advantage of covariant returns.... In .NET 6 though we finished off that feature and added it to records." (@jaredpar)

@ajcvickers : If this is correct then surely the issue does lie with EF Core? i.e. EF Core must be changed to work correctly with the new version of Roslyn not vice versa?

@ajcvickers
Copy link
Member

@richardpawson Agreed that Roslyn is not at issue. Instead, Castle Proxies needs to understand the differently generated code, hence the external issue here is castleproject/Core#601

@richardpawson
Copy link

@ajcvickers I'm concerned now. The Castle Proxies project doesn't seem very active: no code check-ins since March, and limited response to several raised issues. The EF Core team took the decision to make this Microsoft product dependent upon a third-party open source product. Can you provide some reassurance that you have sufficient influence or a private arrangement to get this bug fixed? It is impacting us substantially.

@ajcvickers
Copy link
Member

ajcvickers commented Nov 16, 2021

@richardpawson We will follow up with them and provide help where we can. We are committed to an open-source ecosystem. The alternative to using Castle Proxies would likely have been to drop lazy-loading from EF Core, since usage numbers are very low, and lazy-loading is largely considered an anti-pattern these days.

@richardpawson
Copy link

@ajcvickers Why has this been marked as closed? It might well be that the root of the issue lies in Castle (although they might argue -if they respond at all - that its is not a bug) but since the result is that EF Core does not work correctly in .NET 6, for a documented capability that worked correctly in .NET 5, surely this is a bug that you must take ownership of? Marking it as closed is denying that it is an issue.

@ajcvickers
Copy link
Member

@richardpawson We are tracking the Castle issue. There is currently no action to take on the EF side.

@ajcvickers ajcvickers reopened this Jan 6, 2022
@ajcvickers
Copy link
Member

Reopening to consider a patch that avoids this problem for records with base types, inspired by #27073.

@ajcvickers ajcvickers self-assigned this Jan 6, 2022
@ajcvickers ajcvickers added this to the 6.0.x milestone Jan 6, 2022
ajcvickers added a commit that referenced this issue Jan 6, 2022
Fixes #26602

**Description**

The C# compiler changed the emit strategy for records in .NET 6 to take advantage of covariant returns. The Clone method now always has a return type that matches the containing type. Castle dynamic proxies throws when attempting to create a proxy for such types. This means EF Core lazy-loading and change-tracking proxies are broken for any record with a base type.

An bug has been filed on Castle proxies (castleproject/Core#601), which is the correct place to ultimately fix this issue. However, since EF Core never needs to override the Clone method for its proxies, the fix here simply excludes the Clone method from the proxies we create.

**Customer impact**

Proxies for records with base types cannot be used. Reported by multiple customers. No known workaround.

How found

Multiple customer reports on 6.0.

Regression

Yes, From 5.0

Testing

Added unit and functional tests for records with base types.

Risk

Very low; Clone methods are never used by EF proxies. Also added quirk to revert to previous behavior.
ajcvickers added a commit that referenced this issue Jan 7, 2022
ajcvickers added a commit that referenced this issue Jan 10, 2022
@ajcvickers ajcvickers modified the milestones: 6.0.x, 6.0.2 Jan 10, 2022
@ajcvickers ajcvickers added closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. Servicing-approved and removed Servicing-consider labels Jan 10, 2022
@Homainc
Copy link

Homainc commented Feb 15, 2022

In version 6.0.2 if base record is an abstract public abstract record MyBaseRecord; the same error occurs:

Unhandled exception. System.TypeLoadException: Return type in method 'Castle.Proxies.MyRecordProxy.<Clone>$()' on type 'Castle.Proxies.MyRecordProxy' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not compatible with base type method 'Sandbox.Console.MyRecord.<Clone>$()'.
   at System.Reflection.Emit.TypeBuilder.TermCreateClass(QCallModule module, Int32 tk, ObjectHandleOnStack type)
   at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
   at System.Reflection.Emit.TypeBuilder.CreateTypeInfo()
   at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.CreateType(TypeBuilder type)
   at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType()
   at Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateType(String name, Type[] interfaces, INamingScope namingScope)
   at Castle.DynamicProxy.Generators.ClassProxyGenerator.<>c__DisplayClass1_0.<GenerateCode>b__0(String n, INamingScope s)
   at Castle.DynamicProxy.Generators.BaseProxyGenerator.<>c__DisplayClass33_0.<ObtainProxyType>b__0(CacheKey _)
   at Castle.Core.Internal.SynchronizedDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Castle.DynamicProxy.Generators.BaseProxyGenerator.ObtainProxyType(CacheKey cacheKey, Func`3 factory)
   at Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateCode(Type[] interfaces, ProxyGenerationOptions options)
   at Castle.DynamicProxy.DefaultProxyBuilder.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
   at Microsoft.EntityFrameworkCore.Proxies.Internal.ProxyFactory.CreateProxyType(ProxiesOptionsExtension options, IReadOnlyEntityType entityType)
   at Microsoft.EntityFrameworkCore.Proxies.Internal.ProxyBindingRewriter.ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext`1 context)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalizing(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalizing(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelRuntimeInitializer.Initialize(IModel model, Boolean designTime, IDiagnosticsLogger`1 validationLogger)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, ModelCreationDependencies modelCreationDependencies, Boolean designTime)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel(Boolean designTime)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__8_4(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass2_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.get_ContextServices()
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.get_Dependencies()
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureCreated()

stakx added a commit to stakx/Castle.Core that referenced this issue May 13, 2022
On .NET 6+ this fails with a `TypeLoadException`:

> Return type in method `DerivedEmptyRecord.<Clone>$()` [...] is not
> compatible with base type method `EmptyRecord.<Clone>$()`

From dotnet/efcore#26602 (comment):

> The C# compiler changed the emit strategy for records in .NET 6 to
> take advantage of covariant returns. The Clone method now always has a
> return type that matches the containing type. Covariant returns were
> added to the runtime and language in .NET 5 but records didn't take
> advantage of them (just ran out of time). In .NET 6 though we finished
> off that feature and added it to records.

So we'll need to add support for covariant returns to DynamicProxy.
stakx added a commit to stakx/Castle.Core that referenced this issue May 14, 2022
On .NET 6+ this fails with a `TypeLoadException`:

> Return type in method `DerivedEmptyRecord.<Clone>$()` [...] is not
> compatible with base type method `EmptyRecord.<Clone>$()`

From dotnet/efcore#26602 (comment):

> The C# compiler changed the emit strategy for records in .NET 6 to
> take advantage of covariant returns. The Clone method now always has a
> return type that matches the containing type. Covariant returns were
> added to the runtime and language in .NET 5 but records didn't take
> advantage of them (just ran out of time). In .NET 6 though we finished
> off that feature and added it to records.

So we'll need to add support for covariant returns to DynamicProxy.
@ajcvickers ajcvickers removed their assignment Aug 31, 2024
@Yuvix25
Copy link

Yuvix25 commented Sep 18, 2024

FYI - Castle.Core has a new (ish) version - 5.1.1.
Currently (at least in 7.0.20) in Microsoft.EntityFrameworkCore.Proxies, Castle.Core 5.1.0 is the version which is being used, in which this issue is still not fully fixed (see 5.1.1 release notes).
Manually upgrading to 5.1.1 resolved this issue for me, should probably be bumped in Microsoft.EntityFrameworkCore.Proxies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-external closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported Servicing-approved type-bug
Projects
None yet
Development

No branches or pull requests

7 participants