Skip to content
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

ImportMany failure at runtime instead of composition time #132

Open
weltkante opened this issue May 20, 2019 · 4 comments
Open

ImportMany failure at runtime instead of composition time #132

weltkante opened this issue May 20, 2019 · 4 comments

Comments

@weltkante
Copy link

weltkante commented May 20, 2019

Consider the following scenario having ImportMany over mixed scoped/unscoped exports

public interface IMessageHandler { }

[Export(typeof(IMessageHandler))]
public class UniqueMessageHandler : IMessageHandler { }

[Export(typeof(IMessageHandler))]
[Shared]
public class GlobalMessageHandler : IMessageHandler { }

[Export(typeof(IMessageHandler))]
[Shared("somewhere")]
public class ScopedMessageHandler : IMessageHandler { }

[Export]
public class Helper1
{
    [ImportMany]
    public ICollection<Lazy<IMessageHandler>> Handlers { get; set; }
}

[Export]
public class Helper2
{
    [Import]
    public Lazy<Helper1> LazyHelper { get; set; }
}

Observed behavior:

  • in MEF v1 this cannot happen because shared scopes do not exist
  • in MEF v2 (the nuget version)
    • Helper1.Handlers gets populated with all 3 IMessageHandler exports (probably a bug because now application code sees metadata which it should have never seen)
    • fails at runtime when resolving Lazy<IMessageHandler>.Value on the scoped import
  • in MEF v3 (vs-mef, this project)
    • Helper1 fails to resolve at runtime because it realizes one of the 3 IMessageHandlers is scoped, so it doesn't bother to construct a Lazy import around it. (This is good, even though the failure at runtime is kinda late.)
    • Helper2.LazyHelper gets populated with a Helper1 export even though it will fail to resolve at runtime when calling Lazy<Helper1>.Value (This is bad because it delays failure and application code inspecting metadata doesn't know the import is invalid.)

Expected behavior:

  • since Helper1 can never be constructed it should have been pulled from the composition graph and generated a corresponding entry in the CompositionErrors

PS: The original scenario was someone marking an export as scoped in an extension assembly, causing random application failures because the ImportMany was lazily resolved. Was kinda hard to root cause.

@builder-main
Copy link

builder-main commented Feb 28, 2024

I know your issue is a bit old now and not sure which version it corresponds to, but could this be related ? (using .NETFramework\v4.8\System.ComponentModel.Composition.xml)

https://stackoverflow.com/questions/78076711/mef-importmany-does-not-propagate-exceptions-and-silently-fail

@weltkante
Copy link
Author

weltkante commented Feb 28, 2024

The scenario I outlined above is something that could be detected at composition time but isn't, and instead throws at runtime.

The issue you linked, on the contrary, never throws (according to its author) but he would like for it to be notified that an inner composition failed.

Basically its the opposite behavior, so not really related, no. What he would need is some feature that allows reporting exceptions during runtime construction back through the container.

@AArnott
Copy link
Member

AArnott commented Feb 28, 2024

@weltkante: I think I agree with you on expected behavior. Alternatively it might fall out that we omit ScopedMessageHandler from the ImportMany collection and run with the remaining two. There's a design and some rules for composition that will probably dictate which of these directions the fix goes to.

That said, I doubt I'll be working on this right away.

@weltkante
Copy link
Author

weltkante commented Feb 28, 2024

Oh, I was just responding to the above post. The original report was feedback on a weird edge case I was hitting when someone incorrectly annotated his extension export with a sharing boundary. Nothing thats blocking anything, just was hard to diagnose because the composition graph was reported as valid yet at runtime still failed. So any improvement here is just about improving the ability to diagnose error cases from unexpected scope annotations.

I don't really mind which of the two solutions you mentioned will eventually be picked, the "expected behavior" was just extrapolating the (already existing) failure of Helper1 from runtime to composition time. If its more straightforward to do it in a different way thats just as fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants