Castle.DynamicProxy 和 Simple Injector 基于属性的拦截

Attribute based interception with Castle.DynamicProxy and Simple Injector

我在我的项目中使用了 Simple Injector。为了将 Simple Injector 与 Castle.DynamicProxy 集成,我正在使用 this example.

我有以下属性:

public class MyLogAttribute : Attribute { // some code. }

public class MyTimerAttribute : Attribute { // some code. }

然后这些属性应用于我的服务中的方法。

public interface IMyService
{
    void Do();
}

public class MyService : IMyService
{
    [MyLog, MyTimer]
    public void Do() { // some code. }
}

在我的拦截器中,我尝试使用以下代码获取应用于方法的自定义属性:

public class MyLogIntercept : Castle.DynamicProxy.IInterceptor
{
    public void Intercept(Castle.DynamicProxy.IInvocation invocation)
    {
          var method = invocation.GetConcreteMethod();

          method = invocation.InvocationTarget.GetType().
                        GetMethod(method.Name);

          var attribute = method.GetCustomAttribute<MyLogAttribute>();

          if(attribute != null)   
          { 
             // some code. 
          }
          else
            invocation.Proceed(); 
    }
 }

public class MyTimerIntercept : Castle.DynamicProxy.IInterceptor
{
    public void Intercept(Castle.DynamicProxy.IInvocation invocation)
    {
          var method = invocation.GetConcreteMethod();

          method = invocation.InvocationTarget.GetType().
                       GetMethod(method.Name);

          var attribute = method.GetCustomAttribute<MyTimerAttribute>();

          if(attribute != null)   
          { 
             // some code. 
          }
          else
            invocation.Proceed();   
     }
 }

这些拦截器使用以下代码注册:

container.InterceptWith<MyLogIntercept>(
     type => type == typeof(IMyService));

container.InterceptWith<MyTimerIntercept>(
     type => type == typeof(IMyService));

我的问题是,当我在 Intercept() 方法中尝试获取自定义属性时,我得到 null (attribute == null)。我怎样才能获得我的自定义属性?

P.S。如果为我的服务注册了一个拦截MyTimerInterceptMyLogIntercept它不符合),在Intercept()方法中我可以获得自定义属性成功attribute != null),但是如果两个拦截器都注册了我有问题(attribute == null)。

P.S。我正在使用 Castle.Core 3.3.3

外层拦截器装饰了第二个拦截器,所以当你调用invocation.InvocationTarget.GetType()时,你可能得不到typeof(MyService),但类型变成了Castle.Proxy.IMyServiceProxy。这种类型显然没有声明属性,所以这就是为什么它 returns null.

老实说,我不知道如何解决这个问题,但这是我更喜欢使用 SOLID 代码并使用装饰器而不是使用拦截器的众多原因之一。

使用 SOLID 代码,问题就完全消失了,因为您的服务通常只有 one method,这消除了使用属性标记方法的需要。当你这样做时,你的装饰器或拦截器可以只应用于拦截接口的所有内容(因为它只有一个方法)并且你不必像这样搞砸属性。

如果您开始使用通用接口(例如 ICommandHandler<T> abstraction and IQueryHandler<T> 抽象),则可以将装饰器应用于广泛的实现,从而无需编写拦截器。装饰器消除了依赖外部库(例如 Castle Dynamic Proxy 甚至您的 DI 库)的需要,这使您的代码更加简洁且更易于维护。

正如史蒂文上面所写,这段代码:

 var method = invocation.GetConcreteMethod();

 method = invocation.InvocationTarget.GetType().
    GetMethod(method.Name);

获取代理类型的方法。

获取real类型的方法,可以使用MethodInvocationTarget 属性:

method = invocation.MethodInvocationTarget;