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 24

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

Можно также использовать комбинацию Autofac и DynamicProxy. В этой статье есть хорошее введение и примеры того, как это сделать.

AOP в .Net Core