VContainer
VContainer copied to clipboard
"ValueFactory attempted to access the Value property of this instance" When resolving inside an async method.
I got an exception while calling a resolve of an interface inside a UniTask async method.
Resolve called:
Container.Resolve<IEnumerable<IRequestInstanceOnContainerBuilt>>();
The class that implements the interface:
[UsedImplicitly]
public class StatsApplier : IRequestInstanceOnContainerBuilt, IStatsChangedListener
Class registration:
public override void Configure(IContainerBuilder builder)
{
builder.Register<StatsApplier>(Lifetime.Singleton)
.As<IRequestInstanceOnContainerBuilt>()
.As<IStatsChangedListener>();
Exception:
InvalidOperationException: ValueFactory attempted to access the Value property of this instance.
System.Lazy`1[T].ViaFactory (System.Threading.LazyThreadSafetyMode mode) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
System.Lazy`1[T].ExecutionAndPublication (System.LazyHelper executionAndPublication, System.Boolean useDefaultConstructor) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
System.Lazy`1[T].CreateValue () (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
System.Lazy`1[T].get_Value () (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
VContainer.ScopedContainer.CreateTrackedInstance (VContainer.Registration registration) (at Library/PackageCache/jp.hadashikick.vcontainer@80086eec36/Runtime/Container.cs:138)
VContainer.ScopedContainer.ResolveCore (VContainer.Registration registration) (at Library/PackageCache/jp.hadashikick.vcontainer@80086eec36/Runtime/Container.cs:122)
VContainer.Diagnostics.DiagnosticsCollector.TraceResolve (VContainer.Registration registration, System.Func`2[T,TResult] resolving) (at Library/PackageCache/jp.hadashikick.vcontainer@80086eec36/Runtime/Diagnostics/DiagnosticsCollector.cs:72)
VContainer.ScopedContainer.Resolve (VContainer.Registration registration) (at Library/PackageCache/jp.hadashikick.vcontainer@80086eec36/Runtime/Container.cs:79)
VContainer.Internal.CollectionInstanceProvider.SpawnInstance (VContainer.IObjectResolver resolver) (at Library/PackageCache/jp.hadashikick.vcontainer@80086eec36/Runtime/Internal/InstanceProviders/CollectionInstanceProvider.cs:69)
VContainer.Registration.SpawnInstance (VContainer.IObjectResolver resolver) (at Library/PackageCache/jp.hadashikick.vcontainer@80086eec36/Runtime/Registration.cs:33)
This happened on a child container.
The issue happens because the lazy was created with a security feature for threads:
After inspecting what was happening better, it seems it is a circular dependency issue. I have this interface: IRequestInstanceOnContainerBuilt It allows me to flag objects as objects that I want an instance when the container is created. I have a top level container and a scoped child container. Both have IRequestInstanceOnContainerBuilt concrete instances. The top component creates the instances of the classes that implement this interface by calling Container.Resolve<IEnumerable<IRequestInstanceOnContainerBuilt>>(); This causes the container to resolve all concrete classes that have that. Then the child container is created and calls the same resolve. This causes this exception. I still don't get what becomes a recursive call, but it does, as per the value factory comment on the C# source code for the lazy object under ExecutionAndPublication.
Found the circular dependency: StatApplier (which is a IStatsChangedListener
) asks for a IStatsProvider
which is a ModificationStatsProvider. Then ModificationStatsProvider
asks for a list of IEnumerable<IStatModificationsProvider>
. The only IStatModificationsProvider
existing yet is the ArtifactInventory
, which to be created asks for a IEnumerable<IStatsChangedListener> statsChangedListeners
, which will ask for a StatApplier inside the stat applier creation.
The circular dependency problem need more clear exception message.