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
IServiceProvider resolve differences #755
Comments
We saw something similar with #695. I'm not sure if there's anything we can do about it, but it's worth a second look. |
A simple solution would be to have the I think a better pattern would be to create an extension method for
|
Before we make a decision, let me ask the aspnet team if they have a prescribed/required order for enumerables. I feel like either way, someone's going to feel like there's a breaking difference - existing Autofac users porting to aspnet core will wonder why things are backwards from what they're used to; aspnet core users will wonder why the default service provider has different behavior than the Autofac backing implementation. If there's a specific aspnet team recommendation that would influence the solution. |
Looks like there's already an issue to get some feedback on matters like this from the team. I chimed in and referenced this issue; you can follow along over there if you like. Once we get input (or some indication that they abstain from providing input) we can decide how best to proceed. |
We're looking into the things we currently rely on order for. Will get back to you as soon as possible with some data and recommendations. |
Thanks @davidfowl |
We're going to require container vendors to order services using registration order. We'll be updating the spec tests to make sure that requirement is clearer. |
Thanks, @davidfowl - that helps. We'll see what we can do to update the Autofac implementation accordingly. |
@davidfowl I’m really not sure if we will be able to guarantee the order of resolved services due to the way that registrations assigned to the same service type are handled. When a second registration for the same service type is made, the order that implementations are kept in depends on whether or not the user wants that registration to become the default when a single instance is resolved (it gets moved to the front of the implementation list when overriding an existing registration). We also can’t control the order of registrations dynamically created by users through registration sources. This is less common but something that will impact order nonetheless. I have personally never relied on the container providing services in a particular order as it just seems like a weird assumption to make. If I want to ensure ordering I make it an explicit part of the service interface, implement the IComparable interface, or using I worry more requests like this will add fuel to the fire for those arguing against the “conforming container” interface you are forcing container vendors to adhere to. The leaky nature of the abstraction has never sat particularly well with me, and despite the fact that we’ve been lucky up to this point, I suspected some aspect of the specification we didn’t conform to would crop up eventually. As you demand more conformance from the containers, the number of containers able to comply will keep shrinking. If we do manage to work around this issue we are going to have to make some significant changes and break the API in order to conform. I'm willing to try as we want to come along on the journey, but this sort of thing does make me question the approach. |
That's all true. Not to pile on, but looking closer at what it will take... it will be pretty painful. Probably not impossible but definitely not a five-minute job. (We take PRs! |
All those |
It's not just options, various other services depend on order (like
I totally understand this and we debated it for a few days and came to this conclusion. We're also beefing up our spec to make sure that we can know if containers can support the ASP.NET contract or not. We haven't been good enough at documenting all of the things we rely on though the spec tests gets pretty close.
Can you guys explain why it's a breaking change? I don't understand that one. Are you saying that there's no way to have We also discussed a few other options:
|
I believe that the list of entities can be considered orderly if the entity has a property that allows you to make ordering. The order of registration of service is an ordering property of a service in the services collection. "Enumerable" is not "Orderable" and hides valuable property. I seen right decisions in either using an ordered collection or specifying the property clearly. Using only Enumerable for ordering can be an expensive architectural mistake. |
My workaround while issue discussed in flow listed below:
https://msdn.microsoft.com/en-us/library/bb358497(v=vs.100).aspx |
I don't recommend reversing the service collection as a workaround. If you reverse the services on That's why this is such a tricky problem, especially for Autofac. The order we return the |
I understand that. DI in my App divided into two flow: dotnet and my own. My own DI use Autofac, dotnet uses internal. Inversion (and merge) occur at an end of this two separate process in ConfigureServices in last lines. I understand whole problem as i posted before and awaits Autofac update. In my current situation and in my current app I can afford this crutch for several weeks with reason to not fallback to "facatory" DI. My tests show no problem after this move and i still subscribed to this issue. It is better what sit and wait without work because update to dotnet rc2 breaks my app at this issue. |
That's fair. I didn't know if you were aware; and I definitely didn't want someone encountering the same issue to "skim" the comments here and think that was something they could do without side effect. |
What happened to |
Basically the way it works in Autofac is:
Standard disclaimers apply - I'm going from memory rather than diving into the code; there's more to it than that; registration sources play in differently than standard component registrations; etc. |
As @davidfowl mentioned:
This change has been merged to the DI spec tests for 1.0.0. There are currently no plans to update ASP.NET not to rely on order. aspnet/DependencyInjection#416 |
@tillig So if I'm understanding correctly, the primary issue with the ordering requirement is how that interacts with our other requirement that the last service in the IServiceCollection replaces previous services when resolved individually. Basically this would require significant changes to Autofac (possibly requiring a new way of registering services specifically for ASP.NET) to have the last service resolved in an If we remove the One thing to consider if we do this is how customers could replace existing services and add to |
Last service in currently wins. We pass all the current tests in the spec collection (
The breaking/challenging bit will be that last point - trying to return the The challenge is slightly compounded by Autofac's ability to support the concept of a "registration source" - which is, basically, a class that can lazily produce registrations, like a dynamic service registration factory. When the container is asked, "Do you have a registration for Anyway, that's the challenge we've got to figure out - if there's a (new) requirement to return
Not five minutes' worth of work, to be sure. Not technically insurmountable, but definitely not something we were considering diving into near-term. |
Posted a comment on the DI repo about the issues we are having conforming to the ordering requirement. |
The ordering behaviour is described in these unit tests: From @halter73 in #768 (comment):
Services for explicit registrations will always be returned in added order. Registrations from registration sources will appear at the end of the list. |
I noticed a discrepancy between using the built-in
IServiceProvider
implementation for ASP.NET Core (RC2) and the autofac implementation usingbuilder.Populate(services)
.Say I have a collection of service descriptions which contain multiple entries for
IStartupFilter
(which by default you will if you use IIS integration). The order of these is in theIServiceCollection
is:StartupA
,StartupB
.Using the default
IServiceProvider
implementation, these are resolved in the same order.Using
builder.Populate(services)
registers all of the services in the collection into theBuilderContainer
in the same order. This is important so that later registrations hide earlier ones when resolving a single service. However when resolving all services it inverts the list. ResolvingIEnumerable<IStartupFilter>
now returnsStartupB
,StartupA
.Since the order of services matters for
IStartupFilter
, the middleware registered by these filters are running out of order. I can foresee this causing problems sinceStartupA
isAutoRequestServicesStartupFilter
which registers the middleware that initializes the per-request scope.The text was updated successfully, but these errors were encountered: