DbProviderFactories.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. //------------------------------------------------------------------------------
  2. // <copyright file="DbProviderFactories.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">[....]</owner>
  6. // <owner current="true" primary="false">[....]</owner>
  7. //------------------------------------------------------------------------------
  8. namespace System.Data.Common {
  9. using System;
  10. using System.Collections;
  11. using System.Configuration;
  12. using System.Data;
  13. using System.Diagnostics;
  14. using System.Globalization;
  15. using System.Xml;
  16. public static class DbProviderFactories {
  17. private const string AssemblyQualifiedName = "AssemblyQualifiedName";
  18. private const string Instance = "Instance";
  19. private const string InvariantName = "InvariantName";
  20. private const string Name = "Name";
  21. private const string Description = "Description";
  22. private static ConnectionState _initState; // closed, connecting, open
  23. private static DataTable _providerTable;
  24. private static object _lockobj = new object();
  25. static public DbProviderFactory GetFactory(string providerInvariantName) {
  26. ADP.CheckArgumentLength(providerInvariantName, "providerInvariantName");
  27. // NOTES: Include the Framework Providers and any other Providers listed in the config file.
  28. DataTable providerTable = GetProviderTable();
  29. if (null != providerTable) {
  30. // we don't need to copy the DataTable because its used in a controlled fashion
  31. // also we don't need to create a blank datatable because we know the information won't exist
  32. #if DEBUG
  33. DataColumn[] pkey = providerTable.PrimaryKey;
  34. Debug.Assert(null != providerTable.Columns[InvariantName], "missing primary key column");
  35. Debug.Assert((null != pkey) && (1 == pkey.Length) && (InvariantName == pkey[0].ColumnName), "bad primary key");
  36. #endif
  37. DataRow providerRow = providerTable.Rows.Find(providerInvariantName);
  38. if (null != providerRow) {
  39. return DbProviderFactories.GetFactory(providerRow);
  40. }
  41. }
  42. throw ADP.ConfigProviderNotFound();
  43. }
  44. static public DbProviderFactory GetFactory(DataRow providerRow) {
  45. ADP.CheckArgumentNull(providerRow, "providerRow");
  46. // fail with ConfigProviderMissing rather than ColumnNotInTheTable exception
  47. DataColumn column = providerRow.Table.Columns[AssemblyQualifiedName];
  48. if (null != column) {
  49. // column value may not be a string
  50. string assemblyQualifiedName = providerRow[column] as string;
  51. if (!ADP.IsEmpty(assemblyQualifiedName)) {
  52. // FXCop is concerned about the following line call to Get Type,
  53. // If this code is deemed safe during our security review we should add this warning to our exclusion list.
  54. // FXCop Message, pertaining to the call to GetType.
  55. //
  56. // Secure late-binding methods,System.Data.dll!System.Data.Common.DbProviderFactories.GetFactory(System.Data.DataRow):System.Data.Common.DbProviderFactory,
  57. Type providerType = Type.GetType(assemblyQualifiedName);
  58. if (null != providerType) {
  59. System.Reflection.FieldInfo providerInstance = providerType.GetField(Instance, System.Reflection.BindingFlags.DeclaredOnly|System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Static);
  60. if (null != providerInstance) {
  61. Debug.Assert(providerInstance.IsPublic, "field not public");
  62. Debug.Assert(providerInstance.IsStatic, "field not static");
  63. if (providerInstance.FieldType.IsSubclassOf(typeof(DbProviderFactory))) {
  64. object factory = providerInstance.GetValue(null);
  65. if (null != factory) {
  66. return (DbProviderFactory)factory;
  67. }
  68. // else throw ConfigProviderInvalid
  69. }
  70. // else throw ConfigProviderInvalid
  71. }
  72. throw ADP.ConfigProviderInvalid();
  73. }
  74. throw ADP.ConfigProviderNotInstalled();
  75. }
  76. // else throw ConfigProviderMissing
  77. }
  78. throw ADP.ConfigProviderMissing();
  79. }
  80. static public DbProviderFactory GetFactory(DbConnection connection) {
  81. ADP.CheckArgumentNull(connection, "connection");
  82. return connection.ProviderFactory;
  83. }
  84. static public DataTable GetFactoryClasses() { // V1.2.3300
  85. // NOTES: Include the Framework Providers and any other Providers listed in the config file.
  86. DataTable dataTable = GetProviderTable();
  87. if (null != dataTable) {
  88. dataTable = dataTable.Copy();
  89. }
  90. else {
  91. dataTable = DbProviderFactoriesConfigurationHandler.CreateProviderDataTable();
  92. }
  93. return dataTable;
  94. }
  95. // VSTFDevDiv # 624213: System.Data.Common.DbProviderFactories.GetFactoryClasses() still gets OracleClient provider in ClientSku environment.
  96. static private DataTable IncludeFrameworkFactoryClasses(DataTable configDataTable)
  97. {
  98. DataTable dataTable = DbProviderFactoriesConfigurationHandler.CreateProviderDataTable();
  99. // NOTES: Adding the following Framework DbProviderFactories
  100. // <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%"/>
  101. // <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%"/>
  102. // <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%"/>
  103. // <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%"/>
  104. Type sysDataType = typeof(System.Data.SqlClient.SqlClientFactory);
  105. string asmQualName = sysDataType.AssemblyQualifiedName.ToString().Replace(DbProviderFactoriesConfigurationHandler.sqlclientPartialAssemblyQualifiedName, DbProviderFactoriesConfigurationHandler.oracleclientPartialAssemblyQualifiedName);
  106. DbProviderFactoryConfigSection[] dbFactoriesConfigSection = new DbProviderFactoryConfigSection[(int)DbProvidersIndex.DbProvidersIndexCount];
  107. dbFactoriesConfigSection[(int)DbProvidersIndex.Odbc] = new DbProviderFactoryConfigSection(typeof(System.Data.Odbc.OdbcFactory), DbProviderFactoriesConfigurationHandler.odbcProviderName, DbProviderFactoriesConfigurationHandler.odbcProviderDescription);
  108. dbFactoriesConfigSection[(int)DbProvidersIndex.OleDb] = new DbProviderFactoryConfigSection(typeof(System.Data.OleDb.OleDbFactory), DbProviderFactoriesConfigurationHandler.oledbProviderName, DbProviderFactoriesConfigurationHandler.oledbProviderDescription);
  109. dbFactoriesConfigSection[(int)DbProvidersIndex.OracleClient] = new DbProviderFactoryConfigSection(DbProviderFactoriesConfigurationHandler.oracleclientProviderName, DbProviderFactoriesConfigurationHandler.oracleclientProviderNamespace, DbProviderFactoriesConfigurationHandler.oracleclientProviderDescription, asmQualName);
  110. dbFactoriesConfigSection[(int)DbProvidersIndex.SqlClient] = new DbProviderFactoryConfigSection(typeof(System.Data.SqlClient.SqlClientFactory), DbProviderFactoriesConfigurationHandler.sqlclientProviderName, DbProviderFactoriesConfigurationHandler.sqlclientProviderDescription);
  111. for (int i = 0; i < dbFactoriesConfigSection.Length; i++)
  112. {
  113. if (dbFactoriesConfigSection[i].IsNull() == false)
  114. {
  115. bool flagIncludeToTable = false;
  116. if (i == ((int)DbProvidersIndex.OracleClient)) // OracleClient Provider: Include only if it installed
  117. {
  118. Type providerType = Type.GetType(dbFactoriesConfigSection[i].AssemblyQualifiedName);
  119. if (providerType != null)
  120. {
  121. // NOTES: Try and create a instance; If it fails, it will throw a System.NullReferenceException exception;
  122. System.Reflection.FieldInfo providerInstance = providerType.GetField(Instance, System.Reflection.BindingFlags.DeclaredOnly | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
  123. if ((null != providerInstance) && (providerInstance.FieldType.IsSubclassOf(typeof(DbProviderFactory))))
  124. {
  125. Debug.Assert(providerInstance.IsPublic, "field not public");
  126. Debug.Assert(providerInstance.IsStatic, "field not static");
  127. object factory = providerInstance.GetValue(null);
  128. if (null != factory)
  129. {
  130. flagIncludeToTable = true;
  131. } // Else ignore and don't add to table
  132. } // Else ignore and don't add to table
  133. }
  134. }
  135. else
  136. {
  137. flagIncludeToTable = true;
  138. }
  139. if (flagIncludeToTable == true)
  140. {
  141. DataRow row = dataTable.NewRow();
  142. row[Name] = dbFactoriesConfigSection[i].Name;
  143. row[InvariantName] = dbFactoriesConfigSection[i].InvariantName;
  144. row[Description] = dbFactoriesConfigSection[i].Description;
  145. row[AssemblyQualifiedName] = dbFactoriesConfigSection[i].AssemblyQualifiedName;
  146. dataTable.Rows.Add(row);
  147. } // Else Ignore and do not include to table;
  148. }
  149. }
  150. // NOTES: Additional step added here to maintain the sequence order of the providers listed.
  151. // The Framework Providers get listed first and is followed the custom providers.
  152. for (int i = 0; (configDataTable != null) && (i < configDataTable.Rows.Count); i++)
  153. {
  154. try
  155. {
  156. bool flagIncludeToTable = false;
  157. // OracleClient Provider: Include only if it installed
  158. if (configDataTable.Rows[i][AssemblyQualifiedName].ToString().ToLowerInvariant().Contains(DbProviderFactoriesConfigurationHandler.oracleclientProviderNamespace.ToString().ToLowerInvariant()))
  159. {
  160. Type providerType = Type.GetType(configDataTable.Rows[i][AssemblyQualifiedName].ToString());
  161. if (providerType != null)
  162. {
  163. // NOTES: Try and create a instance; If it fails, it will throw a System.NullReferenceException exception;
  164. System.Reflection.FieldInfo providerInstance = providerType.GetField(Instance, System.Reflection.BindingFlags.DeclaredOnly | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
  165. if ((null != providerInstance) && (providerInstance.FieldType.IsSubclassOf(typeof(DbProviderFactory))))
  166. {
  167. Debug.Assert(providerInstance.IsPublic, "field not public");
  168. Debug.Assert(providerInstance.IsStatic, "field not static");
  169. object factory = providerInstance.GetValue(null);
  170. if (null != factory)
  171. {
  172. flagIncludeToTable = true;
  173. } // Else ignore and don't add to table
  174. } // Else ignore and don't add to table
  175. }
  176. }
  177. else
  178. {
  179. flagIncludeToTable = true;
  180. }
  181. if(flagIncludeToTable == true)
  182. {
  183. // NOTES: If it already exist in the configTable, it raises a ConstraintException;
  184. dataTable.Rows.Add(configDataTable.Rows[i].ItemArray);
  185. }
  186. }
  187. catch (System.Data.ConstraintException)
  188. {
  189. // NOTES: Ignore item; Already exist in the configTable, hence the ConstraintException; Move to the next item;
  190. }
  191. }
  192. return dataTable;
  193. }
  194. static private DataTable GetProviderTable() {
  195. Initialize();
  196. return _providerTable;
  197. }
  198. static private void Initialize() {
  199. if (ConnectionState.Open != _initState) {
  200. lock (_lockobj) {
  201. switch(_initState) {
  202. case ConnectionState.Closed:
  203. _initState = ConnectionState.Connecting; // used for preventing recursion
  204. try {
  205. DataSet configTable = PrivilegedConfigurationManager.GetSection(DbProviderFactoriesConfigurationHandler.sectionName) as DataSet;
  206. _providerTable = (null != configTable) ? IncludeFrameworkFactoryClasses(configTable.Tables[DbProviderFactoriesConfigurationHandler.providerGroup]) : IncludeFrameworkFactoryClasses(null);
  207. }
  208. finally {
  209. _initState = ConnectionState.Open;
  210. }
  211. break;
  212. case ConnectionState.Connecting:
  213. case ConnectionState.Open:
  214. break;
  215. default:
  216. Debug.Assert(false, "unexpected state");
  217. break;
  218. }
  219. }
  220. }
  221. }
  222. }
  223. }