1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
|
//------------------------------------------------------------------------------
// <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
}
}
|