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

Infrastructure: Allow only one database provider per service provider #7457

Closed
ajcvickers opened this issue Jan 23, 2017 · 0 comments
Closed
Labels
area-perf breaking-change closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. providers-beware type-enhancement
Milestone

Comments

@ajcvickers
Copy link
Contributor

In EF Core 1.0 there can be multiple database providers registered in the same service provider (D.I. container). However, only one can be used with any given DbContext instance. This works by defining a set of provider services and having service resolution go through a scoped indirection based on the current context so that the correct service is returned for the provider currently being used.

This was important in pre-release versions of EF where there was no real distinction between the external application service provider and the internal service provider used by EF. This meant that there was no way to use ASP.NET Core in the normal way if the application made use of two different database providers. With the switch to EF managing its own service provider be default, it now means that using ASP.NET Core in the normal way will result in two internal service providers being created--one for each database provider.

Therefore, now that we have made the internal service provider the default experience, we can switch to a simpler model where only one database provider is allowed in the service provider. This means that:

  • There is no indirection mechanism for provider services, which means that:
    • Some services that had to be scoped because they varied per provider can now be singleton
    • A provider can replace any service, not just a "provider service"
    • There is no interface/base class for providers, so providers must rely more on documentation to know which services to implement
    • There is no mechanism to inject services into providers in patch releases, so we will need a different mechanism for that
  • Some caching will be duplicated for applications that do use multiple providers
@ajcvickers ajcvickers self-assigned this Jan 23, 2017
@ajcvickers ajcvickers added this to the 2.0.0 milestone Jan 23, 2017
ajcvickers added a commit that referenced this issue Jan 24, 2017
Issue #7457

Note that the way AddEntityFramework works has changed. Previously, the provider indirection mechanism ensured that any service overridden by a provider would be honored. Since this is gone, we use the following approach:
- TryAdd all provider services
- TryAdd all relational services (any services already registered by the provider are not overwritten)
- TryAdd all core services (any services registered by first two steps are not overwritten)
- Any services explicitly added by application will remain regardless

This means that an application should never call AddEntityFramework directly, since if this is done before the provider services are added then things will break. Therefore this method is renamed and no-longer an extension method. (Note that applications should not have been calling it anyway, but doing so was previously harmless.)

Also note that all services registered are now interfaces. This should have been the case before except for provider-specific implementations that were still resolved through their interfaces, but some concrete services had crept in.

Work still to do:
- Revisit the scopes of services
- Consider combining core convention set builder and model-specific builder into one
- Find a new solution for InjectAdditionalServices, since there is now no longer a hook for this
- Look at ResultOperatorHandler, since it differs from all other services in how it is used
ajcvickers added a commit that referenced this issue Jan 26, 2017
Issue #7457

Note that the way AddEntityFramework works has changed. Previously, the provider indirection mechanism ensured that any service overridden by a provider would be honored. Since this is gone, we use the following approach:
- TryAdd all provider services
- TryAdd all relational services (any services already registered by the provider are not overwritten)
- TryAdd all core services (any services registered by first two steps are not overwritten)
- Any services explicitly added by application will remain regardless

This means that an application should never call AddEntityFramework directly, since if this is done before the provider services are added then things will break. Therefore this method is renamed and no-longer an extension method. (Note that applications should not have been calling it anyway, but doing so was previously harmless.)

Also note that all services registered are now interfaces. This should have been the case before except for provider-specific implementations that were still resolved through their interfaces, but some concrete services had crept in.

Work still to do:
- Revisit the scopes of services
- Consider combining core convention set builder and model-specific builder into one
- Find a new solution for InjectAdditionalServices, since there is now no longer a hook for this
- Look at ResultOperatorHandler, since it differs from all other services in how it is used
@ajcvickers ajcvickers added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jan 26, 2017
ajcvickers added a commit that referenced this issue Feb 28, 2017
Issue #7457

Main points:
- Providers don't need to know scope to register--EF now knows the appropriate scope for each service. (Providers can override this, but should only do so very carefully.)
- Providers don't need to know whether to register service as multiple/enumerable service.
- Better error checking for bad registrations
- Special internal code for registering service dependencies types with check for bad registration
- Service re-writing for patch releases is internal
ajcvickers added a commit that referenced this issue Mar 1, 2017
Issue #7457

Main points:
- Providers don't need to know scope to register--EF now knows the appropriate scope for each service. (Providers can override this, but should only do so very carefully.)
- Providers don't need to know whether to register service as multiple/enumerable service.
- Better error checking for bad registrations
- Special internal code for registering service dependencies types with check for bad registration
- Service re-writing for patch releases is internal
ajcvickers added a commit that referenced this issue Mar 3, 2017
Issue #7457

Main points:
- Providers don't need to know scope to register--EF now knows the appropriate scope for each service. (Providers can override this, but should only do so very carefully.)
- Providers don't need to know whether to register service as multiple/enumerable service.
- Better error checking for bad registrations
- Special internal code for registering service dependencies types with check for bad registration
- Service re-writing for patch releases is internal
@ajcvickers ajcvickers changed the title Allow only one database provider per service provider Infrastructure: Allow only one database provider per service provider May 9, 2017
@ajcvickers ajcvickers modified the milestones: 2.0.0-preview1, 2.0.0 Oct 15, 2022
@ajcvickers ajcvickers removed their assignment Sep 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-perf breaking-change closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. providers-beware type-enhancement
Projects
None yet
Development

No branches or pull requests

2 participants