首页 技术 正文
技术 2022年11月19日
0 收藏 321 点赞 4,574 浏览 5193 个字

在上一节,我们将静态实现AOP,但是对于一个大型项目,要想为每个类,每个方法都去实现AOP ,进行日志记录和权限验证似乎是不可能的。 即使可能对于成百上千个类维护,也是很难维护。所以今天的主题就是如标题所述。

(Real Proxy)真正代理和(Dynamic Proxy)动态代理

Real Proxy 类是个抽象类,定义在 System.Runtime.Remoting.Proxies,定义了代理的一些公共的基本的功能方法。

Dynamic Proxy 类必须继承Real Proxy,通过重写它的调用方法和添加新功能来达到目的。那么 Dynamic Proxy 定义如下:

 

class DynamicProxy<T> : RealProxy
    {
      private readonly T _decorated;
      public DynamicProxy(T decorated)
    : base(typeof(T))
      {
    _decorated = decorated;
      }
      private void Log(string msg, object arg = null)
      {
    Console.ForegroundColor = ConsoleColor.Red;
    Console.WriteLine(msg, arg);
    Console.ResetColor();
      }
      public override IMessage Invoke(IMessage msg)
      {
    var methodCall = msg as IMethodCallMessage;
    var methodInfo = methodCall.MethodBase as MethodInfo;
    Log("In Dynamic Proxy – Before executing ‘{0}’",
      methodCall.MethodName);
    try
    {
      var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
      Log("In Dynamic Proxy – After executing ‘{0}’ ",
    methodCall.MethodName);
      return new ReturnMessage(result, null, 0,
    methodCall.LogicalCallContext, methodCall);
    }
    catch (Exception e)
    {
     Log(string.Format(
       "In Dynamic Proxy- Exception {0} executing ‘{1}’", e),
       methodCall.MethodName);
     return new ReturnMessage(e, methodCall);
    }
      }
    }

为此,我们已经定义好了动态代理类,但是为了使用包装者Repository<T>类, 必须还得使用GetTransparentProxy(他返回一个 IRepository<Customer>实例)方法,每一个方实例的方法的调用将通过代理来调用,也就是说,你可以定义一个Factory 来创建 proxy和返回泛型Repository<T>实例。所以代码类似于定义如下:

 

public class RepositoryFactory
    {
      public static IRepository<T> Create<T>()
      {
    var repository = new Repository<T>();
    var dynamicProxy = new DynamicProxy<IRepository<T>>(repository);
    return dynamicProxy.GetTransparentProxy() as IRepository<T>;
      }
    }

 

接下来,编写控制台代码 大概如下:

    static void Main(string[] args)
    {
      Console.WriteLine("***\r\n Begin program – logging with dynamic proxy\r\n");
      // IRepository<Customer> customerRepository =
      //   new Repository<Customer>();
      // IRepository<Customer> customerRepository =
      //   new LoggerRepository<Customer>(new Repository<Customer>());
      IRepository<Customer> customerRepository =
    RepositoryFactory.Create<Customer>();
      var customer = new Customer
      {
    Id = 1,
    Name = "Customer 1",
    Address = "Address 1"
       ;
      customerRepository.Add(customer);
      customerRepository.Update(customer);
      customerRepository.Delete(customer);
      Console.WriteLine("\r\nEnd program – logging with dynamic proxy\r\n***");
      Console.ReadLine();
    }

 

运行结果,如下:

.Net 框架实现AOP(动态代理实现AOP,本文为翻译)

正如你所看到的,你已经创建一个动态代理,允许添加AOP代码,不需要重复。如果你想添加一个新的方面,现在你只需要创建一个新的类,继承Real Proxy并使用它来装饰第一个代理。如果你的老板要你,要求你添加授权代码,并且只有管理员才可以访问存储库,您可以创建一个新的代理,代码如下:

 

class AuthenticationProxy<T> : RealProxy
    {
      private readonly T _decorated;
      public AuthenticationProxy(T decorated)
    : base(typeof(T))
      {
    _decorated = decorated;
      }
      private void Log(string msg, object arg = null)
      {
    Console.ForegroundColor = ConsoleColor.Green;
    Console.WriteLine(msg, arg);
    Console.ResetColor();
      }
      public override IMessage Invoke(IMessage msg)
      {
    var methodCall = msg as IMethodCallMessage;
    var methodInfo = methodCall.MethodBase as MethodInfo;
    if (Thread.CurrentPrincipal.IsInRole("ADMIN"))
    {
      try
      {
    Log("User authenticated – You can execute ‘{0}’ ",
      methodCall.MethodName);
    var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
    return new ReturnMessage(result, null, 0,
      methodCall.LogicalCallContext, methodCall);
      }
      catch (Exception e)
      {
    Log(string.Format(
      "User authenticated – Exception {0} executing ‘{1}’", e),
      methodCall.MethodName);
    return new ReturnMessage(e, methodCall);
      }
    }
    Log("User not authenticated – You can’t execute ‘{0}’ ",
      methodCall.MethodName);
    return new ReturnMessage(null, null, 0,
      methodCall.LogicalCallContext, methodCall);
      }
    }

所以repository工厂必须更改实现两个代理,代码如下:

    public class RepositoryFactory
    {
      public static IRepository<TCreate<T>()
      {
    var repository = new Repository<T>();
    var decoratedRepository =
      (IRepository<T>)new DynamicProxy<IRepository<T>>(
      repository).GetTransparentProxy();
    // Create a dynamic proxy for the class already decorated
    decoratedRepository =
      (IRepository<T>)new AuthenticationProxy<IRepository<T>>(
      decoratedRepository).GetTransparentProxy();
    return decoratedRepository;
      }
    }

控制台程序,需要更改代码,如下所示:

    static void Main(string[] args)
    {
      Console.WriteLine(
    "***\r\n Begin program – logging and authentication\r\n");
      Console.WriteLine("\r\nRunning as admin");
      Thread.CurrentPrincipal =
    new GenericPrincipal(new GenericIdentity("Administrator"),
    new[] { "ADMIN" });
      IRepository<Customer> customerRepository =
    RepositoryFactory.Create<Customer>();
      var customer = new Customer
      {
    Id = 1,
    Name = "Customer 1",
    Address = "Address 1"
      };
      customerRepository.Add(customer);
      customerRepository.Update(customer);
      customerRepository.Delete(customer);
      Console.WriteLine("\r\nRunning as user");
      Thread.CurrentPrincipal =
    new GenericPrincipal(new GenericIdentity("NormalUser"),
    new string[] { });
      customerRepository.Add(customer);
      customerRepository.Update(customer);
      customerRepository.Delete(customer);
      Console.WriteLine(
    "\r\nEnd program – logging and authentication\r\n***");
      Console.ReadLine();
    }

 

运行结果如下

.Net 框架实现AOP(动态代理实现AOP,本文为翻译)

到此为止就 全部实现动态代理实现AOP.

下一节,我们讲继续讲Aop之方法过滤。

AOP参考

本文翻译自 :https://msdn.microsoft.com/en-us/magazine/dn574804.aspx(面向切面编程)

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,120
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,592
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,437
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,208
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,844
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,929