`
joerong666
  • 浏览: 418372 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

使用PostSharp进行AOP框架设计:一个简单的原型

阅读更多

AOP已经不是一个什么新名词了,在博客园使用关键字搜索可以查出n多条关于AOP的介绍,这里就不再赘述了。

Bruce Zhang's Blog里面有很多关于AOP介绍及其在.net下实现研究,总觉得如果什么都从头来写难免有自造轮子的嫌疑,但是目前也没有很成熟的AOP框架让我们能轻松完成基于AOP架构,不过一直以来都在关注的PostSharp开源项目日趋成熟,目前已发布了PostSharp 1.0 (Beta release 3)。即使如此,也还没能到应用到产品上的时候。

前段时间一直在封装一个权限系统,时常为如何给调用方提供一个良好的编程接口烦恼,加之前前段时间考虑的日志、异常接管、事务、缓存等等一些横向组件的架构分析,自然就想用AOP技术实现,但是由于实现难度实在不小作罢;这两天又重新学习研究了PostSharp的架构与实现思想,觉得还是尝试一下,将其融入现有框架;

早在年初就有不少前辈大师就如何使用这个东西撰写过文章,如Q.yuhenPostSharp - Lightweight Aspect-Oriented System该仁兄下面见解很到位:

和以往基于 Dynamic Proxy 方式与 AOP 解决方案做个比较。

  • 由于采用 MSIL Injection,因此静态代码注入的执行效率要高于使用 Reflection Emit。
  • 使用 MSBuild Task,使得开发人员可以像使用编译器内置 Attribute 那样使用 AOP。
  • 可以拦截任意方法,而 Dynamic Proxy 方式的 AOP 往往采取继承方式来拦截 Virtual 方法。
  • 拥有更多的控制权。包括中断执行流程,修改参数和返回值等等。
  • 还可以拦截 Field Access、Exception 等操作。
  • 无需将对象创建代码改成 "new proxy()",更加透明。
  • 可以使用通配符进行多重拦截匹配。
  • 静态注入带来的问题更多的是注入代码的质量和调试复杂度。

另外有一老外的Using AOP and PostSharp to Enhance Your CodeAB两部分,相当精彩,本文就是在参考这两篇好文的基础上做的。

我们假设有这么个场景,其实这也是实际业务中很常见的处理方式:有一定单管理模块,具备新增、删除两功能,我们在新增删除的时候必须校验权限,在删除的时候还必须记录日志,出现异常了还必须捕捉并记录异常;

按以前的写法我们可能很麻烦,我们要如此这般的写:

<!---->public class Orders
    {
        
public bool Add(string id, string orderName)
        {
            
try
            {
                
if (User.AddEnable)
                {
                    
//TODO:新增订单的实现
                    Console.WriteLine("正在执行新增订单方法的操作,回车继续……");
                    Console.ReadLine();
                    Console.WriteLine(
"您添加订单成功:编号:{0},名称:{1}", id, orderName);
                    
return true;
                }
                
else
                {
                    
//
                }
            }
            
catch (Exception)
            {
                
//TODO:记录异常的实现
                throw;
            }

            
return true;

        }

        
public bool Delete(string id)
        {
            
try
            {
                
if (User.DeleteEnable)
                {
                    
//TODO:删除订单的实现
                    Console.WriteLine("您删除订单成功:编号:{0}", id);
                }
                
else
                {
                    
//
                }

            }
            
catch (Exception)
            {
                
//TODO:记录异常的实现
                throw;
            }

            
return true;
        }

 

这种写的弊端我就不多说了,有很多先驱都阐述过……

我要演示的是采用AOP技术的框架原型实现:

首先我们应该安装PostSharp(一定要安装要不能没办法注入处理代码)

然后我们实现Orders对象

<!---->using System;

namespace PostSharp.Demo
{
    
public class Orders
    {
        [Permission]
        [Exception]
        
public bool Add(string id, string orderName)
        {
            Console.WriteLine(
"正在执行新增订单方法的操作,回车继续……");
            Console.ReadLine();
            Console.WriteLine(
"您添加订单成功:编号:{0},名称:{1}", id, orderName);
            
return true;
        }

        [Logger]
        [Permission]
        [Exception]
        
public bool Delete(string id)
        {
            Console.WriteLine(
"您删除订单成功:编号:{0}", id);

            
return true;
        }
    }
}

当然还要模拟一个用户资格认证

 

<!---->namespace PostSharp.Demo
{
    
/// <summary>
    
/// 静态的用户对象,用于存放当前登录用户,成员资格
    
/// </summary>
    public static class User
    {
        
private static string _userId;

        
public static string UserId
        {
            
get { return _userId; }
            
set { _userId = value; }
        }

        
public static bool AddEnable
        {
            
get
            {
                
return (_userId.ToLower() == "admin");
            }
        }

        
public static bool DeleteEnable
        {
            
get
            {
                
return (_userId.ToLower() == "admin");
            }
        }
    }
}


再然后我们实现权限控制方面PermissionAttribute,日志方面LoggerAttribute,异常处理方面ExceptionAttribute……

PermissionAttribute

<!---->using System;
using PostSharp.Laos;

namespace PostSharp.Demo
{
    [Serializable]
    [global::System.AttributeUsage(AttributeTargets.All, Inherited 
= true, AllowMultiple = false)]
    
public class PermissionAttribute : OnMethodBoundaryAspect
    {
        
public override void OnEntry(MethodExecutionEventArgs eventArgs)
        {
            
if (!User.AddEnable)
            {
                Console.WriteLine(
"用户:【{0}】没有权限:【{1}】", User.UserId, eventArgs.Method);
                eventArgs.FlowBehavior 
= FlowBehavior.Return;
            }

        }
    }
}


LoggerAttribute

<!---->using System;
using PostSharp.Laos;

namespace PostSharp.Demo
{
    [Serializable]
    [global::System.AttributeUsage(AttributeTargets.All, Inherited 
= true, AllowMultiple = false)]
    
public sealed class LoggerAttribute : OnMethodInvocationAspect
    {
        
public override void OnInvocation(MethodInvocationEventArgs eventArgs)
        {
            DateTime time 
= DateTime.Now;
            
string log = "时间:{0},操作人员:{1},操作:{2}!";

            
object[] arg = eventArgs.GetArguments();

            log 
= String.Format(log, time, User.UserId, "删除Id为" + arg[0].ToString() + "的订单!");

            System.IO.File.WriteAllText(
"C:\\Log.Txt", log);
        }
    }
}


ExceptionAttribute

<!---->using System;
using PostSharp.Laos;

namespace PostSharp.Demo
{
    [Serializable]
    [global::System.AttributeUsage(AttributeTargets.All, Inherited 
= true, AllowMultiple = false)]
    
public class ExceptionAttribute : OnExceptionAspect
    {
        
public override void OnException(MethodExecutionEventArgs eventArgs)
        {
            Console.WriteLine(
"程序出现异常:{0}", eventArgs.Exception.Message);
            eventArgs.FlowBehavior 
= FlowBehavior.Return;
        }
    }
}


然后再用控制台程序测试下能不能成功

<!---->Orders order = new Orders();
            Console.WriteLine(
"请输入用户名:");
            User.UserId 
= Console.ReadLine();
            Console.WriteLine(
"请输入密码:");
            Console.ReadLine();
            
string id;

            LRedo:
            Console.WriteLine(
"请输入您要执行的操作:新增(A),删除(D),退出(X)");

            
string opt = Console.ReadLine();

            
if (opt.ToLower() == "a")
            {
                Console.WriteLine(
"请输入订单编号:");
                id 
= Console.ReadLine();

                Console.WriteLine(
"请输入订单名称:");
                
string name = Console.ReadLine();
                order.Add(id, name);
            }
            
else if (opt.ToLower() == "d")
            {
                Console.WriteLine(
"请输入订单编号:");
                id 
= Console.ReadLine();
                order.Delete(id);
            }
            
else if (opt.ToLower() == "x")
            {
            }
            
else
            {
                Console.WriteLine(
"您的输入不正确,请重新输入!");
                
goto LRedo;
            }

            Console.WriteLine(
"按任意键退出……");
            Console.ReadLine();


写完这些我们再反编译一下生成的exe文件,发现里面的Orders成了这模样了,神奇了?

反编译后的代码
<!---->public class Orders
{
    
// Methods
    static Orders()
    {
        
if (!~PostSharp~Laos~Implementation.initialized)
        {
            LaosNotInitializedException.Throw();
        }
        
~PostSharp~Laos~Implementation.~targetMethod~1 = methodof(Orders.Add);
        
~PostSharp~Laos~Implementation.~aspect~1.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~1);
        
~PostSharp~Laos~Implementation.~targetMethod~5 = methodof(Orders.Delete);
        
~PostSharp~Laos~Implementation.~aspect~5.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~5);
        
~PostSharp~Laos~Implementation.~targetMethod~4 = methodof(Orders.Delete);
        
~PostSharp~Laos~Implementation.~aspect~4.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~4);
        
~PostSharp~Laos~Implementation.~targetMethod~3 = methodof(Orders.Add);
        
~PostSharp~Laos~Implementation.~aspect~3.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~3);
        
~PostSharp~Laos~Implementation.~targetMethod~2 = methodof(Orders.Delete);
        
~PostSharp~Laos~Implementation.~aspect~2.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~2);
    }

    
private bool ~Delete(string id)
    {
        Console.WriteLine(
"您删除订单成功:编号:{0}", id);
        
return true;
    }

    
public bool Add(string id, string orderName)
    {
        
bool ~returnValue~1;
        MethodExecutionEventArgs 
~laosEventArgs~7;
        
try
        {
            
object[] ~arguments~6 = new object[] { id, orderName };
            
~laosEventArgs~7 = new MethodExecutionEventArgs(methodof(Orders.Add, Orders), this~arguments~6);
            
~PostSharp~Laos~Implementation.~aspect~1.OnEntry(~laosEventArgs~7);
            
if (~laosEventArgs~7.FlowBehavior == FlowBehavior.Return)
            {
                
return (bool~laosEventArgs~7.ReturnValue;
            }
            
try
            {
                Console.WriteLine(
"正在执行新增订单方法的操作,回车继续……");
                Console.ReadLine();
                Console.WriteLine(
"您添加订单成功:编号:{0},名称:{1}", id, orderName);
                
~returnValue~1 = true;
            }
            
catch (Exception ~exception~2)
            {
                
object[] ~arguments~3 = new object[] { id, orderName };
                MethodExecutionEventArgs 
~laosEventArgs~4 = new MethodExecutionEventArgs(methodof(Orders.Add, Orders), this~arguments~3);
                
~laosEventArgs~4.Exception = ~exception~2;
                
~PostSharp~Laos~Implementation.~aspect~3.OnException(~laosEventArgs~4);
                
switch (~laosEventArgs~4.FlowBehavior)
                {
                    
case FlowBehavior.Continue:
                        
goto Label_0145;

                    
case FlowBehavior.Return:
                        
~returnValue~1 = (bool~laosEventArgs~4.ReturnValue;
                        
goto Label_0145;
                }
                
throw;
            }
        Label_0145:
            
~laosEventArgs~7.ReturnValue = ~returnValue~1;
            
~PostSharp~Laos~Implementation.~aspect~1.OnSuccess(~laosEventArgs~7);
            
~returnValue~1 = (bool~laosEventArgs~7.ReturnValue;
        }
        
catch (Exception ~exception~5)
        {
            
~laosEventArgs~7.Exception = ~exception~5;
            
~PostSharp~Laos~Implementation.~aspect~1.OnException(~laosEventArgs~7);
            
switch (~
分享到:
评论

相关推荐

    PostSharp实现AOP 实例

    在.NET环境中,PostSharp是一个强大的AOP框架,它通过编译时织入的方式实现切面,使得切面的应用对代码侵入性更小。 **PostSharp工作原理**: PostSharp在编译期间动态插入额外的代码,这些代码是切面的实现。当...

    10分钟入门AOP:用PostSharp普及一下AOP

    PostSharp作为一个强大的AOP工具,它的工作原理是在编译阶段对代码进行处理,插入切面代码。使用PostSharp,开发者可以通过自定义的属性(Attribute)来声明切面,然后PostSharp会在编译时自动把这些属性转换为实际...

    aop demo PostSharp

    本示例通过 PostSharp 2.0 在一个简单的控制台应用中展示了 AOP 的基本使用。PostSharp 允许我们定义切面并在不修改原有代码的情况下,轻松地添加额外的功能。这有助于保持代码的清晰性和可维护性,尤其对于需要大量...

    [AOP编程框架].Sharpcrafters.PostSharp.v2.0.9.3

    总的来说,PostSharp作为一个强大的AOP框架,为.NET开发者提供了一种优雅的方式来实现横切关注点,提高代码的可维护性和可读性。通过使用这个框架,开发者可以专注于业务逻辑,而把其他非核心功能交给PostSharp自动...

    C# 实现 AOP微型框架

    C#实现AOP微型框架是将面向切面编程(Aspect-Oriented Programming)的理念应用于C#编程中的一个实践。在VS2008环境下开发的这个框架,为开发者提供了一种方便的方式来插入横切关注点,如日志、事务管理、性能监控等...

    C# 实现的AOP框架

    在C#中实现AOP,我们可以使用.NET提供的System.Reflection.Emit或System.Linq.Expressions库来动态生成代理类,或者使用IL weaving工具如PostSharp进行编译时织入。同时,我们也可以利用.NET Framework中的`System....

    PostSharp1.5安装包(X86和X64)以及示例

    PostSharp使用静态织入方式实现AOP,其连接点非常丰富,使用简单,而且相对其它一些.NET平台上的AOP框架来说,PostSharp较为轻量级,但是功能却一点也不逊色,因此是我比较喜欢的一个AOP框架。更多关于PostSharp的...

    PostSharp 2.1 - Sample Code

    在"PostSharp 2.1 - Sample Code"这个压缩包中,你将找到一系列的示例项目,这些项目展示了如何利用PostSharp进行AOP编程。学习这些示例对于理解如何在C#应用程序中使用PostSharp至关重要。以下是一些关键的知识点:...

    PostSharp 2.0

    PostSharp 2.0是该框架的一个重要版本,带来了诸多改进和新特性。 **面向切面编程(AOP)** 面向切面编程是一种编程范式,旨在解决传统面向对象编程中难以处理的横切关注点问题。在AOP中,代码被组织成核心业务...

    PostSharp2.0.8安装文件

    1. **属性注解(Attribute-Based Aspects)**:PostSharp支持定义和使用自定义的属性,这些属性可以被附加到方法、字段、类等程序元素上,表示一个切面。例如,`[Log]`属性可用于标记需记录日志的方法。 2. **编译...

    C#实现的IOC和AOP框架,供学习

    这个名为“GreeFramOfficial”的压缩包文件,很可能是提供了一个基于C#实现的IOC和AOP框架,供开发者学习和使用。 IOC(Inversion of Control)的核心思想是将对象的创建和管理交给一个容器来处理,而不是由对象...

    PostSharp 4.2 User Manual

    PostSharp是一个面向切面编程(Aspect-Oriented Programming, AOP)框架,允许开发人员通过添加“方面”(aspects)来修改其.NET应用程序的行为。这种技术可以将横切关注点(如日志记录、性能监控、通知机制等)与...

    基于C#语言的BSF.Aop静态AOP织入设计源码框架

    该项目是一款基于C#语言的BSF.Aop静态AOP织入设计源码框架,包含49个文件,包括28个C#源文件、7个DLL库文件、2个项目文件、2个文本文件、1个Git忽略文件、1个用户文件、1个资源文件、1个设置文件、1个可执行文件和1...

    利用C#实现AOP常见的几种方法详解

    面向切面编程(AOP,Aspect Oriented Programming)是一种编程范式,旨在通过将关注点分离,使得系统设计更加模块化。AOP的核心思想是将应用程序的横切关注点(如日志、事务管理、安全检查等)从核心业务逻辑中解耦...

    PostSharp-1.0.7.262-Source.zip

    PostSharp是一款强大的.NET框架下的AOP工具,由Girard Software公司开发。PostSharp的工作原理是通过编译时织入(Compile-Time Weaving)技术,将切面(Aspect)应用到目标代码上,实现了对方法、属性、字段等成员的...

    C#版本AOP注入

    以KingAOP为例,这是一个开源的C# AOP框架,它提供了一种简单的方式来创建和应用切面。通过KingAOP,开发者可以自定义注解,然后在注解标记的方法上应用切面逻辑。这样,业务代码保持简洁,而复杂的逻辑则被移到切面...

    PostSharp_6.1.15_Ultimate-Enterprise-Professional_Downloadly.ir.rar

    6.1.15版本是PostSharp的一个更新,可能包含了性能优化、新功能添加或已知问题修复。 在PostSharp 6.1.15 Ultimate-Enterprise-Professional版本中,我们可以期待以下关键知识点: 1. **面向切面编程(AOP)**:...

    .net平台AOP的实现

    6. **AspectCore**:这是一个轻量级的AOP框架,提供简单易用的API和高性能的AOP实现。它支持多种通知类型和灵活的切点选择器。 在.NET平台上实现AOP,不仅可以提高代码的可维护性和可扩展性,还能让系统设计更加...

Global site tag (gtag.js) - Google Analytics