2014-06-20 4 views
12

Ok, das kann lang werden. Ich versuche, zwei Dinge zu tun:Bestellung von Postsharp Aspekte Ausführung

  • Ich möchte eine Klasse haben, die eine Schnittstelle implementiert durch eine Instanz einer anderen Klasse halten, dass jeder Anruf wird weitergeleitet.

  • Ich möchte auch alle Methodenaufrufe abfangen und etwas tun.

Doing sowohl auf eigene Faust funktioniert super. Sie zu kombinieren, scheint nur in einer Ausführungsreihenfolge zu funktionieren und wie Murphy es hat, ist es das falsche (zumindest für mich).

Ich möchte die Zusammensetzung zuerst injizieren, so dass das Abfangen aller Anrufe auch jene abfangen wird, die zuvor injiziert wurden.

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(); 
    } 
    } 
} 

Ich habe versucht, die Ausführungsreihenfolge der beiden Aspekte zu beeinflussen, indem

  • AspectRoleDependency, die Abfangjäger machen auf dem Komponisten abhängen ersten

  • AspectPriority, auch machen den Komponisten laufen Lauf zuerst.

Da die Tests ergeben immer

TEST #1 
CALL remote implemented 

TEST #2 
Intercepted before 
CALL local implemented 
Intercepted after 

es offensichtlich nicht funktioniert. Hast du eine Ahnung, warum sich meine Ausführungsreihenfolge nicht geändert hat? Habe ich etwas falsch gemacht, habe ich ein Detail in der Dokumentation vermisst? Was kann ich tun, um meine Kompositions-injizierten Methoden abzufangen?

+0

Sie müssen auch den 'InterceptAspect' auf der' TestImpl' Klasse hinzufügen, um Ihr gewünschtes Ergebnis zu erzielen . – nemesv

+0

@nemesv Obwohl das wahrscheinlich funktionieren würde, ist die TestImpl-Klasse manchmal nicht meine Klasse.Ich würde eine Lösung bevorzugen, wo ich TestImpl so lassen kann, wie es ist. – nvoigt

+0

Alternativ können Sie Ihre '[InterceptAspect (AttributeInheritance = MulticastInheritance.Multicast)]' auf der 'ITest'-Schnittstelle selbst setzen. Aber das ist das weiteste, was du bekommen kannst. Das Problem ist, dass Postsharp die IL in einem Schritt winkt und nur die "InterceptAspect" auf die Methoden anwendet, die zur Kompilierzeit vorhanden sind, so dass die neuen Schnittstellenimplementierungen nicht mit dem "ComposeAspect" hinzugefügt werden. Daher sollte der Typ, den Sie mit dem ComposeAspect hinzufügen, bereits den Logging-Code enthalten, der von der InterceptAspect bereitgestellt wird, indem Sie ihn auf die ITest- oder die TestImpl-Klasse setzen. – nemesv

Antwort

2

Mit den aktuellen Aspekten und Ihrem aktuellen Setup können Sie Ihr gewünschtes Ergebnis nicht erreichen.

Das Problem besteht darin, wie Postsharp Arbeit: es ist die IL in einem Schritt winken und es gilt nur die InterceptAspect auf die Methoden, die vorhanden sind, bei Original Kompilierung, damit es nicht die neuen Interface-Implementierungen sehen mit der addierte ComposeAspect.

Also keine Bestellung der akzeptiert oder Bereitstellung von Rollen, Prioritäten oder andere Konfiguration würde hier helfen.

Eine Abhilfe wäre die InterceptAspect auf der injizierten TestImpl Klasse hinzuzufügen:

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

In diesem Fall wird die Logging-Logik TestImpl direkt hinzugefügt werden, so dass diese Methode wird die Protokollierung enthält, wenn es Ihre zusammengesetzt sein wird in Test Klasse.

Oder, wenn Sie nicht jede Implementierung markieren können Sie Ihren Aspekt an der Schnittstelle setzen sich mit:

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