基于微软企业库的AOP组件(含源码)

软件开发,离不开对日志的操作。日志可以帮助我们查找和检测问题,比较传统的日志是在方法执行前或后,手动调用日志代码保存。但自从AOP出现后,我们就可以避免这种繁琐但又必须要实现的方式。本文是在微软企业库的AOP基础上封装出的组件。注意:是使用2.0版本,因为2.0以上版本是基于Net4.5类库的。好了,废话不多说。如图-1所示

图-1

说明

    logmethodBillModel文件,是记录AOP详细信息

    IBasicCodeService和BasicCodeService是用于测试的接口和实现类

    AopUtil是实现Aop的类,核心代码

继续分析代码。

  步骤1,先创建2个特性,用于标记在类和方法上,表示这个类中这个方法需要被Aop记录

    /// <summary>
    /// 贴在接口上
    /// </summary>
    public class NSAopHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container)
        {
            return new NSAopCallHandler();
        }
    }
 

    /// <summary>
    /// 贴在方法上,作用:用于开启AOP功能
    /// 开启AOP日志保存
    /// </summary>
    public class NSAopMethodToMethodHandlerAttribute : System.Attribute
    {
    }

  步骤2,继承ICallHandler接口实现Aop功能

    public class NSAopCallHandler : ICallHandler
    {        
        public int Order { get; set; }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            //增加其他日志类型,处理方案如下
            //无论是否需记录log_method方法,方法均先执行完成.同时,记录时执行时间

            MethodBase mbCurrent = input.MethodBase;
            string methodName = input.MethodBase.Name;
            string fullName = input.Target.ToString() + "." + methodName; 
            
            //1,方法执行,并记录开始和结束执行时间
            DateTime dtmBegin = DateTime.Now;
            var methodReturn = getNext()(input, getNext);
            DateTime dtmEnd = DateTime.Now;

            TimeSpan ts = dtmEnd - dtmBegin;
            decimal invokeMilliSecond = Convert.ToDecimal(ts.TotalMilliseconds);              

            //6,判断是否需保存Aop日志
            object attriToMethod  = AttributeHelper.GetCustomAttribute(mbCurrent, "NSAopMethodToMethodHandlerAttribute");
            if (attriToMethod != null    )
            {
                string declaringType = input.MethodBase.ToString();
                string instanceName = input.MethodBase.Module.Name;

                //获取参数列表
                Dictionary<string, string> dicParamInfo = new Dictionary<string, string>();
                for (var i = 0; i < input.Arguments.Count; i++)
                {
                    string piName = input.Arguments.ParameterName(i);
                    string piValue = input.Arguments[i] as string;
                    dicParamInfo.Add(piName, piValue);
                }

                //获取方法的层级关系
                //参考地址:http://www.cnblogs.com/mumuliang/p/3939143.html
                string parentFullName = null;
                string parentDeclaringType = null;
                System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace();
                System.Diagnostics.StackFrame[] sfs = st.GetFrames();
                for (int u = 0; u < sfs.Length; ++u)
                {
                    System.Reflection.MethodBase mb = sfs[u].GetMethod();

                    //数据如下所示                
                    //[CALL STACK][12]: ExampleAOP.AOPProxy.BasicCodeService.DoSomething1
                    //[CALL STACK][13]: ExampleAOP.AOPProxy.AOPProxyTest.Output
                    //[CALL STACK][14]: ExampleAOP.Program.Main
                    string parentInfo = string.Format("[CALL STACK][{0}]: {1}.{2}", u, mb.DeclaringType.FullName, mb.Name);

                    //判断是否包含本方法.若包含,则获取其下一级的数据即可
                    string source = mb.Name;
                    if (source == methodName)
                    {
                        if (u + 1 < sfs.Length)
                        {
                            System.Reflection.MethodBase mbParent = sfs[u + 1].GetMethod();

                            parentFullName = mbParent.DeclaringType.FullName + "." + mbParent.Name;
                            parentDeclaringType = mbParent.ToString();
                        }

                        break;
                    }
                }

                //记录至全局静态变量
                logmethodBillModel modelLog = new logmethodBillModel()
                {
                    MethodName = methodName,
                    FullName = fullName,
                    DeclaringType = declaringType,
                    ParentFullName = parentFullName,
                    ParentDeclaringType = parentDeclaringType,
                    ParamInfo = dicParamInfo,
                    InvokeBeginTime = dtmBegin,
                    InvokeEndTime = dtmEnd,
                    InvokeMilliSecond = invokeMilliSecond,
                    InstanceName = instanceName,
                };
                BaseService.LogMethods.Add(modelLog);
            }

            return methodReturn;
        }
    }

  步骤3,就是对接口的使用,当然这里用的是IOC。如下代码所示

        /// <summary>
        /// 创建Service服务类,基于微软企业库
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T CreateService<T>() where T : class
        {
            IUnityContainer container = new UnityContainer().AddNewExtension<Interception>();
            container.RegisterType<IBasicCodeService, BasicCodeService>();

            container.Configure<Interception>().SetInterceptorFor<T>(new InterfaceInterceptor());

            T t = container.Resolve<T>();
            return t;
        }

