-
Notifications
You must be signed in to change notification settings - Fork 152
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
Exception thrown when attempting to inject COM interface #986
Comments
I'm afraid this is a bug I can't fix. Fixing this quite radically changes the way Simple Injector works. Basically, the problem can be demonstrated with the following code: var comObject = new Inventor.Application();
Type consumer = typeof(Foo<Inventor.Application>);
var ctor = consumer.GetConstructors().Single();
var param = ctor.GetParameters().Single();
var comExpr = Expression.Constant(comObject);
Expression.New(ctor, comExpr);
public record Foo<T>(T instance) { } When
Notice, BTW, how this code is pure .NET code. It runs without Simple Injector. This exception is caused by a limitation in Although it's not impossible for Simple Injector to work around this limitation of the .NET framework, this is not an investment I'm willing to make. Not only is this an enormous undertaking for a corner case scenario, more importantly, it forces me to make breaking changes to the API of Simple Injector—something I never take lightly. You can expect other DI Containers to have similar limitations, especially the one's that are more optimized. Chances are slim, for instance, that this would work with MS.DI. Not all is lost, though. Simple workarounds exist. I'd like to propose a workaround, which is to make the COM object accessible through a 'provider' class or abstraction and to inject that provider instead of injecting the COM object directly. For instance: // Application:
public sealed record AutodeskProvider(Inventor.Application Application);
public class UserInterfaceManager : IUserInterfaceManager
{
// Inject IAutodeskProvider instead of Inventor.Application
public UserInterfaceManager(AutodeskProvider provider) ...
} // Composition Root
// Register AutodeskProvider instead of Inventor.Application.
container.RegisterInstance(new AutodeskProvider(new Inventor.Application())); This works, because the COM object is no longer part of the constructor signature that is being constructed by Simple Injector and compiled by .NET. |
Hi Steven, First of all, I want to thank you for taking the time to write such an extensive response! I agree it is not worth the large effort, as you describe it, to make Simple Injector work fully with the relic that COM Interop is. I sure hope Autodesk will move to a .NET API one day; the current API feels so outdated... Now that you are mentioning Microsoft.Extensions.DependencyInjection... I use that in my current implementation. It actually works directly with the COM interface. However, I decided to switch to Simple Injector because Autodesk ships Inventor with version 1.0.0 of Microsoft.Extensions.DependencyInjection. The .config files of add-ins are completely ignored, so I have to hack the .config file of Inventor to redirect to newer versions of the library. This was unacceptable for me. Also, thank you for suggesting a workaround. I had already had something comparable in mind. I'm glad I don't have to discard Simple Injector either. I wish you happy hollidays! |
Interesting to hear that this actually works with MS.DI. That means they abandoned using It took me a few hours to investigate this and write the response. After reproducing the issue in a unit test my intention was on fixing this issue. That code was added in v5 which was based on #598. That's because there already is some code inside Simple Injector that detects whether a registration is for a COM object and tries to work around the limitation within the But during the process I slowly started to realize that the code in place actually did very little. The code allowed to directly resolve a COM object from the container, but that's hardly ever useful. If you're requesting the COM object directly from the container, you could as well pass it manually without the container. Because of this, I'm considering to remove the current COM object checks from the container and instead prevent the registration of COM objects altogether and throw an exception that points at a section in the documentation that explains how to work with COM objects (that section still has to be written). |
I did some quick searching and from what I've read |
Describe the bug
I am integrating Simple Injector into an AddIn-type application for Autodesk Inventor. Inventor exposes its API through COM interop. The primary entry point is a COM interface named Inventor.Application. Contrary to its name, this is indeed an interface, not a class. The Application instance gets successfully registered in the container using: container.RegisterInstance(inventor). Subsequently, the instance is retrieved successfully with: var inventor = container.GetInstance();. However, when the COM interface is utilized in the constructors of services, an exception is thrown upon calling container.Verify().
Expected behavior
I expect the Application instance to be injected into services.
Actual behavior
Instead the following exception is thrown:
To Reproduce
As I assume you may not have access to an Autodesk Inventor installation, the steps below can help simulate my situation:
container.RegisterInstance(comInstance)
container.Verify()
container.Register<IService, Service>()
Additional context
If you require any assistance, I am more that glad to help you out!
The text was updated successfully, but these errors were encountered: