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


    在上一节,我们将静态实现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("*** Begin program - logging with dynamic proxy ");
          // 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(" End program - logging with dynamic proxy ***");
          Console.ReadLine();
        }


    运行结果,如下:

    image

    正如你所看到的,你已经创建一个动态代理,允许添加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(
        "*** Begin program - logging and authentication ");
          Console.WriteLine(" Running 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(" Running as user");
          Thread.CurrentPrincipal =
        new GenericPrincipal(new GenericIdentity("NormalUser"),
        new string[] { });
          customerRepository.Add(customer);
          customerRepository.Update(customer);
          customerRepository.Delete(customer);
          Console.WriteLine(
        " End program - logging and authentication ***");
          Console.ReadLine();
        }


    运行结果如下

    image

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

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

    AOP参考


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

  • 相关阅读:
    字符串函数之strncat
    1的数目_扩展问题
    关于虚函数(多态)与继承的一道搜狗笔试题
    给定两个正整数(二进制形式表示)A和B,问把A变为B需要改变多少位(bit)?也就是说,整数A和B的二进制表示中有多少位是不同的?
    字符串函数之strcmp
    字符串函数之strchr
    1的数目
    linux scp 远程获取文件
    scala之helloworld
    scala0011
  • 原文地址:https://www.cnblogs.com/DripRoad/p/5596687.html
Copyright © 2020-2023  润新知