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

API for Code based configuration for DBProviderFactories #16532

Closed
kkurni opened this issue Feb 26, 2016 · 9 comments
Closed

API for Code based configuration for DBProviderFactories #16532

kkurni opened this issue Feb 26, 2016 · 9 comments
Assignees
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-System.Data
Milestone

Comments

@kkurni
Copy link
Contributor

kkurni commented Feb 26, 2016

Problem

DbProviderFactories in .NET Framework provides an API to manage DbProviderFactory which configured in machine.config and load that assembly from GAC via reflection

In Corefx, there is no more GAC and machine.config.

Community are asking to have a standard way to manage DbProviderFactory to write provider agnostic code in libraries.
https://github.com/dotnet/corefx/issues/4571
https://github.com/dotnet/corefx/issues/5782

https://msdn.microsoft.com/en-us/library/ms971499.aspx

Proposal

We will bring back DbProviderFactories in CoreFx.
But instead of register/read the configuration from machine.config, we will provide a code based configuration.

This will allow application writer to hook this with any configuration mechanism.

Contract Changes

We will bring back DbProviderFactories.GetFactory functions in V1 contract which will support .Net 4.6.2.
And add "RegisterFactory" functions in V2 contract to support .Net vNext. (version after 4.6.2)

For portability, we will bring "RegisterFactory" into .Net vNext and should work side by side with file config behavior. e.g code based config will override file based config).

Portable library (such as ORM), can start using GetFactory and target it for .Net 4.6.2.
If this library used in .NET 4.6.2 , GetFactory will return factory which defined in machine/app configs.
Corefx application which used this portable library can register their factory using "RegisterFactory".

Once we release "RegisterFactory" into .Net vNext, The behavior will be work seamless in both frameworks.

namespace System.Data.Common
{
    public static class DbProviderFactories
    {
        // V1 -- Supported by .NET Framework 4.6.2 (the upcoming version)
        public static DbProviderFactory GetFactory(string providerInvariantName);
        public static DbProviderFactory GetFactory(DbConnection connection);

        // V2 -- Supported by .NET Core 1.0 and by .NET Framework vNext (version after 4.6.2)
        public static void RegisterFactory(string providerInvariantName, DbProviderFactory factory);
        public static IEnumerable<string> GetFactoryProviderNames();
    }
}

DbProviderFactories

CoreFx Implementation

public abstract class DbProviderFactories
    {

        internal static readonly Dictionary<string, Func<DbProviderFactory>> _configs = new Dictionary<string, Func<DbProviderFactory>>();

        public static DbProviderFactory GetFactory(string providerInvariantName)
        {
            ADP.CheckArgumentLength(providerInvariantName, nameof(providerInvariantName));

            if (_configs.ContainsKey(providerInvariantName))
            {
                return _configs[providerInvariantName]();
            }

            throw ADP.ConfigProviderNotFound();
        }

        public static DbProviderFactory GetFactory(DbConnection connection)
        {
            ADP.CheckArgumentNull(connection, nameof(connection));
            return connection.ProviderFactory;
        }

        public static void RegisterFactory(string providerInvariantName, DbProviderFactory factory) {
            ADP.CheckArgumentNull(providerInvariantName, nameof(providerInvariantName));
            ADP.CheckArgumentNull(constructorDelegate, nameof(constructorDelegate));

            _configs[providerInvariantName]  = factory;
        }

        public static IEnumerable<string> GetFactoryProviderNames() {
             return _configs.Keys.toArray();
        }
    }

Usage

For CoreFX application, You need to register your provider factory during startup of your application.

public static void Startup()
        {
            //SqlClientFactory is a singleton factory
            DbProviderFactories.Add("System.Data.SqlClient", SqlClientFactory.Instance);

            //You can use other factory which not singleton.
            DbProviderFactories.Add("System.Data.OtherProvider", new OtherProviderFactory());
        }

Progress

I have created initial commit on my branch to inspect what are the changes needed.
kkurni/corefx@68380b3

@kkurni kkurni self-assigned this Feb 26, 2016
@kkurni
Copy link
Contributor Author

kkurni commented Feb 26, 2016

@davidfowl
Copy link
Member

You should allow overriding the factory. Blocking that seems unnecessarily restrictive.

@kkurni
Copy link
Contributor Author

kkurni commented Mar 23, 2016

@davidfowl I assume that your suggestion is about overriding the value of factory registration.

  if (Dictionary.ContainsKey(providerInvariantName))
            {
                throw ADP.ConfigProviderKeyAlreadyExists();
            }

The reason why we don't allow for duplicate is to make the behavior less unpredictable.
e.g If we allow this, any libraries that you reference can just override your provide without any advanced agreement or notification. This will be hard to debug and find out which libraries override the value.

But the application can decide in advanced which provider they want to use and create their own policy to select which provider they want to use if there is a conflict. e.g File based config override mechanism based on folder hierarchy.

@davidfowl
Copy link
Member

The reason why we don't allow for duplicate is to make the behavior less unpredictable.
e.g If we allow this, any libraries that you reference can just override your provide without any advanced agreement or notification. This will be hard to debug and find out which libraries override the value.

Making it impossible though seems a bit restrictive. There's a thin line between trying to protect users from the scenarios "you can think will be confusing" and scenarios "you didn't anticipate would be useful". Blocking it because you can only think of a case that would confusing customers is bad.

Another think I'd like from this API is the ability to new up a DbProviderFactoriesConfiguration. The static should be the default but if you want to create a totally separate hive then you should be able to create one, and pass it into DbProviderFactory.GetFactory. It'll make it easier to unit test and isolate (multi-tenant scenarios).

@kkurni kkurni assigned saurabh500 and unassigned kkurni Apr 22, 2016
@gafemoyano
Copy link

Does this mean that there ris no way to register a custom provider, say "Oracle.ManagedDataAccess.Client" on .NET 4.6.2?

@grahamehorner
Copy link

@gafemoyano Oracle.ManagedDataAccess.Client is not a .NET core compatible provider it is a full framework provider

@karelz
Copy link
Member

karelz commented Nov 10, 2016

@YoungGah plans to port over the old one (tracked by #15732), not create a new one. Sorry for the confusion and thanks for your effort and help here!

@karelz karelz closed this as completed Nov 10, 2016
@KevalPatel
Copy link

What is ADP here ?

@karelz
Copy link
Member

karelz commented May 1, 2017

@KevalPatel please don't comment on old-closed issues. No one is likely monitoring them.

I don't understand your question in this context, so can't answer.

@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 2.0.0 milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Jan 2, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-System.Data
Projects
None yet
Development

No branches or pull requests

8 participants