|
//------------------------------------------------------------------------------
// <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.Configuration;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.Xml;
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 static ConnectionState _initState; // closed, connecting, open
private static DataTable _providerTable;
private static object _lockobj = new object();
static public DbProviderFactory GetFactory(string providerInvariantName) {
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);
}
}
throw ADP.ConfigProviderNotFound();
}
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;
}
}
}
}
}
}
|