-
-
Notifications
You must be signed in to change notification settings - Fork 837
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Open generic registered as SingleInstance in child lifetime scope fails to resolve #847
Comments
Just a friendly bump :) What are the chances that someone (with the knowledge to understand the nuances) might look at this? Trying to do a thing with AspNetCore in Azure Service Fabric that relies on the Startup using a child scope rather than a "root" Container (as per the AutofacServiceProviderFactory approach). The fact that a child scope behaves differently from a Container is a little disturbing. Can someone at least give me some confidence that changing lifetime (on non-instance registrations) to InstancePerLifetimeScope is a "good" workaround? Thanks. |
There are two project owners for core Autofac and the 20+ integration packages, neither of whom have Autofac maintenance as their day job. Unfortunately, that means we have to prioritize and this isn't at the top right now. When it is, we'll comment back, but until then, things that can help speed this along:
|
Understood, we all need to pay the bills :) I've been having a poke at it in an attempt to come up with a PR... The disturbing thing is that if the parts are registered in a "root" container (rather than a "child" scope with BeginLifetimeScope) then the Resolve works fine. The odd thing (to me) is that it is the lifestyle of the dependent (ILogger) that determines if the dependency (ILoggerFactory) can be resolved. I'll leave updates here as I find them. |
OK, I think I have a theory... I think the problem is one of semantics/expectations ie Singleton doesn't mean what we (well I) think it means. Let me see if I can explain. Q: What does Singleton mean in the context of a child scope anyway? When you register with SingleInstance the registration is given a RootScopeLifetime. What this seems to mean is that, even though the registration is in some child scope, it is the root (ultimate parent) scope which is used as the activation context for resolving dependencies (see InstanceLookup:55). SingleInstance seems to mean, there will be only one instance in this scope, but any dependencies must be resolvable from the root container. So, of course, our test case above fails. It's trying to find the dependency (ILoggerFactory) in the root container. But it's registered in the child. So it can't resolve it => fail. This scope mismatch seems counter-intuitive to me. But it's all about the nuances, right? :) Could you also comment on the following... Q: If you only have a root container, is there any real functional/behavioral difference between SingleInstance and InstancePerLifetimeScope? Q: if you can resolve a SingleInstance from a child scope. Is it disposed/removed when the scope is disposed? Or is it "held" by the root scope? Q: If you have a child scope, the only difference with using InstancePerLifetimeScope is that dependencies will be resolved from the current scope first then bubble up parents if not found. Q: if my theory on how it behaves is correct, what would be the use case for SingleInstance? Thank you for any time you can spend helping me understand |
The |
Thanks for taking the time to help out @AndyPook
The singleton should be rooted to the child lifetime scope that it was defined in. Using
The registration is always given the
Yes, most definitely. There will only be one
It is held and disposed by the most root lifetime scope that it is defined in. With the fix in place you will see this is working as expected.
Your theory was based on what you were seeing in the code, which was unfortunately incorrect, at least for this particular scenario involving a new child lifetime scope being updated with a singleton registration coming from a registration source. As you can see from my previous comments there is definitely a difference. Don't let this one very specific issue change your view on how things should work. 😃 |
Ahhh, that makes sense. Thanks for the full explanation, very helpful. Q: given the work (the scope restrict register, rescoping etc) does this imply some guidance on perf? ie if you create a scope per request and are registering "a load of stuff" in the child scope. I haven't been able to grok what's happening well enough to gauge what the cost might be... thoughts? I have a "solution" that "fixes" my problem by using Lastly and fully understanding @tillig 's initial point... do you have any theories, hopes about when this change might hit nuget? Thanks again for taking the time |
I ran into the exact same issue, and would have never figured it out until I came across this GitHub issue. Thanks everyone for the detailed record provided here, that was a tremendous help. |
This fix is included in 4.6.1 which has been pushed to NuGet. |
very cool. Thanks for your efforts.
…On 25 July 2017 at 14:00, Alex Meyer-Gleaves ***@***.***> wrote:
This fix is included in 4.6.1 which has been pushed to NuGet.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#847 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAvrq6c68PyqjjMrOWoz4IkZiVGYdpOFks5sReb4gaJpZM4M_YZA>
.
|
Shouldn't Autofac.Extensions.DependencyInjection package also be updated? |
@astef An update to a base package doesn't require all downstream packages be updated. If you want this update, just add a direct reference to Autofac and get the latest. |
Based on the issue autofac/Autofac.Extensions.DependencyInjection#5:
Registering a standard typed service as a singleton in a child lifetime scope correctly allows you to resolve the singleton from within that lifetime scope. However, If you register an open generic in a child lifetime scope as a single instance and it depends on the newly registered singleton it fails:
The
SingleInstance()
registration on the open generic has something to do with it. If you remove it, this works fine:I'm guessing there's something about the way the
OpenGenericRegistrationSource
determines what parameters it can fulfill that doesn't mesh up with the scenario here.The text was updated successfully, but these errors were encountered: