首先,我们先要制作一个自定义Attribute,让他可以具有上下文读取功能,所以我们这个Attribute类要同时继承Attribute和IContextAttribute。

接口IContextAttribute中有两个方法需要实现

1、bool   IsContextOK(Context ctx, IConstructionCallMessage msg);

2、void  GetPropertiesForNewContext(IConstructionCallMessage msg);

简单解释一下这两个方法:

1、IsContextOK方法是让我们检查当前上下文(current  context)是否有问题,如果没有问题返回true,有问题的话返回false,然后该类会去调用GetPropertiesForNewContext

2、GetPropertiesForNewContext 是 系统会自动new一个context ,然后让我们去做些新环境应该做的事。

  1. /// <summary>
  2. /// Some class if you want to intercept,you must mark this attribute.
  3. /// </summary>
  4. public class InterceptAttribute : Attribute, IContextAttribute
  5. {
  6. public InterceptAttribute()
  7. {
  8. Console.WriteLine(" Call 'InterceptAttribute' - 'Constructor'  ");
  9. }
  10. public void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
  11. {
  12. ctorMsg.ContextProperties.Add(new InterceptProperty());
  13. }
  14. public bool IsContextOK(Context ctx, IConstructionCallMessage ctorMsg)
  15. {
  16. InterceptProperty interceptObject = ctx.GetProperty("Intercept") as InterceptProperty;
  17. return interceptObject != null;
  18. }
  19. }

ok,这是这个类的实现,要解释几点:

1、InterceptAttribute这个类继承的是Attribute,用于[Attribute]标记用的。

2、InterceptAttribute这个类继承IContextAttribute,用于给标记上的类获得上下文权限,然后要实现该接口的两个方法。

3、IsContextOK方法是去判断当前是否有“Intercept”这个属性,因为我们只需要这个属性,所以只要检查这个属性当前上下文有没有即可,如果有返回true,没有的话会调用GetPropertiesForNewContext函数。

(我们这里只做拦截器功能,所以只添加Intercept自定义属性,当然如果有需要可以添加多个属性,然后在这个函数中进行相应检查)

4、如果调用GetPropertiesForNewContext函数,他会让我们进行新上下文环境的自定义,我在这做了一个操作:在当前的上下文中添加一个属性,这个属性就是Intercept。

5、下一章我会实现InterceptProperty这个类,其实这个类就是一个上下文属性。

好了,接着上一篇文章,我们要实现一个InterceptProperty类。

先讲一下,这个类我们要继承两个接口IContextProperty和IContributeObjectSink

IContextProperty:这个接口是说明该类是一个上下文属性,他其中有两个方法IsNewContextOK和Freeze

1、Freeze()该方法用来定位被创建的Context的最后位置,一般不用写入什么逻辑。

2、IsNewContextOK()这个方法让我们检验:我们对当前新Context是否满意。满意返回true,不满意false则会异常,我们再进行处理。

IContributeObjectSink: 这个接口是是一个消息池,只有继承这个接口我们才能接收Object消息。

当然也有IContributeEnvoySink,IContributeClientContextSink,IContributeServerContextSink,这些消息池,能接收不同形式的消息,在这里不过多解释。

1、IContributeObjectSink 里面的 GetObjectSink()方法需要我们去实现,主要作用是得到一个消息池的对象。

好,话不多说,直接贴代码:

  1. //IContributeObjectSink,IContributeEnvoySink,IContributeClientContextSink,IContributeServerContextSink
  2. public class InterceptProperty:IContextProperty,IContributeObjectSink
  3. {
  4. public InterceptProperty()
  5. {
  6. Console.WriteLine(" Call 'InterceptProperty' - 'Constructor'  ");
  7. }
  8. public string Name {
  9. get
  10. {
  11. return "Intercept";
  12. }
  13. }
  14. public void Freeze(Context newContext)
  15. {
  16. }
  17. public bool IsNewContextOK(Context newCtx)
  18. {
  19. var result = newCtx.GetProperty("Intercept");
  20. return result!=null;
  21. //return false;
  22. }
  23. public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)
  24. {
  25. InterceptSink interceptSink = new InterceptSink(nextSink);
  26. return interceptSink;
  27. }
  28. }
 

简单解释一下,IsNewContextOK() 函数中,我主要是在当前新的上下文中获得我想要的Intercept属性,正常情况下,系统会构造出InterceptProperty对象,GetProperty()函数就是get出Name属性是否匹配,如果匹配则return true,否则异常。
另外的GetObjectSink方法则是得到一个InterceptSink的对象,下一节我会实现InterceptSink类。

之前为InterceptAttribute的上下文环境添加了“Intercept”属性(InterceptProperty),正因为InterceptProperty继承了IContributeObjectSink,所以我们要实现GetObjectSink(),继而我们要创建一个继承ImessageSink的类来作为返回值。

这样就引发出了InterceptSink类的实现:

  1. public class InterceptSink : IMessageSink
  2. {
  3. private IMessageSink nextSink = null;
  4. public IMessageSink NextSink
  5. {
  6. get { return nextSink; }
  7. }
  8. public InterceptSink(IMessageSink nextSink)
  9. {
  10. Console.WriteLine(" Call 'InterceptSink' - 'Constructor'  ");
  11. this.nextSink = nextSink;
  12. }
  13. public IMessage SyncProcessMessage(IMessage msg)
  14. {
  15. Console.WriteLine("method_name: " + msg.Properties["__MethodName"].ToString());
  16. IMessage returnMsg = nextSink.SyncProcessMessage(msg);
  17. return returnMsg;
  18. }
  19. public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
  20. {
  21. return null;
  22. }
  23. }

核心方法是:SyncProcessMessage(Imessage msg)

传入参数msg中,我们可以找到调用对象方法的相应数据。

ok,我们拦截器基本构造完成,接下来我来告诉大家如何去使用。

注意一个问题,object拦截器我们要拦截什么,那么我们就要在需要拦截的类上面做手脚了。

首先,创建我们需要被拦截的类。

然后,我们再对类进行相应的包装:

1、该类要标记InterceptAttribute属性

2、该类要继承ContextBoundObject,只有继承ContextBoundObject的类,vs才能知道该类需要访问Context,这样标记的InterceptAttribute才有效。

  1. /// <summary>
  2. /// If you want to add the interceptpool on this class , the class need to do:
  3. /// 1、inherited form ContextBoundObject.
  4. /// 2、mark the InterceptAttribute.
  5. /// </summary>
  6. [Intercept]
  7. public class SimonDemo:ContextBoundObject
  8. {
  9. public SimonDemo()
  10. {
  11. Console.WriteLine(" Call 'SimonDemo' - 'Constructor'  ");
  12. }
  13. public void Operate1()
  14. {
  15. Console.WriteLine("Call 'SimonDemo' - 'Operate1' ");
  16. }
  17. }

然后,我们在Main函数中创建一个该类的对象,并进行调用方法。

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. Console.WriteLine("Call Main ..");
  6. SimonDemo simon = new SimonDemo();
  7. simon.Operate1();
  8. Console.WriteLine("exit Main ..");
  9. Console.Read();
  10. }
  11. }

这样,通过调试,我们就可以看出拦截器都拦截出了什么

(转)C#制作一个消息拦截器-LMLPHP

接下来是运行结果:

(转)C#制作一个消息拦截器-LMLPHP

这样可以看出我的程序拦截,并输出了调用函数的名字。

05-11 14:02
查看更多