Well its been a great year. I'm thinking of moving on from my current contract - been 4 years slogging on at the same area. Longest contract I've ever had - heck, longest job I've ever had.
Well, on to more interesting things - like code. We have developed a unified Framework here where I am contracting at to centralize (aka reuse) more commonly used areas of functionality, mostly data access. All data access has been abstracted into static method calls such as (note class names have been changed):
DataSet myData = Framework.Data.Enterprise.EmployeeGateway.GetAllEmployees();
or, if a Business Object wrapper was available, can be:
EmployeeCollection myEmployeeCollection = Framework.Data.Enterprise.BusinessObject.EmployeeGateway.GetAllEmployees();
An application that wants employee data simply calls one of the methods above. Simple, huh? Now, we wanted to deploy the application behind a firewall. We no longer had direct access to the database and all data requests had to know be funneled through web services. But who wanted to recode 398 stored procedures? Using a bit of reflection, I was able to potentially open up all of the static method calls so that an application running outside the firewall was able to make the same database call without knowing it was actually been funnelled through one (or more!) web services for its data. Code tidbit below:
public class EmployeeGateway
{
private EmployeeGateway() { }
public static DataSet GetAllEmployees()
{
return ExecDataSetQuery(“GET_ALL_EMPLOYEES“, null);
}
private static DataSet ExecDataSetQuery(string sProc, SqlParameter[] parms)
{
// Connection factory returns either a SqlConnection or a WebService instance
// based on a Framework configuration file. Connection information for a given
// data source was either an encrypted connection string or an encrypted web
// service endpoint.
object connection = ConnectionFactory.CreateConnection(DataSourceEnum.Employee);
DataSet ds = null;
if (connection.GetType().Equals(typeof(SqlConnection))
{
using (SqlConnection sqlConnection = connection as SqlConnection)
{
// standard SqlDataAdapter / Fill code here
}
}
else if (connection.GetType().Equals(typeof(Framework.Web.Services.Enterprise.EmployeeGateway)))
{
using (Framework.Web.Services.Enterprise.EmployeeGateway webServiceConnection = connection as Framework.Web.Services.Enterprise.EmployeeGateway)
{
try
{
MethodInfo method = webServiceConnection.GetType().GetMethod(ExtractWebMethodName(sProc);
if (null != method)
ds = (DataSet)method.Invoke(webServiceConnection, Framework.Data.SqlController.ToObjectArray(parms));
else
throw new Framework.Data.DataException(String.Format(“Unable to locate Web Service name of {0} on the {1} connection.“, sProc, DataSourceEnum.Employee.ToString()));
}
catch (System.Exception ex)
{
// publish error to a central event log
throw new Framework.Data.DataException(String.Format(“Failed to execute Web Service {0}.“, webServiceConnection.ToString()), ex);
}
}
}
else
throw new Framework.Data.DataException(String.Format(“Unhandled connection request {0} returned from ConnectionFactory.“, connection.ToString());
}
}
The caveats of course is that the Web Service proxy names need to match the stored procedure names. Not a bad tradeoff if you don't have to write all the web service proxy instantiations in your code and get them for free. The bolded function names above are included below for completeness.
internal static string ExtractWebMethodName(string sProc)
{
string webMethodName = sProc;
int sProcSeperatorIndex = sProc.LastIndexOf(“.“);
if (sProcSeperatorIndex > -1)
webMethodName = sProc.SubString(sProcSeperatorIndex+1, sProc.Length - sProcSeperatorIndex);
return webMethodName;
}
internal static Object[] ToObjectArray(SqlParameter[] parms)
{
int parmLength = 0;
if (null != parms)
{
// figure out array length
foreach (SqlParameter parm in parms)
{
if (parm.Direction != ParameterDirection.Output)
parmLength++;
}
}
int index = 0;
object[] args = new object[parmLength];
if (null != parms)
{
foreach (SqlParameter parm in parms)
{
if (parm.Direction != ParameterDirection.Output)
args[index++] = parm.Value;
}
}
return args;
}