autofac / Autofac

An addictive .NET IoC container
https://autofac.org
MIT License
4.44k stars 836 forks source link

Type equivalence for the embedded interop types not working #1400

Closed snechaev closed 8 months ago

snechaev commented 8 months ago

Describe the Bug

The embedded interop types (at least enums) are treated as the different types when embedded into the different assemblies. So, if the registration and resolving are in the different assemblies, the resolution will fail. More details and sample project below.

I'm using the COM interop in my project. The interop assembly (made with the tlbimp) is referenced in several projects in the solution (everywhere with the Embedded interop types = true). In the following description the psBlendMode is the enum from the interop assembly (so, it is also embedded into the each assembly in the solution).

I have two assemblies - the Lib (class library) and the App (exe). The container registrations are made in the Lib. The resolutions are made in the App.

The registred service are dependent on the psBlendMode

builder.RegisterType<BlendModeService>().As<IService<PsBlendMode>>();

If I trying to resolve from the code inside the Lib, all works fine. If I move resolution code into the App, resolution will fail. If I will get the same type from the Lib assembly with reflection, the resoltion will succeed

//inside App assembly
var libType = typeof(IService<>).Assembly.GetType(typeof(PsBlendMode).FullName!)!; //find PsBlendMode in the Lib assembly
var genericListType = typeof(IService<>).MakeGenericType(libType); //generate service type to resolve

var canResolveLibEnum = container.TryResolve(genericListType, out _); //PsBlendMode from the Lib -> ok
var canResolveCurrentAssemblyEnum = container.TryResolve(typeof(IService<PsBlendMode>), out _); // PsBlendMode from the App -> fail

The runtime treated these types as the equivalent: typeof(PsBlendMode).IsEquivalentTo(libType) is true.

Steps to Reproduce

Expected Behavior

Registered service IService<PsBlendMode> should resolve correctly regardless of the assembly resolution code is called from.

Exception with Stack Trace

The code attached does not throw any exception, but if use Resolve instead of the TryResolve, the exception will be the following

Autofac.Core.Registration.ComponentNotRegisteredException
  HResult=0x80131500
  Message=The requested service 'Lib.IService`1[[Photoshop.PsBlendMode, ConsoleApp11, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.

See https://autofac.rtfd.io/help/service-not-registered for more info.
  Source=Autofac
  StackTrace:
   at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
   at Program.<Main>$(String[] args) in D:\delme\ConsoleApp11\ConsoleApp11\Program.cs:line 24

Dependency Versions

Autofac:

Additional Info

Related issue which claims that No-PIA scenario is supported: https://github.com/autofac/Autofac/issues/211

I digged into the history and found this related commits

Additional info about type equivalence and embedded interop types: https://learn.microsoft.com/en-us/dotnet/framework/interop/type-equivalence-and-embedded-interop-types

tillig commented 8 months ago

I'm not going to lie, COM interop support and troubleshooting this is not going to make it to the list of priorities.

We're long past portable class libraries and into supporting .NET Core SDKs and netstandard.

The issue you mentioned, #211, is from 2010 - 13 years ago now and many, many breaking-change-major-releases ago. If it's not working now... it's not supported. Likely somewhere in there, transitioning from per-platform libraries to portable class libraries to .NET core, we lost that ability.

If you want support for this put back, we'd be happy to look at a PR for it. We will not accept PRs that target .NET desktop framework, have a lot of #ifdef sorts of things in it, or will otherwise cause a maintenance challenge for us. If it's something simple like changing an == to a .Equals call, awesome; if it's super complex, probably not.