Sep
22
2006
Dynamically loading dll in .net - howto part 11
Posted by admin under
In practice
Please read this article serie from the beginning
In part 10 we started implementing our DAL - and having it implement a welldefined interface is gonna make our application able to dynamically load which data access layer to use. It will open up for the possiblity to switch data storage engines - even to later on add some support for some other database (say Oracle) without the need to recompile the application. Just make sure the new driver implements the correct interface!
So - lets look at the facts:
1. CustomerInterfaces.dll - here we define the DAL interface
namespace CustomerInterfaces
{
public interface DALInterface
{
long Customer_Save(string sConnString, long lId, string sName);
DataSet Customer_Open(string sConnString, long ld);
DataSet Customer_ListAll(string sConnString);
...
2. We have developed the driver for SQL Server - CustomerDAL_SQLServer - and it's implementing the DALInterface
namespace CustomerDAL_SQLServer
{
public class DataAccess : CustomerInterfaces.DALInterface
{
#region DALInterface Members
public long Customer_Save(string sConnString, long lId, string sName)
{
SqlParameter[] paramsToSP = new SqlParameter[2];
paramsToSP[0] = new SqlParameter("@id", SqlDbType.Int);
paramsToSP[0].Value = lId;
paramsToSP[1] = new SqlParameter("@name", SqlDbType.VarChar, 50);
paramsToSP[1].Value = sName;
return Convert.ToInt32(Microsoft.ApplicationBlocks.Data.SqlHelper.ExecuteScalar(sConnString,
CommandType.StoredProcedure, "cust_SaveCustomer", paramsToSP));
}
3. Our CustomerClasses.dll contains a customer class and a file class and those should now start to use our DAL
Dynamic configuration of which DAL to use
We need to somehow tell the web application which DAL dll to use - since we are NOT statically linking to the dll (referencing it - we are instead just referencing the CustomerInterface dll ). So web.config would be a good place:
<appSettings>
<add key="DataAccessComponent" value="CustomerDAL_SQLServer.DataAccess, CustomerDAL_SQLServer"/>
<appSettings>
I have added a key - DataAccessComponent and pointing it to a pretty hard to understand string. The syntax is <fullnamespacespecification>.<classname>, <dll>. The secret behind it is that we can use it to call Activator.CreateInstance and have .NET load dll if needed and instantiate that class for us. Lets see how it looks in code.
In CustomerClasses we add a MyGlobals.cs class.
class MyGlobals
{
private static CustomerInterfaces.DALInterface m_GetDataAccessComponent = null;
public static CustomerInterfaces.DALInterface GetDataAccessComponent()
{
if (m_GetDataAccessComponent == null)
{
string sClassName = System.Configuration.ConfigurationManager.AppSettings["DataAccessComponent"].ToString();
string sName = Type.GetType(sClassName).Name;
m_GetDataAccessComponent = (CustomerInterfaces.DALInterface)Activator.CreateInstance(Type.GetType(sClassName));
}
return m_GetDataAccessComponent;
}
}
We store a static reference to a dal class ( m_GetDataAccessComponent ) and first time accessed we will instantiate the class as defined in our web.config!
So lets now change our CustomerClasses.Customer code to use the dynamically load DAL instead:
old customercollection
public class CustomerCollection : System.Collections.Generic.List<Customer>
{
public void OpenAll()
{
DataSet ds = Microsoft.ApplicationBlocks.Data.SqlHelper.ExecuteDataset(
System.Configuration.ConfigurationManager.ConnectionStrings["MainConn"].ToString(),
CommandType.StoredProcedure, "cust_ListCustomers");
foreach (DataRow row in ds.Tables[0].Rows )
{
Customer oCust = new Customer();
oCust.InitFromRow( row );
Add(oCust);
}
}
new customercollection
public class CustomerCollection : System.Collections.Generic.List<Customer>
{
public void OpenAll()
{
DataSet ds = MyGlobals.GetDataAccessComponent().Customer_ListAll(
System.Configuration.ConfigurationManager.ConnectionStrings["MainConn"].ToString()
);
foreach (DataRow row in ds.Tables[0].Rows )
{
Customer oCust = new Customer();
oCust.InitFromRow( row );
Add(oCust);
}
}
}
And that's it! Our application is now fully functional again - no new functionality, but we have the power to add extra drivers - I am gonna add a driver for MySQL in the next article.
Please don't forget download the code attached to this article! It contains the full solution.