基于微软企业库的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
即可下载 

时间: 2024-10-23 20:27:47

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

基于微软RDLC报表控件示例(含源码)

      五一放假,研究了下RDLC,之前一直有人说如何强大?研究之后才发现,确实很强大.微软的这套东西,感觉是借鉴了Sybase的数据窗口,配置方式大同小异咯.我们现在看看这套东西如何使用?       有句话叫:别看广告看疗效,这里我在举两个简单的例子,如图-1和图-2所示.       示例一:点击功能系统名称链接字段,会跳转到图-2所示的功能系统下所包含的功能模块列表. 图-1 图-2       我们看看是如何制作出来的?这里我使用的是VS05版本,VS08当然也可以的.新建报表文件

在数据库访问项目中使用微软企业库Enterprise Library,实现多种数据库的支持

在我们开发很多项目中,数据访问都是必不可少的,有的需要访问Oracle.SQLServer.Mysql这些常规的数据库,也有可能访问SQLite.Access,或者一些我们可能不常用的PostgreSQL.IBM DB2.或者国产达梦数据库等等,这些数据库的共同特点是关系型数据库,基本上开发的模型都差不多,不过如果我们基于ADO.NET的基础上进行开发的话,那么各种数据库都有自己不同的数据库操作对象,微软企业库Enterprise Library是基于这些不同数据库的操作做的抽象模型,适合多数据

数据库-在用微软企业库连接SqlServerCe不成功

问题描述 在用微软企业库连接SqlServerCe不成功 我在项目中用微软企业库的方式连接SqlServer Ce不成功,但是连接MSSQL没问题:我想知道微软企业库是否能连接SqlServer Ce: 配置文件 <add name=""CS_Telecom"" connectionString=""Data Source=D:EWS_ProjectDataBaseMyDatabase#1.sdf;Password=123456"

微软企业库删除效率问题

问题描述 方法一DataTabledt=silkPlanDataset.MT_PL_ZS_TASK_DEL.GetChanges(DataRowState.Deleted);if(dt!=null){//dt.RejectChanges();DateTimedtime1=DateTime.Now;DataColumn[]keys=newDataColumn[1];keys[0]=dt.Columns["ZS_TASK_DEL_ID"];dt.PrimaryKey=keys;//指定主键

使用微软企业库EnterpriseLibary访问SQLite数据库

SQLite是一个小型的C程序库,实现了独立的,可嵌入的,零配置的SQL数据库引擎,SQLite用的非常广泛,支持通用的SQL92标准,支持事务操作, 支持最大可达2T的数据库,在小型数据库使用性能上由于微软的Access数据库等等特点. 由于默认的微软企业库EnterpriseLibary不支持 SQLite的数据库访问,因此需要在 企业库EnterpriseLibary中访问这种数据库的话,需要使用一个企业库的扩展类库,该类库可以http://entlibcontrib.codeplex.c

基于JavaScript实现添加到购物车效果附源码下载_javascript技巧

我们有很多种方法实现将商品添加到购物车,通常的做法是点击"添加到购物车"按钮,会跳转到购物车,在购物车里可以点击"结算"按钮进行结算.而今天我给大家介绍一个更友好的解决方案. 查看演示 下载源码 默认情况下,购物车是隐藏不可见的,当用户点击添加到购物车按钮后,商品信息会添加到购物车,购物车会以按钮的形式出现在页面右下角,点击按钮则会展开购物车,显示购物车中的商品信息,同时也可以对购物车中的商品进行删除或者结算等操作.用户也可以暂时关闭购物车继续购物. HTML结构

基于android的无线视频监控,使用源码可是在pc端显示不了

问题描述 基于android的无线视频监控,使用源码可是在pc端显示不了 http://www.cnblogs.com/feifei1010/archive/2012/08/31/2664939.html在这里可以下载到源码这个是pc端开启服务器这个是android上运行不管是我输入0.0.0.0 还是127.0.0.1 我在pc端的程序看不到视频接入 请大神给予指导 谢谢了 解决方案 http://wenku.baidu.com/link?url=QOLtRQ2FoJRl80QAKsz8OaU

c++ directx-求 基于c++的DirectX 11 3D 综合实例 源码

问题描述 求 基于c++的DirectX 11 3D 综合实例 源码 如图,包含天空盒,四种光照,线框模式开关,雾化,镜面,反射,法线映射,着色体,曲面细分. 不是全都有也可以,最起码有五个. 急求,三天内急求,急急急,谢谢了 解决方案 可以尝试和这位博主交流:http://blog.csdn.net/xoyojank/article/category/337624/2 解决方案二: http://download.csdn.net/album/detail/885 解决方案三: [Direct

android 编程时,如何在Eclipse中查看Android源码或者第三方组件包源码

相信大多数人都知道怎么在eclipse中看android源码,但是在eclipse中看第三方源码的方法呢,我查看到这篇博文之前我不知道,可能是我才疏学浅,可能很多大牛都知道了,我在这里还是转过来,希望能给不会的人一些帮助. 转自:http://blog.csdn.net/cjjky/article/details/6535426 在学习过程中如果经常阅读源码,理解程度会比较深,学习效率也会比较高,那么如何方便快捷的阅读Android源码? 如何查看Android源码[以Android2.2为例]