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


    首先,我们先要制作一个自定义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 ,然后让我们去做些新环境应该做的事。

    [csharp]view plain copy
     
     print?
    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.           
    18.         return interceptObject != null;  
    19.     }  
    20. }  

    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()方法需要我们去实现,主要作用是得到一个消息池的对象。

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

    [csharp]view plain copy
     
     print?
    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.         }  
    18.         public bool IsNewContextOK(Context newCtx)  
    19.         {  
    20.             var result = newCtx.GetProperty("Intercept");  
    21.             return result!=null;  
    22.             //return false;  
    23.         }  
    24.   
    25.         public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)  
    26.         {  
    27.             InterceptSink interceptSink = new InterceptSink(nextSink);  
    28.             return interceptSink;  
    29.         }  
    30.     }  
     

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

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

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

    [csharp]view plain copy
     
     print?
    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.           
    14.         public IMessage SyncProcessMessage(IMessage msg)  
    15.         {  
    16.               
    17.             Console.WriteLine("method_name: " + msg.Properties["__MethodName"].ToString());  
    18.             IMessage returnMsg = nextSink.SyncProcessMessage(msg);  
    19.             return returnMsg;  
    20.         }  
    21.         public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)  
    22.         {  
    23.             return null;  
    24.         }  
    25.     }  

    核心方法是:SyncProcessMessage(Imessage msg)

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

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

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

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

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

    1、该类要标记InterceptAttribute属性

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

    [csharp]view plain copy
     
     print?
    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函数中创建一个该类的对象,并进行调用方法。

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


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

    接下来是运行结果:

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

  • 相关阅读:
    mysql之全局查询日志
    使用MySQL Workbench进行数据库设计——MySQL Workbench使用方法总结
    HttpClient工具类
    JSON字符串转换为Map
    Java判断一个日期是否在下周日期区间
    Linux 查看日志文件
    判断一个日期是否为当前日期的前后几天的方法
    Spring-Boot 整合Dubbo 解决@Reference 注解为null情况
    spring注解之@Scope
    Swagger Annotation 详解(建议收藏)
  • 原文地址:https://www.cnblogs.com/lenther2002/p/6841858.html
Copyright © 2020-2023  润新知