dongfo / autofac

Automatically exported from code.google.com/p/autofac
0 stars 0 forks source link

Importing the same type twice in constructor #348

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?
1.Register a class (A) that inject a MEF exported class (B) twice in 
constructor.
2.Make sure that the MEF exported class (B) import at least one other class (C) 
in constructor. It can be Autofac or MEF exported. Doesn't seem to matter.
3.Try resolve class A.

What is the expected output?
The type should be resolved successfully.

What do you see instead?
I get an exception along the lines of:
{"GetExportedValue cannot be called before prerequisite import 
'AutofacMef.MefClass..ctor (Parameter=\"dependency\", 
ContractName=\"AutofacMef.StandardDependency\")' has been set."}

What version of Autofac are you using? On what version of .NET/Silverlight?
Autofac(.Mef) 2.5.2.830
.NET 4

Please provide any additional information below.
I've attached a solution which shows the error.

Original issue reported on code.google.com by kristof...@kristofferjansson.com on 10 Nov 2011 at 6:54

Attachments:

GoogleCodeExporter commented 8 years ago
Thank you for the report and repro, I'll try to take a look at this ASAP.

Original comment by nicholas...@gmail.com on 23 Jan 2012 at 5:19

GoogleCodeExporter commented 8 years ago

Original comment by travis.illig on 21 Sep 2012 at 4:33

GoogleCodeExporter commented 8 years ago
Verified this is still an issue in the 3.0 code. Doing the same thing in just 
Autofac works; it's definitely something in the MEF integration code.

Original comment by travis.illig on 15 Jul 2013 at 4:54

GoogleCodeExporter commented 8 years ago
The stack trace for the resolution exception:
   at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Resolving\ResolveOperation.cs:line 89
   at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Lifetime\LifetimeScope.cs:line 230
   at Autofac.Core.Container.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Container.cs:line 181
   at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\ResolutionExtensions.cs:line 786
   at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\ResolutionExtensions.cs:line 396
   at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\ResolutionExtensions.cs:line 244
   at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\ResolutionExtensions.cs:line 197
   at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\ResolutionExtensions.cs:line 181
   at Autofac.Tests.Integration.Mef.SimpleRegistrationTests.DuplicateConstructorDependency() in c:\dev\opensource\autofac\trunk\Core\Tests\Autofac.Tests.Integration.Mef\SimpleRegistrationTests.cs:line 104

The inner exception stack trace actually points to where the MEF failure is 
occurring:

   at System.ComponentModel.Composition.ReflectionModel.ReflectionComposablePart.EnsureGettable()
   at System.ComponentModel.Composition.ReflectionModel.ReflectionComposablePart.GetExportedValue(ExportDefinition definition)
   at Autofac.Integration.Mef.RegistrationExtensions.<>c__DisplayClass1c.<>c__DisplayClass1e.<RegisterComposablePartDefinition>b__15() in c:\dev\opensource\autofac\trunk\Core\Source\Autofac.Integration.Mef\RegistrationExtensions.cs:line 279
   at System.ComponentModel.Composition.Primitives.Export.GetExportedValueCore()
   at System.ComponentModel.Composition.Primitives.Export.get_Value()
   at Autofac.Integration.Mef.RegistrationExtensions.<>c__DisplayClass1c.<RegisterComposablePartDefinition>b__16(IComponentContext c) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac.Integration.Mef\RegistrationExtensions.cs:line 289
   at Autofac.RegistrationExtensions.<>c__DisplayClass10`1.<Register>b__f(IComponentContext c, IEnumerable`1 p) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\RegistrationExtensions.cs:line 231
   at Autofac.Builder.RegistrationBuilder.<>c__DisplayClass1`1.<ForDelegate>b__0(IComponentContext c, IEnumerable`1 p) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Builder\RegistrationBuilder.cs:line 36
   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Activators\Delegate\DelegateActivator.cs:line 68
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Resolving\InstanceLookup.cs:line 79
   at Autofac.Core.Resolving.InstanceLookup.Execute() in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Resolving\InstanceLookup.cs:line 62
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Resolving\ResolveOperation.cs:line 119
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Resolving\InstanceLookup.cs:line 119
   at Autofac.Core.Activators.Reflection.AutowiringParameter.<>c__DisplayClass2.<CanSupplyValue>b__0() in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Activators\Reflection\AutowiringParameter.cs:line 62
   at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate() in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Activators\Reflection\ConstructorParameterBinding.cs:line 114
   at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Activators\Reflection\ReflectionActivator.cs:line 128
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Resolving\InstanceLookup.cs:line 79
   at Autofac.Core.Resolving.InstanceLookup.Execute() in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Resolving\InstanceLookup.cs:line 62
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Resolving\ResolveOperation.cs:line 119
   at Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Resolving\ResolveOperation.cs:line 67
   at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Resolving\ResolveOperation.cs:line 79

Original comment by travis.illig on 15 Jul 2013 at 5:52

GoogleCodeExporter commented 8 years ago
OK, I think I figured this out, but I'll need another set of eyes on it once I 
push the fix to make sure I didn't fix it in a way that will cause more issues.

The problem lies in the way exports and imports need to be set on things 
getting resolved [indirectly] through MEF.

A type registration gets converted to a 'ComposablePart' in a catalog. When you 
want an object based on a ComposablePart, you resolve the ComposablePart and 
then get its value. Dependencies are in the form of 'Exports' that get 
'Imported' by the ComposablePart. Autofac basically has a lot of lambdas 
registered to automatically do Autofac resolution and populate the set of 
required import items on a ComposablePart so when you ask the part for its 
value, MEF wires things up and it all works.

The problem up being that if you ask for the same ComposablePart twice, the 
FIRST time you ask for it all the exports get wired up properly and it works; 
the SECOND time, it somehow skips the wireup of the exports and everything 
fails.

That was happening through an OnActivating event, but OnActivating didn't seem 
to want to fire for the particular unique ComposablePart more than once per 
resolution. Which makes sense, as technically a single instance (during the 
resolution process) is only getting activated the one time. Unfortunately, 
we're actually returning different ComposablePart instances each time - they 
just happen to boil down to the same internal dependency instance.

SOOOOO I fixed it by setting the required imports as part of the actual 
activation lambda when exports get queried. That way it'll always happen.

What I'm afraid of is the possibility that during an individual resolution 
operation something may inadvertently get double-activated or something like 
that. All the unit tests pass, things seem to just work, but... it'd just be 
nice to see if someone else can look at it and make sure I didn't do something 
dumb.

I'll push the fix shortly.

Original comment by travis.illig on 17 Jul 2013 at 3:53

GoogleCodeExporter commented 8 years ago
This issue was closed by revision b1084276c9e8.

Original comment by travis.illig on 17 Jul 2013 at 3:57

GoogleCodeExporter commented 8 years ago
OK, pushed. Includes an update to the version info for Autofac.Integration.Mef 
so it can be released as needed.

Original comment by travis.illig on 17 Jul 2013 at 3:57