RealProxy в ядре dotnet?
Я работаю с пространствами имен System.Runtime.Remoting.Proxies
и System.Runtime.Remoting.Messaging
для AOP в C#.
Я пытаюсь перенести свое приложение с .Net Framework 4.6 на ядро dnxcore/dotnet.
Intellisense говорит, что эти два пространства имен недоступны в моем фреймворке-vesion (netcoreapp1.0 / dnxcore50). Есть идеи, появятся ли эти два пространства имен? или есть идеи, как получить AOP, как с RealProxy
-классом?
Я не хочу использовать сторонние библиотеки - я хочу использовать только то, что предлагает мне .Net.
3 ответа:
Похоже, RealProxy не придет к .NET Core / Standard . В этом выпуске разработчик Microsoft предлагаетDispatchProxy в качестве альтернативы.
Кроме того, некоторые существующие платформы AOP могут поддерживать .NET Core уже или в будущем (как видно из комментариев к вопросу).
Альтернативой является
DispatchProxy
, который имеет замечательный пример здесь: http://www.c-sharpcorner.com/article/aspect-oriented-programming-in-c-sharp-using-dispatchproxy/.Если мы упростим код, то получим следующее:
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"); } }
Итак, если у нас есть пример класса
Calculator
с соответствующим интерфейсом (здесь не показано):public class Calculator : ICalculator { public int Add(int a, int b) { return a + b; } }
Мы можем просто использовать его так
static void Main(string[] args) { var decoratedCalculator = LoggingDecorator<ICalculator>.Create(new Calculator()); decoratedCalculator.Add(3, 5); Console.ReadKey(); }
Вы можете использовать либо
System.Reflection.DispatchProxy
, либо свои собственные простые реализации декоратора. Проверьтешаблон декоратора на странице Википедии для примеров реализации.В настоящее время в .NET Core нельзя использовать инъекцию конструктора с
DispatchProxy
. Вы должны использовать метод фабрикиDispatchProxy.Create()
и инъекцию свойств с явным приведением к типу прокси, который вы хотите использовать. Для получения дополнительной информации проверьте DispachProxyTest.cs в репозитории .NET Core GitHub.Это пример простого универсального декоратор, который наследует
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; } }
И это использование:
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); } }