好了,搞定收工。看看调用的代码。so easy

    class Program
    {
        static void Main(string[] args)
        {
            IBasicCodeService baService = BaseService.CreateService<IBasicCodeService>();
            string userName = baService.SingleUserCode("user1");
            List<string> listUserCode = baService.GetListUserCode("code1", "name1");

            System.Console.WriteLine("生成日志个数:" + BaseService.LogMethods.Count);

            System.Console.ReadKey();
        }
    }

这里有一点要说明下,就是接口中有方法1(需记录Aop);方法2(不需记录)。这种情况下,若方法2引用方法1时,也想生成Aop的话,需这样调用,直接使用this是不行的

        public string SingleUserCode(string userCode)
        {
            IBasicCodeService baService = BaseService.CreateService<IBasicCodeService>();
            var listUserCode = baService.GetListUserCode(userCode, "name1");

            return listUserCode[0];
        }

        public List<string> GetListUserCode(string userCode, string userName)
        {
            return new List<string>() { "UserCode1", "UserCode2" };
        }

介绍AOP比较全面的博客

C#进阶系列——AOP?AOP!

 源码下载方式 1,关注微信公众号:小特工作室(也可直接扫描签名处二维码) 2,发送:示例4008 即可下载 

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏GuZhenYin

SignalR系列续集[系列6:使用自己的连接ID]

前言 老规矩,前言~,在此先道个歉,之前的1-5对很多细节问题都讲的不是很详细,也有很多人在QQ或者博客问我一些问题 所以,特开了这个续集.. - -, 讲一些...

511100
来自专栏智能大石头

XCode读取Excel数据(适用于任何数据库)

虽然是充血模型,虽然是强类型,XCode同样支持遍历任何数据库结构,并以强类型(相对于DataSet等字典访问)方式读取数据。 要遍历数据库结构是很容易的事情,...

22980
来自专栏ASP.NET MVC5 后台权限管理系统

ASP.NET MVC5+EF6+EasyUI 后台管理系统(63)-Excel导入和导出-自定义表模导入

前言 上一节使用了LinqToExcel和CloseXML对Excel表进行导入和导出的简单操作,大家可以跳转到上一节查看: ASP.NET MVC5+EF...

45850
来自专栏恰童鞋骚年

自己动手写一个简单的MVC框架(第二版)

  在ASP.NET MVC中,最核心的当属“路由系统”,而路由系统的核心则源于一个强大的System.Web.Routing.dll组件。

10620
来自专栏葡萄城控件技术团队

异步陷阱之死锁篇

提倡异步编程旨在给用户更好的前端体验,但异步编程也让学习成本和犯错几率大大升高,其中最常见且最难处理的就是死锁。 何谓“死锁”,英文术语称“Deadlock”,...

31190
来自专栏博客园

持久化方式

HttpContext抽象提供了一个简单的IDictionary<Object,Object>类型的字典集合,叫做Items。在每个请求中,这个集合从HttpR...

12720
来自专栏晓晨的专栏

Entity Framework Core 2.0 使用代码进行自动迁移

16430
来自专栏木宛城主

ASP.NET那点不为人知的事(三)

有了以下的知识: ASP.NET那点不为人知的事(一) ASP.NET那点不为人知的事(二) 想必开发一个小型服务器以不是问题了,功能补复杂,能够响应...

21690
来自专栏Porschev[钟慰]的专栏

【2013年】开发常见问题回顾(一)

记录开发中遇到的和别人问的较多的问题.... IE10中LinkButton不可用     这应该是2013年初遇到的一个BUG,当使用Asp.Net开发Web...

29250
来自专栏菩提树下的杨过

.net中的认证(authentication)与授权(authorization)

注:这篇文章主要给新手看的,老手们可能会觉得没啥营养,就请绕过吧。 “认证”与“授权”是几乎所有系统中都会涉及的概念,通俗点讲: 认证(authenticat...

377100

扫码关注云+社区

领取腾讯云代金券