zoukankan      html  css  js  c++  java
  • C# Attribute 实现简单的 AOP 处理的例子(转)

    工作中遇到这样的情况,项目开发之前,没提过什么日志的东西。

    项目开发的差不多了,说需要记录日志文件。

    比如客户端调用服务器的时候,都什么时间,谁,调用了什么之类的。

     

    目前还不确定,这个日志到底要怎么记录,以及都记录哪些信息。

    上网查询了一下 AOP 的东西,实现办法还真不少。

    这里就写个简单的,使用 Attribute 实现的例子。

     

    首先是个 目标类,也就是针对这个类的方法,来做AOP的操作。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace A0075_AOPAttributes.Sample
    {
        public class ObjectClass
        {
            public void Test1()
            {
                Console.WriteLine("Test");
            }
            public void Test2(string para)
            {
                Console.WriteLine("Test:" + para);
            }
            public void Test3(int para)
            {
                Console.WriteLine("Test:" + para);
            }
        }
    }

    出于演示的目的,这个类只有3个方法。只输出点基本的信息。

    由于实际的项目,那个类有几十个方法,每个方法,都复制/粘贴一段 Log 代码上去,也不现实。

    下面是 Attribute的代码

     

    using System;
    using System.Text;
    using System.Runtime.Remoting.Messaging;

    namespace A0075_AOPAttributes.Sample
    {

        public class AutoLogSink : IMessageSink
        {

            /// <summary>
            /// 保存下一个接收器
            /// </summary>
            private IMessageSink nextSink;

            /// <summary>
            /// 在构造器中初始化下一个接收器
            /// </summary>
            /// <param name="next"></param>
            public AutoLogSink(IMessageSink next)
            {
                nextSink = next;
            }

            /// <summary>
            /// 必须实现的IMessageSink接口属性
            /// </summary>
            public IMessageSink NextSink
            {
                get
                {
                    return nextSink;
                }
            }

            /// <summary>
            /// 实现IMessageSink的接口方法,当消息传递的时候,该方法被调用
            /// </summary>
            /// <param name="msg"></param>
            /// <returns></returns>
            public IMessage SyncProcessMessage(IMessage msg)
            {
                //拦截消息,做前处理
                Preprocess(msg);
                //传递消息给下一个接收器
                IMessage retMsg = nextSink.SyncProcessMessage(msg);
                //调用返回时进行拦截,并进行后处理
                Postprocess(msg, retMsg);
                return retMsg;
            }


            /// <summary>
            /// IMessageSink接口方法,用于异步处理,我们不实现异步处理,所以简单返回null,
            /// 不管是同步还是异步,这个方法都需要定义
            /// </summary>
            /// <param name="msg"></param>
            /// <param name="replySink"></param>
            /// <returns></returns>
            public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
            {
                return null;
            }

            /// <summary>
            /// 前处理.
            /// </summary>
            /// <param name="msg"></param>
            private void Preprocess(IMessage msg)
            {
                //检查是否是方法调用,我们只拦截Order的Submit方法。
                IMethodCallMessage call = msg as IMethodCallMessage;
                if (call == null)
                    return;
                StringBuilder buff = new StringBuilder();
                buff.AppendFormat("$LOG$:开始调用{0}方法。参数数量:{1}", call.MethodName, call.InArgCount);
                buff.AppendLine();
                for (int i = 0; i < call.InArgCount; i++)
                {
                    buff.AppendFormat("  参数[{0}] : {1}", i + 1, call.InArgs[i]);
                    buff.AppendLine();
                }
                Console.Write(buff.ToString());
            }

            /// <summary>
            /// 后处理
            /// </summary>
            /// <param name="msg"></param>
            /// <param name="retMsg"></param>
            private void Postprocess(IMessage msg, IMessage retMsg)
            {
                IMethodCallMessage call = msg as IMethodCallMessage;
                if (call == null)
                    return;
                StringBuilder buff = new StringBuilder();
                buff.AppendFormat("$LOG$:调用{0}方法结束", call.MethodName);
                buff.AppendLine();
                Console.Write(buff.ToString());
            }
        }

     

        public class AutoLogProperty : IContextProperty, IContributeObjectSink
        {
            public AutoLogProperty()
            {
            }

            /// <summary>
            /// IContributeObjectSink的接口方法,实例化消息接收器
            /// </summary>
            /// <param name="obj"></param>
            /// <param name="next"></param>
            /// <returns></returns>
            public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink next)
            {
                return new AutoLogSink(next);
            }

            /// <summary>
            /// IContextProperty接口方法,如果该方法返回ture,在新的上下文环境中激活对象
            /// </summary>
            /// <param name="newCtx"></param>
            /// <returns></returns>
            public bool IsNewContextOK(Context newCtx)
            {
                return true;
            }

            /// <summary>
            /// IContextProperty接口方法,提供高级使用
            /// </summary>
            /// <param name="newCtx"></param>
            public void Freeze(Context newCtx)
            {
            }

            /// <summary>
            /// IContextProperty接口属性
            /// </summary>
            public string Name
            {
                get { return "AutoLog"; }
            }
        }

     

        [AttributeUsage(AttributeTargets.Class)]
        public class AutoLogAttribute : ContextAttribute
        {
            public AutoLogAttribute() : base("AutoLog")
            {
            }

            /// <summary>
            /// 覆盖 ContextAttribute方法,创建一个上下文环境属性
            /// </summary>
            /// <param name="ctorMsg"></param>
            public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
            {
                ctorMsg.ContextProperties.Add(new AutoLogProperty());
            }
        }


    }

    下面是 使用 Attribute 实现简单的 AOP 目标代码 [粗体的地方,为在原代码的基础上增加的代码]

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace A0075_AOPAttributes.Sample
    {
        [AutoLog]
        public class ObjectClassAOP: ContextBoundObject
        {
            public void Test1()
            {
                Console.WriteLine("Test");
            }
            public void Test2(string para)
            {
                Console.WriteLine("Test:" + para);
            }
            public void Test3(int para)
            {
                Console.WriteLine("Test:" + para);
            }
        }
    }

     

    测试运行代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    using A0075_AOPAttributes.Sample;

    namespace A0075_AOPAttributes
    {
        class Program
        {
            static void Main(string[] args)
            {

                ObjectClass obj = new ObjectClass();
                obj.Test1();
                obj.Test2("Test");
                obj.Test3(1024);

                ObjectClassAOP objAop = new ObjectClassAOP();
                objAop.Test1();
                objAop.Test2("Test");
                objAop.Test3(1024);

                Console.ReadLine();
            }
        }
    }

    运行结果:

    Test
    Test:Test
    Test:1024
    $LOG$:开始调用Test1方法。参数数量:0
    Test
    $LOG$:调用Test1方法结束
    $LOG$:开始调用Test2方法。参数数量:1
      参数[1] : Test
    Test:Test
    $LOG$:调用Test2方法结束
    $LOG$:开始调用Test3方法。参数数量:1
      参数[1] : 1024
    Test:1024
    $LOG$:调用Test3方法结束

  • 相关阅读:
    [LeetCode] Power of Three 判断3的次方数
    [LeetCode] 322. Coin Change 硬币找零
    [LeetCode] 321. Create Maximum Number 创建最大数
    ITK 3.20.1 VS2010 Configuration 配置
    VTK 5.10.1 VS2010 Configuration 配置
    FLTK 1.3.3 MinGW 4.9.1 Configuration 配置
    FLTK 1.1.10 VS2010 Configuration 配置
    Inheritance, Association, Aggregation, and Composition 类的继承,关联,聚合和组合的区别
    [LeetCode] Bulb Switcher 灯泡开关
    [LeetCode] Maximum Product of Word Lengths 单词长度的最大积
  • 原文地址:https://www.cnblogs.com/zjoch/p/2117656.html
Copyright © 2011-2022 走看看