dadhi / DryIoc

DryIoc is fast, small, full-featured IoC Container for .NET
MIT License
1.01k stars 123 forks source link

[BUG] Resolve<> crashes with the misleading, casting-related Exception when class is also registered using RegisterInitializer #648

Closed MacSz-mjss closed 3 months ago

MacSz-mjss commented 3 months ago

Hello,

We use DryIoc in our project and don't always create registrations with standard DI Register<TAbstraction, TImplementation> manner, but rather simplified Register<TImplementation>. Having DryIoc, we also use RegisterInitializer, like so:

container.Register<SomeClass1>(Reuse.Singleton);
container.Register<SomeClass2>(Reuse.Singleton);
container.RegisterInitializer<SomeClass2>((service, _) => service.Initialize());

Under some circumstances, creating these instances for the very first time, using Resolve<>, can throw an Exception and this is expected behavior for our application.

We have recently found a bug in DryIoc that throws DryIoc logic-related Exception instead of the real Exception, thrown by our code while creating our instance using Resolve<>. The Exceptions thrown are related to object casting and might vary depending on unknown circumstances. We have found two distinct, yet similar Exceptions (being thrown while calling Resolve<> for the second time that throws our Exception; first attempt is always correct and caught by try/catch):

In both cases, the stack trace completely hides the real Exception we expect to see (it is expected that our codebase throws). Reproduction of the bug is attached in the below sample project: DryIocResolveBug.zip

As a workaround, we have found 2 working solutions:

  1. Do not use RegisterInitializer: service registered using just only Register<> is resolved correctly - our expected Exception is always thrown as expected.
  2. Use registrations with standard DI manner Register<TAbstraction, TImplementation>: as soon as the service is registered and resolved with the usage of an interface, it Resolves correctly, even if it used RegisterInitializer.

Kindly please fix the behavior so that DryIoc rethrows Exceptions being thrown by the registered services while Resolving.

dadhi commented 3 months ago

@MacSz-mjss Thanks for the reporting.

System.ArgumentException: Object of type 'DryIoc.ScopedItemException' cannot be converted to type 'SomeType'.
System.InvalidOperationException : No coercion operator is defined between types 'DryIoc.ScopedItemException' and 'DryIoc.HiddenDisposable'.

You have helped me with your observation, it will simplify fixing.

MacSz-mjss commented 3 months ago

You are welcome :). Thank you for your quick reply.

dadhi commented 3 months ago

@MacSz-mjss Hi,

I have checked the sample project and was able to reproduce the problem. Then I have updated the DryIoc to the latest preview v6-preview-07 and the issue appears to be fixed. Could you check it on your side? The latest preview is very much a stable version, I am planning to release the final version soon.

MacSz-mjss commented 3 months ago

@dadhi Hello We have checked our case with the 6.0.0-preview-07 version and the behavior is now correct 😊

Our expected exceptions are now thrown correctly and there are no signs of any object casting-related errors.

Thank you for your quick fix and response, we truly appreciate it 👍

dadhi commented 3 months ago

:-) fixed