2016-07-19 34 views
18

Pracuję z przestrzeniami nazw System.Runtime.Remoting.Proxies i dla AOP w C#. Próbuję przenieść moją aplikację z .Net Framework 4.6 do jądra dnxcore/dotnet.RealProxy w rdzeniu dotnet?

Intellisense mówi, że te dwie przestrzenie nazw nie są dostępne w mojej wersji szkieletowej (netcoreapp1.0/dnxcore50). Masz pomysł, czy te dwie przestrzenie nazw się pojawią? lub jakikolwiek pomysł jak uzyskać AOP z klasy RealProxy?

Nie chcę korzystać z bibliotek stron trzecich - chcę używać tylko tego, co oferuje mi .Net.

+0

czy znalazłeś rozwiązanie tego problemu ??? –

+1

@RafaelEnriquez do dziś nie ma żadnego zaimplementowanego w jądrze sieciowym asp 1. Może z 1.1 lub 1.2. kiedy coś znalazłem, opublikuję odpowiedź :) –

+0

Jakie jest więc rozwiązanie? Czy https://www.nuget.org/packages/System.Runtime/ jest kompatybilny z .NetCore? –

Odpowiedz

9

It looks like RealProxy won't come to .NET Core/Standard. W tym wydaniu deweloper Microsoft sugeruje alternatywę w postaci DispatchProxy.

Ponadto niektóre istniejące ramy AOP mogą obsługiwać .NET Core już lub w przyszłości (jak widać w komentarzach do pytania).

Alternatywą jest DispatchProxy, która ma wspaniały przykład tutaj: http://www.c-sharpcorner.com/article/aspect-oriented-programming-in-c-sharp-using-dispatchproxy/.

Gdybyśmy uprościć kod, to co mamy:

public class LoggingDecorator<T> : DispatchProxy 
{ 
    private T _decorated; 

    protected override object Invoke(MethodInfo targetMethod, object[] args) 
    { 
     try 
     { 
      LogBefore(targetMethod, args); 

      var result = targetMethod.Invoke(_decorated, args); 

      LogAfter(targetMethod, args, result); 
      return result; 
     } 
     catch (Exception ex) when (ex is TargetInvocationException) 
     { 
      LogException(ex.InnerException ?? ex, targetMethod); 
      throw ex.InnerException ?? ex; 
     } 
    } 

    public static T Create(T decorated) 
    { 
     object proxy = Create<T, LoggingDecorator<T>>(); 
     ((LoggingDecorator<T>)proxy).SetParameters(decorated); 

     return (T)proxy; 
    } 

    private void SetParameters(T decorated) 
    { 
     if (decorated == null) 
     { 
      throw new ArgumentNullException(nameof(decorated)); 
     } 
     _decorated = decorated; 
    } 

    private void LogException(Exception exception, MethodInfo methodInfo = null) 
    { 
     Console.WriteLine($"Class {_decorated.GetType().FullName}, Method {methodInfo.Name} threw exception:\n{exception}"); 
    } 

    private void LogAfter(MethodInfo methodInfo, object[] args, object result) 
    { 
     Console.WriteLine($"Class {_decorated.GetType().FullName}, Method {methodInfo.Name} executed, Output: {result}"); 
    } 

    private void LogBefore(MethodInfo methodInfo, object[] args) 
    { 
     Console.WriteLine($"Class {_decorated.GetType().FullName}, Method {methodInfo.Name} is executing"); 
    } 
} 

Więc jeśli mamy przykładową klasę Calculator z odpowiednim interfejsem (nie pokazanego tutaj):

public class Calculator : ICalculator 
{ 
    public int Add(int a, int b) 
    { 
     return a + b; 
    } 
} 

możemy po prostu używaj go w ten sposób:

static void Main(string[] args) 
{ 
    var decoratedCalculator = LoggingDecorator<ICalculator>.Create(new Calculator()); 
    decoratedCalculator.Add(3, 5); 
    Console.ReadKey(); 
} 
+0

Tak więc "DispatchProxy" jest teraz drogą do zrobienia. Dziękuję za podzielenie się swoją wiedzą. :) –

4

Możesz użyć albo System.Reflection.DispatchProxy lub własne proste implementacje dekoratorów. Sprawdź stronę Decorator pattern w Wikipedii, gdzie znajdziesz przykłady implementacji.

Obecnie w .NET Core nie można używać wtrysku konstruktora z DispatchProxy. Musisz użyć metody fabrycznej i wtrysku własności z wyraźnym rzutowaniem na typ proxy, którego chcesz użyć. Aby uzyskać więcej informacji, sprawdź numer DispachProxyTest.cs w repozytorium .NET Core GitHub.

To jest przykład prostego generycznego dekoratora, która dziedziczy DispatchProxy:

class GenericDecorator : DispatchProxy 
{ 
    public object Wrapped { get; set; } 
    public Action<MethodInfo, object[]> Start { get; set; } 
    public Action<MethodInfo, object[], object> End { get; set; } 
    protected override object Invoke(MethodInfo targetMethod, object[] args) 
    { 
     Start?.Invoke(targetMethod, args); 
     object result = targetMethod.Invoke(Wrapped, args); 
     End?.Invoke(targetMethod, args, result); 
     return result; 
    } 
} 

I to użycie:

class Program 
{ 
    static void Main(string[] args) 
    { 
     IEcho toWrap = new EchoImpl(); 
     IEcho decorator = DispatchProxy.Create<IEcho, GenericDecorator>(); 
     ((GenericDecorator)decorator).Wrapped = toWrap; 
     ((GenericDecorator)decorator).Start = (tm, a) => Console.WriteLine($"{tm.Name}({string.Join(',', a)}) is started"); 
     ((GenericDecorator)decorator).End = (tm, a, r) => Console.WriteLine($"{tm.Name}({string.Join(',', a)}) is ended with result {r}"); 
     string result = decorator.Echo("Hello"); 
    } 

    class EchoImpl : IEcho 
    { 
     public string Echo(string message) => message; 
    } 

    interface IEcho 
    { 
     string Echo(string message); 
    } 
} 
1

Można również użyć kombinacji Autofac i DynamicProxy. Ten artykuł ma fajne wprowadzenie i przykłady, jak to osiągnąć.

AOP in .Net Core

+1

Nie chciał używać 3rd party: P - ale tak, dziękuję za udostępnienie rozwiązania +1 –