根据我查到的资料应该是要利用Attribute来实现,并且AttributeTargets应该为Assembly。但是我做的一个Demo的运行结果表明并没有运行过这个Attribute.
代码如下:
TestAttribute.cs+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
using System;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Activation;namespace AOP.Experiment
{
internal class CallTracingAspect : IMessageSink
{
private IMessageSink m_next;
private String m_typeAndName ; internal CallTracingAspect(IMessageSink next)
{
// Cache the next sink in the chain
m_next = next;
} public IMessageSink NextSink
{
get
{
return m_next;
}
} public IMessage SyncProcessMessage(IMessage msg)
{
Preprocess(msg);
IMessage returnMethod = m_next.SyncProcessMessage(msg);
PostProcess(msg, returnMethod);
return returnMethod;
}
public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
throw new InvalidOperationException() ;
}
public static string ContextName
{
get
{
return "CallContext" ;
}
}
private void Preprocess(IMessage msg)
{
if (!(msg is IMethodMessage)) return; IMethodMessage call = msg as IMethodMessage;
Type t = Type.GetType(call.TypeName) ;
m_typeAndName = t.Name + "." + call.MethodName ;
Console.Write("calltrace PreProcessing: " + m_typeAndName + "("); for (int i = 0; i < call.ArgCount; ++i)
{
if (i > 0) Console.Write(", ");
Console.Write(call.GetArgName(i) + "= " + call.GetArg(i));
}
Console.WriteLine(")");
// set us up in the callContext
call.LogicalCallContext.SetData(ContextName, this);
} private void PostProcess(IMessage msg, IMessage msgReturn)
{
// We only want to process method return calls
if (!(msg is IMethodMessage) ||
!(msgReturn is IMethodReturnMessage)) return; IMethodReturnMessage retMsg = (IMethodReturnMessage)msgReturn;
Console.Write("calltrace PostProcessing: ");
Exception e = retMsg.Exception;
if (e != null)
{
Console.WriteLine("Exception was thrown: " + e);
return;
} // Loop through all the [out] parameters
Console.Write(m_typeAndName + "(");
if (retMsg.OutArgCount > 0)
{
Console.Write("out parameters[");
for (int i = 0; i < retMsg.OutArgCount; ++i )
{
if (i > 0) Console.Write(", ");
Console.Write(retMsg.GetOutArgName(i) + "= " +
retMsg.GetOutArg(i));
}
Console.Write("]");
}
if (retMsg.ReturnValue.GetType() != typeof(void))
Console.Write("returned [" + retMsg.ReturnValue + "]"); Console.WriteLine(")");
}
}
public class CallTracingProperty : IContextProperty, IContributeServerContextSink
{
public IMessageSink GetServerContextSink(IMessageSink next)
{
Console.WriteLine("***In CallTracingProperty's GetObjectSink***");
Console.WriteLine("Next Message Sink is " + next.GetType());
return new CallTracingAspect(next);
}
public bool IsNewContextOK( Context newCtx )
{
return true ;
}
public void Freeze(Context newContext)
{
}
public string Name
{
get
{
return "CallTracingProperty";
}
}
}
[AttributeUsage(AttributeTargets.Assembly)]
public class CallTracingAttribute : ContextAttribute
{
public CallTracingAttribute() : base("CallTracing") {}
public override void GetPropertiesForNewContext(IConstructionCallMessage ccm)
{
ccm.ContextProperties.Add(new CallTracingProperty());
Console.WriteLine("CallTracingAttribute has been created for new context");
}
}
}
TestClass.cs+++++++++++++++++++++++++++++++++++++++++++++++++
using System;namespace AOP.Experiment
{
public class cTestClass:ContextBoundObject
{
public cTestClass()
{
Console.WriteLine("TestClass ctor()");
} public override string ToString()
{
return "Test Class";
} }
}TestClass.cs的AssemblyInfo.cs+++++++++++++++++++++++++++++++++++++using System.Reflection;
using System.Runtime.CompilerServices;
using AOP.Experiment;[assembly: CallTracing()][assembly: AssemblyTitle("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrade("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]TestManager.cs+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
using System;
using System.Reflection;namespace AOP.Experiment
{
class cTestManager
{
[STAThread]
static void Main(string[] args)
{
Assembly TestAssembly;
cTestClass TestClass;
try
{
Console.WriteLine("dd");
TestAssembly = Assembly.LoadFrom("E:\\DR\\Module\\Debug\\TestClass.dll");
Console.WriteLine(TestAssembly.GetName().ToString());
TestClass = (cTestClass)TestAssembly.CreateInstance("AOP.Experiment.cTestClass");
Console.WriteLine(TestClass.ToString()); }
catch(Exception e)
{
Console.WriteLine(e.ToString());
} Console.ReadLine();
}
}
}请有经验的朋友看一下,还有哪里需要设置的地方,谢谢!
代码如下:
TestAttribute.cs+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
using System;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Activation;namespace AOP.Experiment
{
internal class CallTracingAspect : IMessageSink
{
private IMessageSink m_next;
private String m_typeAndName ; internal CallTracingAspect(IMessageSink next)
{
// Cache the next sink in the chain
m_next = next;
} public IMessageSink NextSink
{
get
{
return m_next;
}
} public IMessage SyncProcessMessage(IMessage msg)
{
Preprocess(msg);
IMessage returnMethod = m_next.SyncProcessMessage(msg);
PostProcess(msg, returnMethod);
return returnMethod;
}
public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
throw new InvalidOperationException() ;
}
public static string ContextName
{
get
{
return "CallContext" ;
}
}
private void Preprocess(IMessage msg)
{
if (!(msg is IMethodMessage)) return; IMethodMessage call = msg as IMethodMessage;
Type t = Type.GetType(call.TypeName) ;
m_typeAndName = t.Name + "." + call.MethodName ;
Console.Write("calltrace PreProcessing: " + m_typeAndName + "("); for (int i = 0; i < call.ArgCount; ++i)
{
if (i > 0) Console.Write(", ");
Console.Write(call.GetArgName(i) + "= " + call.GetArg(i));
}
Console.WriteLine(")");
// set us up in the callContext
call.LogicalCallContext.SetData(ContextName, this);
} private void PostProcess(IMessage msg, IMessage msgReturn)
{
// We only want to process method return calls
if (!(msg is IMethodMessage) ||
!(msgReturn is IMethodReturnMessage)) return; IMethodReturnMessage retMsg = (IMethodReturnMessage)msgReturn;
Console.Write("calltrace PostProcessing: ");
Exception e = retMsg.Exception;
if (e != null)
{
Console.WriteLine("Exception was thrown: " + e);
return;
} // Loop through all the [out] parameters
Console.Write(m_typeAndName + "(");
if (retMsg.OutArgCount > 0)
{
Console.Write("out parameters[");
for (int i = 0; i < retMsg.OutArgCount; ++i )
{
if (i > 0) Console.Write(", ");
Console.Write(retMsg.GetOutArgName(i) + "= " +
retMsg.GetOutArg(i));
}
Console.Write("]");
}
if (retMsg.ReturnValue.GetType() != typeof(void))
Console.Write("returned [" + retMsg.ReturnValue + "]"); Console.WriteLine(")");
}
}
public class CallTracingProperty : IContextProperty, IContributeServerContextSink
{
public IMessageSink GetServerContextSink(IMessageSink next)
{
Console.WriteLine("***In CallTracingProperty's GetObjectSink***");
Console.WriteLine("Next Message Sink is " + next.GetType());
return new CallTracingAspect(next);
}
public bool IsNewContextOK( Context newCtx )
{
return true ;
}
public void Freeze(Context newContext)
{
}
public string Name
{
get
{
return "CallTracingProperty";
}
}
}
[AttributeUsage(AttributeTargets.Assembly)]
public class CallTracingAttribute : ContextAttribute
{
public CallTracingAttribute() : base("CallTracing") {}
public override void GetPropertiesForNewContext(IConstructionCallMessage ccm)
{
ccm.ContextProperties.Add(new CallTracingProperty());
Console.WriteLine("CallTracingAttribute has been created for new context");
}
}
}
TestClass.cs+++++++++++++++++++++++++++++++++++++++++++++++++
using System;namespace AOP.Experiment
{
public class cTestClass:ContextBoundObject
{
public cTestClass()
{
Console.WriteLine("TestClass ctor()");
} public override string ToString()
{
return "Test Class";
} }
}TestClass.cs的AssemblyInfo.cs+++++++++++++++++++++++++++++++++++++using System.Reflection;
using System.Runtime.CompilerServices;
using AOP.Experiment;[assembly: CallTracing()][assembly: AssemblyTitle("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrade("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]TestManager.cs+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
using System;
using System.Reflection;namespace AOP.Experiment
{
class cTestManager
{
[STAThread]
static void Main(string[] args)
{
Assembly TestAssembly;
cTestClass TestClass;
try
{
Console.WriteLine("dd");
TestAssembly = Assembly.LoadFrom("E:\\DR\\Module\\Debug\\TestClass.dll");
Console.WriteLine(TestAssembly.GetName().ToString());
TestClass = (cTestClass)TestAssembly.CreateInstance("AOP.Experiment.cTestClass");
Console.WriteLine(TestClass.ToString()); }
catch(Exception e)
{
Console.WriteLine(e.ToString());
} Console.ReadLine();
}
}
}请有经验的朋友看一下,还有哪里需要设置的地方,谢谢!
而且TestAttribute.cs里面很多的方法,不像是为了测试建立的。
using System;
using System.Reflection;namespace AOP.Experiment
{
class cTestManager
{
[STAThread]
static void Main(string[] args)
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyLoad += new AssemblyLoadEventHandler(MyAssemblyLoadEventHandler);
Assembly TestAssembly;
//cTestClass TestClass;
try
{
Console.WriteLine("dd");
TestAssembly = Assembly.LoadFrom("E:\\DR\\Module\\Debug\\TestClass.dll");
Console.WriteLine(TestAssembly.GetName().ToString());
object o = TestAssembly.CreateInstance("AOP.Experiment.cTestClass");
Console.WriteLine(o.ToString()); }
catch(Exception e)
{
Console.WriteLine(e.ToString());
} Console.ReadLine();
} static void MyAssemblyLoadEventHandler(object sender, AssemblyLoadEventArgs args)
{
Console.WriteLine("ASSEMBLY LOADED: " + args.LoadedAssembly.FullName);
Console.WriteLine();
}
}
}
多谢Saucer。我知道依照你那样的方法添加一个事件是可以实现这个功能的,但是我想做的是对所有的Assembly都实现这样的功能,这个功能应该是属于非功能代码(non-functional code)。所以,我还是想利用Attribute实现这个功能。 在你的回复中说是要使用ContextBoundObject对象,其实在我的TestClass类中已经有了这样的定义:
public class cTestClass:ContextBoundObject
并且我在TestClass.cs的AssemblyInfo.cs文件中添加了这样的引用(不知道是不是这样的用法):
[assembly: CallTracing()]
虽然这样的用法在编译上是可以通过的,但是好象就是不能执行进Attribute中去。 如果定义AttributeTargets为Class,同时把[CallTracing()]添加到TestClass的定义之前,是可以的。这就说明Attribute的定义是没有问题的,问题可能在于如何使用这个Attribute。还望指教。