【问题标题】:RealProxy in dotnet core?dotnet核心中的RealProxy?
【发布时间】:2016-11-22 21:25:48
【问题描述】:

我正在为 C# 中的 AOP 使用命名空间 System.Runtime.Remoting.ProxiesSystem.Runtime.Remoting.Messaging。 我正在尝试将我的应用程序从 .Net Framework 4.6 移植到 dnxcore/dotnet core。

Intellisense 说,这两个命名空间不适用于我的 framework-vesion (netcoreapp1.0 / dnxcore50)。知道这两个命名空间是否会出现吗?或者知道如何像RealProxy-class 一样获得 AOP?

我不想使用 3rd-party-libraries - 我只想使用 .Net 提供给我的东西。

【问题讨论】:

  • 你找到解决方法了吗???
  • @RafaelEnriquez 直到今天还没有在 asp net core 1 中实现。也许是 1.1 或 1.2。当我找到一些东西时,我会在这里发布答案:)
  • 那么有什么解决办法呢? nuget.org/packages/System.Runtime 是否与 .NetCore 兼容?
  • @HaseebJadoon 我没有使用当前版本的 netstandard/netcore/whatevernet 进行测试——我为 AOP 编写了自己的实现。这篇文章很快就迎来了他的第一个生日 - 但请随时使用当前版本进行测试,并让我们知道它是否有效:)
  • @MatthiasBurger 我正在将 spring.net 移植到 .net 标准。今天 di/ioc/aop 正在工作。一些细节你会看到github.com/spring-projects/spring-net/issues/133

标签: c# aop dnx .net-core


【解决方案1】:

It looks like RealProxy won't come to .NET Core/Standard。在本期中,一位微软开发人员建议将DispatchProxy 作为替代方案。

此外,一些现有的 AOP 框架可能已经或将来支持 .NET Core(如问题中的 cmets 所示)。

另一种选择是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();
}

【讨论】:

  • 所以DispatchProxy 是现在要走的路。感谢您分享您的知识。 :)
  • 只是评论 targetMethod.Invoke 使用反射并且速度很慢。此外,如果不跳过一些涉及更慢反射的箍,它也不适用于异步方法。该方法有效,但确实不太理想。
  • 伤心。 DispatchProxy 只能用于接口,不能用于类。
【解决方案2】:

您可以使用System.Reflection.DispatchProxy 或您自己的简单装饰器实现。查看 Wikipedia 上的 Decorator pattern 页面以获取实现示例。

目前在 .NET Core 中,您不能将构造函数注入与 DispatchProxy 一起使用。您必须使用 DispatchProxy.Create() 工厂方法和属性注入,并将显式转换为您要使用的代理类型。有关更多信息,请查看 .NET Core GitHub 存储库中的 DispachProxyTest.cs

这是一个简单的继承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);
    }
}

【讨论】:

    【解决方案3】:

    你可以使用支持.Net Core的Castle.Core

    using Castle.DynamicProxy;
    using System;
    using System.Reflection;
    
    namespace ObservableProxyTest
    {
        class Program
        {
            private static readonly ProxyGenerator Generator = new ProxyGenerator();
    
            static void Main(string[] args)
            {
                var obj = new MyEntity()
                {
                    Name = "My name",
                    Description = "My description"
                };
    
                var proxy = Generator.CreateClassProxyWithTarget(obj, new ObservableInterceptor());
    
                Console.WriteLine("Object changed: " + proxy.IsChanged);
    
                proxy.Name = "My name 2";
                proxy.Description = "My description 2";
    
                Console.WriteLine("Object changed: " + proxy.IsChanged);
    
                Console.ReadLine();
            }
        }
    
        internal interface IObservable
        {
            bool IsChanged { get; }
            void SetChanged();
        }
    
        public abstract class BaseEntity : IObservable
        {
            public virtual bool IsChanged { get; protected set; }
    
            public void SetChanged()
            {
                IsChanged = true;
            }
        }
    
        public class MyEntity : BaseEntity
        {
            // Virtual keyword is very important
            public virtual string Name { get; set; }
            public virtual string Description { get; set; }
        }
    
        internal class ObservableInterceptor : IInterceptor
        {
            public void Intercept(IInvocation invocation)
            {
                var observable = invocation.InvocationTarget as IObservable;
                if (observable != null && !observable.IsChanged && IsSetter(invocation.Method))
                {
                    observable.SetChanged();
                }
                invocation.Proceed();
            }
    
            private bool IsSetter(MethodInfo method)
            {
                return method.IsSpecialName && method.Name.StartsWith("set_", StringComparison.OrdinalIgnoreCase);
            }
        }
    
    }
    

    还请阅读非常好的文章:https://fullboarllc.com/change-tracking-structuremap-dynamicproxy/

    【讨论】:

      猜你喜欢
      • 2019-05-29
      • 1970-01-01
      • 2013-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-25
      相关资源
      最近更新 更多