|
|
|
|
|||||||||||||
Article Index . Late Binding ADO.NET Providers using Reflection
This article looks at how to use Reflection in C# to load and use ADO.NET providers at run time. Background How can objects be late bound in .NET?
A simple class,
using System.Reflection;
public class LateBinder
{
/// <exception cref="System.TypeLoadException">The type couldn't be
/// loaded.</exception>
/// <exception cref="System.Exception">The assembly couldn't be loaded
/// or other errors.</exception>
/// <exception cref="System.ArgumentNullException">fullyQualifiedTypeName
/// is a null reference.</exception>
public static object CreateInstance(string assemblyName,string fullyQualifiedTypeName)
{
Type type = null;
if (assemblyName != null)
{
// this method will also search the GAC and will use the latest
// version if multiple versions are found.
Assembly assembly = Assembly.LoadWithPartialName(assemblyName);
if (assembly != null)
{
type = assembly.GetType(fullyQualifiedTypeName,true,true);
}
else
{
throw new Exception("Failed to load assembly \"" + assemblyName + "\".");
}
}
else
{
type = Type.GetType(fullyQualifiedTypeName,true,true);
}
// invoke the type's constructor to create an instance
object instance = type.InvokeMember("",
BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.Instance,
null,
null,
new object[] { });
return instance;
}
public static object CreateInstance(string fullyQualifiedTypeName)
{
return CreateInstance(null,fullyQualifiedTypeName);
}
}
This class could then be used to create instances on the fly, for example a DataSet. Note that the System.Data assembly name must be specified since the DataSet is defined in the assembly System.Data.dll. This will load the System.Data.dll assembly if it has not yet been loaded.
object o = LateBinder.CreateInstance("System.Data","DataSet");
Console.WriteLine(o.ToString());
Now what?! How can we take advantage of Late Binding? Your current code for obtaining a specific connection inside your DAL may look like this ...
private static IDbConnection GetConnection(DatabaseProviderType providerType)
{
switch (providerType)
{
case DatabaseProviderType.OleDb:
return new OleDbConnection();
break;
case DatabaseProviderType.SqlClient:
return new SqlConnection();
break;
case DatabaseProviderType.OracleClient:
return new OracleConnection();
break;
// TODO: implement future ADO.NET managed providers here
default:
throw new Exception("Unable to determine the appropriate provider type for "
+ providerType);
}
}
public enum DatabaseProviderType {
OleDb,
SqlClient,
OracleClient
}
The above code uses the OleDbConnection, SqlConnection and OracleConnection types directly meaning that your DAL assembly will not compile unless they are referenced and will not load unless these types are present. Therefore all your applications using the DAL assembly will need to have the corresponding .dlls for each ADO.NET managed provider they support whether it is used or not. You will also need to extend your switch statement and enum as new managed providers are released or required by your application, for example: Microsoft Exchange provider, ODBC provider, MySQL provider etc. This is clearly not desirable but how can it be avoided? The answer obviously lies with late binding ... Revised GetConnection method using late binding.
private static IDbConnection GetConnection(string assemblyName,
string providerConnectionTypeName)
{
object o = LateBinder.CreateInstance(assemblyName,providerConnectionTypeName);
if (!(o is IDbConnection))
{
throw new Exception("\"" + providerConnectionTypeName
+ "\" doesn't implement IDbConnection.");
}
return (IDbConnection) o;
}
Voila! Performance
Performance Test Code
class Class1
{
[STAThread]
static void Main(string[] args)
{
string sql = "SELECT * FROM YOUR_TABLE";
// OleDb
string connectionString = "Provider=MSDAORA.1;Data Source=xxx;User Id=xxx;PASSWORD=xxx";
// OracleClient
//string connectionString = "Data Source=xxx;User Id=xxx;PASSWORD=xxx";
{
DateTime start = DateTime.Now;
double rows = 0;
for (int n=0; n < 100; n++)
{
// late - OracleClient
//IDbConnection connection = GetConnection("System.Data.OracleClient",
// "System.Data.OracleClient.OracleConnection");
// early - OracleClient
//IDbConnection connection = GetConnection(DatabaseProviderType.OracleClient);
// late - OleDb
//IDbConnection connection = GetConnection("System.Data",
// "System.Data.OleDb.OleDbConnection");
// early - OleDb
IDbConnection connection = GetConnection(DatabaseProviderType.OleDb);
connection.ConnectionString = connectionString;
using (connection)
{
connection.Open();
IDbCommand command = connection.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = sql;
IDataReader reader = command.ExecuteReader();
while (reader.Read())
{
rows++;
}
}
}
DateTime end = DateTime.Now;
Console.WriteLine("Rows: " + rows + " Millis:"
+ end.Subtract(start).Ticks/TimeSpan.TicksPerMillisecond);
}
// wait for input
Console.ReadLine();
}
private static IDbConnection GetConnection(DatabaseProviderType providerType)
{
switch (providerType)
{
case DatabaseProviderType.OleDb:
return new OleDbConnection();
break;
case DatabaseProviderType.SqlClient:
return new SqlConnection();
break;
case DatabaseProviderType.OracleClient:
return new OracleConnection();
break;
default:
throw new Exception("Unable to determine the appropriate provider type for "
+ providerType);
}
}
public enum DatabaseProviderType
{
OleDb,
SqlClient,
OracleClient
}
private static IDbConnection GetConnection(string assemblyName,
string providerConnectionTypeName)
{
object o = LateBinder.CreateInstance(assemblyName,providerConnectionTypeName);
if (!(o is IDbConnection))
{
throw new Exception("\"" + providerConnectionTypeName
+ "\" doesn't implement IDbConnection.");
}
return (IDbConnection) o;
}
}
Performance Test Results ![]() Two things can be concluded from the test results:
Conclusion Downloads and Further Reading Copyright © 2002 Thycotic Software Ltd. | |||||||||||||||
| Copyright © 2000-2003 ASPAlliance.com Page Rendered at
2/9/2010 1:48:22 PM |
|||||||||||||||