dotnet 核心中的 RealProxy?
RealProxy in dotnet core?
我正在为 C# 中的 AOP 使用命名空间 System.Runtime.Remoting.Proxies
和 System.Runtime.Remoting.Messaging
。
我正在尝试将我的应用程序从 .Net Framework 4.6 移植到 dnxcore/dotnet 核心。
Intellisense 说,这两个命名空间不适用于我的框架版本 (netcoreapp1.0 / dnxcore50)。知道这两个名称空间是否会出现吗?或者知道如何像 RealProxy
-class 一样获得 AOP?
我不想使用第 3 方库 - 我只想使用 .Net 提供的内容。
It looks like RealProxy won't come to .NET Core/Standard. In the issue, a Microsoft developer suggests 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");
}
}
因此,如果我们有一个示例 class 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
或您自己的简单装饰器实现。查看维基百科上的 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);
}
}
可以使用支持.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/
我正在为 C# 中的 AOP 使用命名空间 System.Runtime.Remoting.Proxies
和 System.Runtime.Remoting.Messaging
。
我正在尝试将我的应用程序从 .Net Framework 4.6 移植到 dnxcore/dotnet 核心。
Intellisense 说,这两个命名空间不适用于我的框架版本 (netcoreapp1.0 / dnxcore50)。知道这两个名称空间是否会出现吗?或者知道如何像 RealProxy
-class 一样获得 AOP?
我不想使用第 3 方库 - 我只想使用 .Net 提供的内容。
It looks like RealProxy won't come to .NET Core/Standard. In the issue, a Microsoft developer suggests 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");
}
}
因此,如果我们有一个示例 class 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
或您自己的简单装饰器实现。查看维基百科上的 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);
}
}
可以使用支持.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/