根据我查到的资料应该是要利用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();
}
}
}请有经验的朋友看一下,还有哪里需要设置的地方,谢谢!

解决方案 »

  1.   

    专门新建了一个项目来测试代码,但是愣没看出来哪里是在计数,lz还是出来说明一下吧。
    而且TestAttribute.cs里面很多的方法,不像是为了测试建立的。
      

  2.   

    当然上面给出的代码都是用来测试的,所以没有涉及到计数方面的功能实现. 我预想的结果是,在运行cTestManager中的Main函数后可以跑出Preprocess和Postprocess中的输出信息.但是结果并非我预想的那样. 如果把Attribute的作用域设定为Class的话,Preprocess和Postprocess中的输出信息是可以输出的. 不知道是我的代码中间还少了什么东西, 还是根本就不能用这样的方法来实现这样的功能?
      

  3.   

    this kind of interception is only valid on classes derived from ContextBoundObject, never works on the assembly itself
      

  4.   

    for your purposes, look into AppDomain's AssemblyLoad event, for example:
    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();
        }
    }
    }
      

  5.   

    To Saucer:
        多谢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。还望指教。
      

  6.   

    Attribute做不到的,象IMessageSink这样的拦截只适用于被调用的ContextBoundObject对象