Pokazywanie postów oznaczonych etykietą postsharp. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą postsharp. Pokaż wszystkie posty

niedziela, 29 czerwca 2014

[C#|Visual Studio] AOP: Method Interception

Opakowanie metody możemy wykonać zarówno w Castle.DynamicProxy jak i przez Postsharp. Oba podejścia nieco różnią się od siebie.

W przypadku Castle zakładamy, że będziemy korzystać z kontenera IoC. Mamy prosty interfejs IMyInterface oraz prosty typ MyType. Rozpoczynamy od stworzenia interceptora, który będzie logował zdarzenia. Musi on dziedziczyć po interfejsie IInterceptor z przestrzeni nazw IInterceptor. Interfejs ten wystawia metodę Intercept.

public class LoggingInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Console.WriteLine("On Enter");
        try
        {
            invocation.Proceed();
        }
        catch (Exception)
        {
            Console.WriteLine("On Error");
            throw;
        }
        finally
        {
            Console.WriteLine("On Exit");
        }
    }
}

Pozostaje jeszcze skonfigurować odpowiednio kontener i można korzystać z typu opakowanego w intereceptor.

using (var windsorContainer = new WindsorContainer())
{
    windsorContainer.Register(Component.For<LoggingInterceptor>());
    windsorContainer.Register(Component.For<IMyInterface>()
                                    .ImplementedBy<MyType>()
                                    .Interceptors<LoggingInterceptor>());

    var type = windsorContainer.Resolve<IMyInterface>();

    type.Run();
}

W Postsharpie dziedziczymy po bazowej klasie OnMethodBoundaryAspect, która definiuje potrzebne nam metody wirtualne. Ważne, by nasz aspekt oznaczyć atrybutem Serializable.

[Serializable]
public class LoggingInterceptor2: OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionArgs args)
    {
        Console.WriteLine("On Entry");
        base.OnEntry(args);
    }

    public override void OnException(MethodExecutionArgs args)
    {
        Console.WriteLine("On Error");
        base.OnException(args);
    }

    public override void OnExit(MethodExecutionArgs args)
    {
        Console.WriteLine("On Exit");
        base.OnSuccess(args);
    }
}

Nasza klasa jest atrybutem, który możemy umieścić nad definicją dowolnej metody.

[C#|Visual Studio] AOP: Wprowadzenie

Programowanie aspektowe powstało niejako w odpowiedzi na powtarzające się schematy pisania kodu takie jak na przykład instrukcje try-catch, transakcje, logowanie itd. Aby uniknąć kopiowania kodu wprowadzono komplementarne do OOP pojęcie aspektów. AOP wprowadza kilka ważnych pojęć:
  • cross-cutting concerns - funkcjonalności używane w wielu miejscach w systemie, np. logowanie zdarzeń
  • advice - kod wykonujący cross-cutting concern
  • pointcut - miejsce występowania aspektów (np. wyjście metody abc)
  • tangling - określenie opisujące wymieszanie kodu typu advice z logiką biznesową
  • weaving (dzierganie) - proces wstrzykiwania kodu związanego z aspektem do logiki biznesowej
Cała idea polega na tym, że chcemy oddzielić cross-cutting concerns od właściwej logiki. Często nie wystarczy wydzielenie do nowej klasy, bo mamy np. do czynienia z konstrukcjami języka typu try-catch-finally. AOP daje nam kod czystszy i napisany w bardziej deklaratywny sposób. Programowanie aspektowe zapewnia zachowanie Single Responsibility Principle, a co za tym idzie znacznie ułatwia refaktoryzację. W wielu przypadkach można je porównać do wzorca dekoratora (np. opakowujemy wywołanie metody w dodatkowy kod).

Przykładowe lokalizacje aspektów:
  • przed wywołaniem metody
  • po pomyślnym zakończeniu metody
  • przy rzuceniu wyjątku
  • zawsze po metodzie (wewnątrz bloku finally)

Najpopularniejsze narzędzia związane z  AOP to Postsharp oraz Castle Dynamic Proxy. Postsharp działa na zasadzie postkompilacji modyfikując wytworzone przez Visual Studio assembly. Dodaje on instrukcje IL w wybranych przez nas miejscach. Jest zintegrowany z VS tak, że możemy przeprowadzać dzięki niemu np. walidację postkompilacyjną. Jeżeli assembly nie przejdzie takiej walidacji, to VS zwróci błąd kompilacji.
Instalujemy go NuGetem, przy czym za pełną wersję trzeba zapłacić.



Drugie narzędzie co Castle Dynamic Proxy. Wstrzykiwanie aspektów odbywa się tu runtime-owo i jest powiązane z kontenerami IoC. Odpytując kontener o dany interfejs dostajemy jego implementację opakowaną w kod przerywający wykonanie metody i dodający do niej kod aspektowy. Jest częścią większego frameworka Castle, w którym kontenerem IoC jest Castle Windsor.