订购Postsharp Aspects执行

时间:2014-06-20 15:14:50

标签: c# visual-studio-2012 aop postsharp

好的,这可能会变得冗长。我想做两件事:

  • 我想拥有一个通过保存每个调用被路由到的另一个类的实例来实现接口的类。

  • 我还希望拦截所有方法调用并执行某些操作。

两者都做得很好。结合它们似乎只能在一个执行顺序中起作用,而且正如墨菲所说的那样,它是错误的(至少对我而言)。

我想首先注入组合,这样拦截所有调用也会拦截先前注入的那些。

namespace ConsoleApplication13
{
  using System;
  using System.Reflection;

  using PostSharp;
  using PostSharp.Aspects;
  using PostSharp.Aspects.Dependencies;
  using PostSharp.Extensibility;

  [Serializable]
  [ProvideAspectRole("COMPOSER")]
  public sealed class ComposeAspectAttribute : CompositionAspect
  {
    [NonSerialized]
    private readonly Type interfaceType;

    private readonly Type implementationType;

    public ComposeAspectAttribute(Type interfaceType, Type implementationType)
    {
      this.interfaceType = interfaceType;
      this.implementationType = implementationType;
    }

    // Invoked at build time. We return the interface we want to implement. 
    protected override Type[] GetPublicInterfaces(Type targetType)
    {
      return new[] { this.interfaceType };
    }

    // Invoked at run time. 
    public override object CreateImplementationObject(AdviceArgs args)
    {
      return Activator.CreateInstance(this.implementationType);
    }
  }

  [Serializable]
  [ProvideAspectRole("INTERCEPTOR")]
  [MulticastAttributeUsage(MulticastTargets.Method)]
  [AspectRoleDependency(AspectDependencyAction.Order, AspectDependencyPosition.After, "COMPOSER")]
  public sealed class InterceptAspectAttribute : MethodInterceptionAspect
  {
    public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
    {
      base.CompileTimeInitialize(method, aspectInfo);

      // Warning in VS output
      Message.Write(method, SeverityType.Warning, "XXX", "Method: " + method.Name);
    }

    public override void OnInvoke(MethodInterceptionArgs args)
    {
      Console.WriteLine("Intercepted before");
      args.Proceed();
      Console.WriteLine("Intercepted after");
    }
  }

  interface ITest
  {
    void Call();
  }

  class TestImpl : ITest
  {
    public void Call()
    {
      Console.WriteLine("CALL remote implemented");
    }
  }

  [InterceptAspect(AspectPriority = 1)]
  [ComposeAspect(typeof(ITest), typeof(TestImpl), AspectPriority = 2)]
  class Test
  {
    // this should, after compilation, have all methods of ITest, implemented through an instance of TestImpl, which get intercepted before TestImpl is called

    public void CallLocalImplementedTest()
    {
      Console.WriteLine("CALL local implemented");
    }
  }


  class Program
  {
    static void Main()
    {
      var test = new Test();

      ITest t = Post.Cast<Test, ITest>(test);

      Console.WriteLine("TEST #1");
      t.Call();

      Console.WriteLine("TEST #2");
      test.CallLocalImplementedTest();

      Console.ReadLine();
    }
  }
}

我试图通过

来影响这两个方面的执行顺序
  • AspectRoleDependency,使拦截器依赖于首先运行的作曲家

  • AspectPriority,也让作曲家先跑。

因为测试总是产生

TEST #1
CALL remote implemented

TEST #2
Intercepted before
CALL local implemented
Intercepted after
它显然不起作用。你有一个线索,为什么我的执行命令没有改变?我做错了什么,我错过了文档中的细节吗?我还能做些什么来拦截我注射成分的方法呢?

1 个答案:

答案 0 :(得分:2)

根据当前方面和您当前的设置,您无法获得所需的结果。

问题在于Postsharp的工作方式:IL会在一步中挥舞IL并且只将InterceptAspect应用于在原始编译时出现的方法,所以它不会查看使用ComposeAspect添加的新界面实现。

因此,接受或提供角色,优先级或其他配置的顺序不会对此有所帮助。

一种解决方法是在注入的InterceptAspect类中添加TestImpl

[InterceptAspect]
class TestImpl : ITest
  {
    public void Call()
    {
      Console.WriteLine("CALL remote implemented");
    }
  }

在这种情况下,将直接添加日志记录逻辑TestImpl,因此这些方法将包含将其组合到Test类中的日志记录。

或者,如果您没有标记每个实现,您可以将您的方面放在界面本身上:

[InterceptAspect(AttributeInheritance = MulticastInheritance.Multicast)]
interface ITest
{
   void Call();
}