Je travaille avec les espaces de noms System.Runtime.Remoting.Proxies
et System.Runtime.Remoting.Messaging
pour AOP en C #. J'essaie de porter mon application de .Net Framework 4.6 vers le noyau dnxcore/dotnet.
Intellisense dit que ces deux espaces de noms ne sont pas disponibles avec mon framework-vesion (netcoreapp1.0/dnxcore50). Une idée si ces deux espaces de noms apparaîtront? ou une idée comment obtenir l'AOP comme avec la classe RealProxy
-?
Je ne veux pas utiliser de bibliothèques tierces - je veux seulement utiliser ce que .Net m'offre.
Il semble que RealProxy ne sera pas disponible sur .NET Core/Standard . Dans le problème, un développeur Microsoft suggère DispatchProxy comme alternative.
De plus, certains frameworks AOP existants peuvent prendre en charge .NET Core déjà ou à l'avenir (comme on le voit dans les commentaires sur la question).
Une alternative est le DispatchProxy
, qui a un merveilleux exemple ici: http://www.c-sharpcorner.com/article/aspect-oriented-programming-in-c-sharp-using- dispatchproxy / .
Si nous simplifions le code, voici ce que nous obtenons:
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");
}
}
Donc, si nous avons un exemple de classe Calculator
avec une interface correspondante (non représentée ici):
public class Calculator : ICalculator
{
public int Add(int a, int b)
{
return a + b;
}
}
on peut simplement l'utiliser comme ça
static void Main(string[] args)
{
var decoratedCalculator = LoggingDecorator<ICalculator>.Create(new Calculator());
decoratedCalculator.Add(3, 5);
Console.ReadKey();
}
Vous pouvez utiliser System.Reflection.DispatchProxy
Ou vos propres implémentations de décorateur simples. Consultez la page Pattern Decorator sur Wikipedia pour des exemples d'implémentation.
Actuellement, dans .NET Core, vous ne pouvez pas utiliser l'injection de constructeur avec DispatchProxy
. Vous devez utiliser la méthode d'usine et la propriété DispatchProxy.Create()
avec une conversion explicite en type de proxy que vous souhaitez utiliser. Pour plus d'informations, consultez DispachProxyTest.cs dans le référentiel .NET Core GitHub.
Voici un exemple de décorateur générique simple qui hérite de 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;
}
}
Et c'est son utilisation:
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);
}
}
Vous pouvez également utiliser une combinaison d'Autofac et de DynamicProxy. Cet article a une belle introduction et des exemples sur la façon de l'accomplir.