| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- //------------------------------------------------------------------------------
- // <copyright file="DbProviderFactories.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- // <owner current="true" primary="true">Microsoft</owner>
- // <owner current="true" primary="false">Microsoft</owner>
- //------------------------------------------------------------------------------
- namespace System.Data.Common {
- using System;
- using System.Collections;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Configuration;
- using System.Data;
- using System.Diagnostics;
- using System.Globalization;
- using System.Xml;
- using System.Linq;
- using System.Reflection;
- public static class DbProviderFactories {
- private const string AssemblyQualifiedName = "AssemblyQualifiedName";
- private const string Instance = "Instance";
- private const string InvariantName = "InvariantName";
- private const string Name = "Name";
- private const string Description = "Description";
- private const string InstanceFieldName = "Instance";
- private static ConcurrentDictionary<string, ProviderRegistration> _registeredFactories = new ConcurrentDictionary<string, ProviderRegistration>();
- private static ConnectionState _initState; // closed, connecting, open
- private static DataTable _providerTable;
- private static object _lockobj = new object();
- static public DbProviderFactory GetFactory(string providerInvariantName) => GetFactory(providerInvariantName, true);
- static public DbProviderFactory GetFactory(string providerInvariantName, bool throwOnError) {
- if (throwOnError)
- ADP.CheckArgumentLength(providerInvariantName, "providerInvariantName");
- // NOTES: Include the Framework Providers and any other Providers listed in the config file.
- DataTable providerTable = GetProviderTable();
- if (null != providerTable) {
- // we don't need to copy the DataTable because its used in a controlled fashion
- // also we don't need to create a blank datatable because we know the information won't exist
- #if DEBUG
- DataColumn[] pkey = providerTable.PrimaryKey;
- Debug.Assert(null != providerTable.Columns[InvariantName], "missing primary key column");
- Debug.Assert((null != pkey) && (1 == pkey.Length) && (InvariantName == pkey[0].ColumnName), "bad primary key");
- #endif
- DataRow providerRow = providerTable.Rows.Find(providerInvariantName);
- if (null != providerRow) {
- return DbProviderFactories.GetFactory(providerRow);
- }
- }
- if (throwOnError)
- throw ADP.ConfigProviderNotFound();
- return null;
- }
- static public DbProviderFactory GetFactory(DataRow providerRow) {
- ADP.CheckArgumentNull(providerRow, "providerRow");
-
- // fail with ConfigProviderMissing rather than ColumnNotInTheTable exception
- DataColumn column = providerRow.Table.Columns[AssemblyQualifiedName];
- if (null != column) {
- // column value may not be a string
- string assemblyQualifiedName = providerRow[column] as string;
- if (!ADP.IsEmpty(assemblyQualifiedName)) {
- // FXCop is concerned about the following line call to Get Type,
- // If this code is deemed safe during our security review we should add this warning to our exclusion list.
- // FXCop Message, pertaining to the call to GetType.
- //
- // Secure late-binding methods,System.Data.dll!System.Data.Common.DbProviderFactories.GetFactory(System.Data.DataRow):System.Data.Common.DbProviderFactory,
- Type providerType = Type.GetType(assemblyQualifiedName);
- if (null != providerType) {
- System.Reflection.FieldInfo providerInstance = providerType.GetField(Instance, System.Reflection.BindingFlags.DeclaredOnly|System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Static);
- if (null != providerInstance) {
- Debug.Assert(providerInstance.IsPublic, "field not public");
- Debug.Assert(providerInstance.IsStatic, "field not static");
- if (providerInstance.FieldType.IsSubclassOf(typeof(DbProviderFactory))) {
- object factory = providerInstance.GetValue(null);
- if (null != factory) {
- return (DbProviderFactory)factory;
- }
- // else throw ConfigProviderInvalid
- }
- // else throw ConfigProviderInvalid
- }
- throw ADP.ConfigProviderInvalid();
- }
- throw ADP.ConfigProviderNotInstalled();
- }
- // else throw ConfigProviderMissing
- }
- throw ADP.ConfigProviderMissing();
- }
- static public DbProviderFactory GetFactory(DbConnection connection) {
- ADP.CheckArgumentNull(connection, "connection");
- return connection.ProviderFactory;
- }
-
- static public DataTable GetFactoryClasses() { // V1.2.3300
- // NOTES: Include the Framework Providers and any other Providers listed in the config file.
- DataTable dataTable = GetProviderTable();
- if (null != dataTable) {
- dataTable = dataTable.Copy();
- }
- else {
- dataTable = DbProviderFactoriesConfigurationHandler.CreateProviderDataTable();
- }
- return dataTable;
- }
- // VSTFDevDiv # 624213: System.Data.Common.DbProviderFactories.GetFactoryClasses() still gets OracleClient provider in ClientSku environment.
- static private DataTable IncludeFrameworkFactoryClasses(DataTable configDataTable)
- {
- DataTable dataTable = DbProviderFactoriesConfigurationHandler.CreateProviderDataTable();
- // NOTES: Adding the following Framework DbProviderFactories
- // <add name="Odbc Data Provider" invariant="System.Data.Odbc" description=".Net Framework Data Provider for Odbc" type="System.Data.Odbc.OdbcFactory, System.Data, Version=%ASSEMBLY_VERSION%, Culture=neutral, PublicKeyToken=%ECMA_PUBLICKEY%"/>
- // <add name="OleDb Data Provider" invariant="System.Data.OleDb" description=".Net Framework Data Provider for OleDb" type="System.Data.OleDb.OleDbFactory, System.Data, Version=%ASSEMBLY_VERSION%, Culture=neutral, PublicKeyToken=%ECMA_PUBLICKEY%"/>
- // <add name="OracleClient Data Provider" invariant="System.Data.OracleClient" description=".Net Framework Data Provider for Oracle" type="System.Data.OracleClient.OracleClientFactory, System.Data.OracleClient, Version=%ASSEMBLY_VERSION%, Culture=neutral, PublicKeyToken=%ECMA_PUBLICKEY%"/>
- // <add name="SqlClient Data Provider" invariant="System.Data.SqlClient" description=".Net Framework Data Provider for SqlServer" type="System.Data.SqlClient.SqlClientFactory, System.Data, Version=%ASSEMBLY_VERSION%, Culture=neutral, PublicKeyToken=%ECMA_PUBLICKEY%"/>
- Type sysDataType = typeof(System.Data.SqlClient.SqlClientFactory);
- string asmQualName = sysDataType.AssemblyQualifiedName.ToString().Replace(DbProviderFactoriesConfigurationHandler.sqlclientPartialAssemblyQualifiedName, DbProviderFactoriesConfigurationHandler.oracleclientPartialAssemblyQualifiedName);
- DbProviderFactoryConfigSection[] dbFactoriesConfigSection = new DbProviderFactoryConfigSection[(int)DbProvidersIndex.DbProvidersIndexCount];
- dbFactoriesConfigSection[(int)DbProvidersIndex.Odbc] = new DbProviderFactoryConfigSection(typeof(System.Data.Odbc.OdbcFactory), DbProviderFactoriesConfigurationHandler.odbcProviderName, DbProviderFactoriesConfigurationHandler.odbcProviderDescription);
- dbFactoriesConfigSection[(int)DbProvidersIndex.OleDb] = new DbProviderFactoryConfigSection(typeof(System.Data.OleDb.OleDbFactory), DbProviderFactoriesConfigurationHandler.oledbProviderName, DbProviderFactoriesConfigurationHandler.oledbProviderDescription);
- dbFactoriesConfigSection[(int)DbProvidersIndex.OracleClient] = new DbProviderFactoryConfigSection(DbProviderFactoriesConfigurationHandler.oracleclientProviderName, DbProviderFactoriesConfigurationHandler.oracleclientProviderNamespace, DbProviderFactoriesConfigurationHandler.oracleclientProviderDescription, asmQualName);
- dbFactoriesConfigSection[(int)DbProvidersIndex.SqlClient] = new DbProviderFactoryConfigSection(typeof(System.Data.SqlClient.SqlClientFactory), DbProviderFactoriesConfigurationHandler.sqlclientProviderName, DbProviderFactoriesConfigurationHandler.sqlclientProviderDescription);
- for (int i = 0; i < dbFactoriesConfigSection.Length; i++)
- {
- if (dbFactoriesConfigSection[i].IsNull() == false)
- {
- bool flagIncludeToTable = false;
- if (i == ((int)DbProvidersIndex.OracleClient)) // OracleClient Provider: Include only if it installed
- {
- Type providerType = Type.GetType(dbFactoriesConfigSection[i].AssemblyQualifiedName);
- if (providerType != null)
- {
- // NOTES: Try and create a instance; If it fails, it will throw a System.NullReferenceException exception;
- System.Reflection.FieldInfo providerInstance = providerType.GetField(Instance, System.Reflection.BindingFlags.DeclaredOnly | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
- if ((null != providerInstance) && (providerInstance.FieldType.IsSubclassOf(typeof(DbProviderFactory))))
- {
- Debug.Assert(providerInstance.IsPublic, "field not public");
- Debug.Assert(providerInstance.IsStatic, "field not static");
- object factory = providerInstance.GetValue(null);
- if (null != factory)
- {
- flagIncludeToTable = true;
- } // Else ignore and don't add to table
- } // Else ignore and don't add to table
- }
- }
- else
- {
- flagIncludeToTable = true;
- }
- if (flagIncludeToTable == true)
- {
- DataRow row = dataTable.NewRow();
- row[Name] = dbFactoriesConfigSection[i].Name;
- row[InvariantName] = dbFactoriesConfigSection[i].InvariantName;
- row[Description] = dbFactoriesConfigSection[i].Description;
- row[AssemblyQualifiedName] = dbFactoriesConfigSection[i].AssemblyQualifiedName;
- dataTable.Rows.Add(row);
- } // Else Ignore and do not include to table;
- }
- }
- // NOTES: Additional step added here to maintain the sequence order of the providers listed.
- // The Framework Providers get listed first and is followed the custom providers.
- for (int i = 0; (configDataTable != null) && (i < configDataTable.Rows.Count); i++)
- {
- try
- {
- bool flagIncludeToTable = false;
- // OracleClient Provider: Include only if it installed
- if (configDataTable.Rows[i][AssemblyQualifiedName].ToString().ToLowerInvariant().Contains(DbProviderFactoriesConfigurationHandler.oracleclientProviderNamespace.ToString().ToLowerInvariant()))
- {
- Type providerType = Type.GetType(configDataTable.Rows[i][AssemblyQualifiedName].ToString());
- if (providerType != null)
- {
- // NOTES: Try and create a instance; If it fails, it will throw a System.NullReferenceException exception;
- System.Reflection.FieldInfo providerInstance = providerType.GetField(Instance, System.Reflection.BindingFlags.DeclaredOnly | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
- if ((null != providerInstance) && (providerInstance.FieldType.IsSubclassOf(typeof(DbProviderFactory))))
- {
- Debug.Assert(providerInstance.IsPublic, "field not public");
- Debug.Assert(providerInstance.IsStatic, "field not static");
- object factory = providerInstance.GetValue(null);
- if (null != factory)
- {
- flagIncludeToTable = true;
- } // Else ignore and don't add to table
- } // Else ignore and don't add to table
- }
- }
- else
- {
- flagIncludeToTable = true;
- }
- if(flagIncludeToTable == true)
- {
- // NOTES: If it already exist in the configTable, it raises a ConstraintException;
- dataTable.Rows.Add(configDataTable.Rows[i].ItemArray);
- }
- }
- catch (System.Data.ConstraintException)
- {
- // NOTES: Ignore item; Already exist in the configTable, hence the ConstraintException; Move to the next item;
- }
- }
- return dataTable;
- }
- static private DataTable GetProviderTable() {
- Initialize();
- return _providerTable;
- }
- static private void Initialize() {
- if (ConnectionState.Open != _initState) {
- lock (_lockobj) {
- switch(_initState) {
- case ConnectionState.Closed:
- _initState = ConnectionState.Connecting; // used for preventing recursion
- try {
- DataSet configTable = PrivilegedConfigurationManager.GetSection(DbProviderFactoriesConfigurationHandler.sectionName) as DataSet;
- _providerTable = (null != configTable) ? IncludeFrameworkFactoryClasses(configTable.Tables[DbProviderFactoriesConfigurationHandler.providerGroup]) : IncludeFrameworkFactoryClasses(null);
- }
- finally {
- _initState = ConnectionState.Open;
- }
- break;
- case ConnectionState.Connecting:
- case ConnectionState.Open:
- break;
- default:
- Debug.Assert(false, "unexpected state");
- break;
- }
- }
- }
- }
- #if MONO
- public static bool TryGetFactory(string providerInvariantName, out DbProviderFactory factory)
- {
- factory = GetFactory(providerInvariantName, throwOnError: false);
- return factory != null;
- }
- public static IEnumerable<string> GetProviderInvariantNames()
- {
- return _registeredFactories.Keys.ToList();
- }
- public static void RegisterFactory(string providerInvariantName, string factoryTypeAssemblyQualifiedName)
- {
- ADP.CheckArgumentLength(providerInvariantName, nameof(providerInvariantName));
- ADP.CheckArgumentLength(factoryTypeAssemblyQualifiedName, nameof(factoryTypeAssemblyQualifiedName));
-
- // this method performs a deferred registration: the type name specified is checked when the factory is requested for the first time.
- _registeredFactories[providerInvariantName] = new ProviderRegistration(factoryTypeAssemblyQualifiedName, null);
- }
- private static DbProviderFactory GetFactoryInstance(Type providerFactoryClass)
- {
- ADP.CheckArgumentNull(providerFactoryClass, nameof(providerFactoryClass));
- if (!providerFactoryClass.IsSubclassOf(typeof(DbProviderFactory)))
- {
- throw ADP.Argument(SR.Format(SR.ADP_DbProviderFactories_NotAFactoryType, providerFactoryClass.FullName));
- }
- FieldInfo providerInstance = providerFactoryClass.GetField(InstanceFieldName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static);
- if (null == providerInstance)
- {
- throw ADP.InvalidOperation(SR.ADP_DbProviderFactories_NoInstance);
- }
- if (!providerInstance.FieldType.IsSubclassOf(typeof(DbProviderFactory)))
- {
- throw ADP.InvalidOperation(SR.ADP_DbProviderFactories_NoInstance);
- }
- object factory = providerInstance.GetValue(null);
- if (null == factory)
- {
- throw ADP.InvalidOperation(SR.ADP_DbProviderFactories_NoInstance);
- }
- return (DbProviderFactory)factory;
- }
- public static void RegisterFactory(string providerInvariantName, Type providerFactoryClass)
- {
- RegisterFactory(providerInvariantName, GetFactoryInstance(providerFactoryClass));
- }
- public static void RegisterFactory(string providerInvariantName, DbProviderFactory factory)
- {
- ADP.CheckArgumentLength(providerInvariantName, nameof(providerInvariantName));
- ADP.CheckArgumentNull(factory, nameof(factory));
- _registeredFactories[providerInvariantName] = new ProviderRegistration(factory.GetType().AssemblyQualifiedName, factory);
- }
-
- public static bool UnregisterFactory(string providerInvariantName)
- {
- return !string.IsNullOrWhiteSpace(providerInvariantName) && _registeredFactories.TryRemove(providerInvariantName, out _);
- }
- private struct ProviderRegistration
- {
- internal ProviderRegistration(string factoryTypeAssemblyQualifiedName, DbProviderFactory factoryInstance)
- {
- this.FactoryTypeAssemblyQualifiedName = factoryTypeAssemblyQualifiedName;
- this.FactoryInstance = factoryInstance;
- }
- internal string FactoryTypeAssemblyQualifiedName { get; }
- /// <summary>
- /// The cached instance of the type in <see cref="FactoryTypeAssemblyQualifiedName"/>. If null, this registation is seen as a deferred registration
- /// and <see cref="FactoryTypeAssemblyQualifiedName"/> is checked the first time when this registration is requested through GetFactory().
- /// </summary>
- internal DbProviderFactory FactoryInstance { get; }
- }
- #endif
- }
- }
|