实现消息截获,我们熟知的方法有将需要监控的类型从 ContextBandObject类派生,从而用消息截获器实行对 对象的横向监控。 以下是另一种简单的实行对象调用的监控AOP技术实现;

1. 调用代码例子


2. 源代码实现

/// <summary>
/// Executes both standalone and transacted SQL queries described by strongly-typed interface.
/// </summary>
/// <typeparam name="T">Interface with function prototypes</typeparam>
/// <exception cref="System.ArgumentException">Thrown when there is an error in prototype description.</exception>
/// <exception cref="System.Data.SqlClient.SqlException">Error from SQL Server while executing query.</exception>
public sealed class SqlQuery<T> : RealProxy where T : class
{
private readonly SqlConnection connection;
private readonly SqlTransaction transaction;
private readonly bool closeConnection;
public static T Create(SqlConnection connection)
{
return (new SqlQuery<T>(connection, null)).GetTransparentProxy() as T;
}
public static T Create(SqlTransaction transaction)
{
return (new SqlQuery<T>(transaction.Connection, transaction)).GetTransparentProxy() as T;
}
public static T Create(string connectionString)
{
return (new SqlQuery<T>(connectionString)).GetTransparentProxy() as T;
}
private SqlQuery(SqlConnection conn, SqlTransaction tran) : base(typeof(T))
{
connection = conn;
transaction = tran;
closeConnection = false;
}
private SqlQuery(string connectionString) : base(typeof(T))
{
connection = new SqlConnection(connectionString);
transaction = null;
closeConnection = true;
}
[DebuggerStepThrough]
public override IMessage Invoke(IMessage msg)
{
IMethodCallMessage method = msg as IMethodCallMessage;
if (method == null)
throw new ArgumentException("Failed to cast IMessage to IMethodCallMessage");
if (method.HasVarArgs)
throw new ArgumentException("Variable arguments are not supprted by SQL Server");
MethodInfo mi = (MethodInfo)method.MethodBase;
Type t = mi.ReturnType;
bool Void = (t == null || t.FullName == "System.Void");
SqlParameterCacheEntry entry = SqlParameterCache.GetEntry(mi);
using (SqlCommand cmd = connection.CreateCommand())
{
cmd.Transaction = transaction;
cmd.CommandType = entry.CommandType;
cmd.CommandText = entry.CommandText;
SqlParameter[] parameters = entry.GetParameters();
int i = -1;
int recordsAffected = -1;
int argCount = method.ArgCount;
object recordsSelected = null;
foreach (SqlParameter p in parameters)
{
cmd.Parameters.Add(p);
if (entry.ReturnsValue && p.ParameterName.StartsWith("@")) continue;
if (++i >= argCount)
throw new ArgumentException("Too many parameters passed");
if (!p.ParameterName.Equals(method.GetArgName(i), StringComparison.InvariantCultureIgnoreCase))
throw new ArgumentException("Parameter name \'" + p.ParameterName +
"\' does not match defined name", method.GetArgName(i));
if (p.Direction == ParameterDirection.ReturnValue) continue;
if (p.Direction == ParameterDirection.Output) continue;
object value = method.Args[i];
if (value is IDbDataParameter)
{
IDbDataParameter dbp = (IDbDataParameter)value;
p.Value = (dbp.Value == null) ? DBNull.Value : dbp.Value;
}
else
p.Value = (value == null) ? DBNull.Value : value;
}
if (i < argCount - 1)
throw new ArgumentException("Not enough parameters passed");
List<object> outParams = new List<object>(method.ArgCount);
try
{
if (closeConnection)
connection.Open();
if (entry.ReturnsRecordset)
{
bool singleRow = false;
CommandBehavior opts = CommandBehavior.Default;
if (t == typeof(DataSet))
recordsSelected = new DataSet();
else if (t == typeof(DataTable))
opts = CommandBehavior.SingleResult;
else if (t == typeof(SingleRowDataTable))
{
opts = CommandBehavior.SingleResult | CommandBehavior.SingleRow;
singleRow = true;
}
else
throw new ArgumentException("DataSet, DataTable or SingleRowDataTable must be returned", "Return value");
using (SqlDataReader rd = cmd.ExecuteReader(opts))
{
if (!singleRow)
{
do
{
DataColumn[] columns = GetColumnInfo(rd);
object[] values = new object[columns.Length];
DataTable table = new DataTable();
table.BeginLoadData();
table.Columns.AddRange(columns);
while (rd.Read())
{
rd.GetValues(values);
table.Rows.Add(values);
}
table.EndLoadData();
table.AcceptChanges();
if (recordsSelected != null && recordsSelected is DataSet)
((DataSet)recordsSelected).Tables.Add(table);
else
{
recordsSelected = table;
break;
}
}
while (rd.NextResult());
}
else
{
DataColumn[] columns = GetColumnInfo(rd);
object[] values = new object[columns.Length];
SingleRowDataTable table = new SingleRowDataTable();
table.BeginLoadData();
table.Columns.AddRange(columns);
if (rd.Read())
{
rd.GetValues(values);
table.Rows.Add(values);
}
table.EndLoadData();
table.AcceptChanges();
recordsSelected = table;
}
rd.Close();
}
}
else
{
recordsAffected = cmd.ExecuteNonQuery();
}
for (int j = 0; j < method.ArgCount; j++)
{
SqlParameter p = cmd.Parameters[method.GetArgName(j)];
outParams.Add(((p.Direction == ParameterDirection.Input || p.Value == DBNull.Value) ? null : p.Value));
}
}
finally
{
if (closeConnection)
connection.Close();
}
if (entry.ReturnsRecordset)
return new ReturnMessage(recordsSelected, outParams.ToArray(), outParams.Count, method.LogicalCallContext, method);
if (entry.ReturnsValue)
{
object value = cmd.Parameters[entry.ReturnParameter].Value;
if (value == DBNull.Value) value = null;
return new ReturnMessage(value, outParams.ToArray(), outParams.Count, method.LogicalCallContext, method);
}
else if (Void)
return new ReturnMessage(null, outParams.ToArray(), outParams.Count, method.LogicalCallContext, method);
else if (t == typeof(int))
return new ReturnMessage(recordsAffected, outParams.ToArray(), outParams.Count, method.LogicalCallContext, method);
throw new ArgumentException("Method must return SqlReturn-marked value, DataSet, DataTable, SingleRowDataTable, Int or Void", "Return value");
}
}
posted on 2006-11-16 22:19  望天  阅读(567)  评论(0编辑  收藏  举报