Unity拦截GetCustomAttribute

时间:2013-06-20 19:59:24

标签: c# unity-container interception getcustomattributes

提前感谢您的帮助! (是的,底部有一个问题)

我正在使用Unity 3.x拦截来执行AOP之前和之后的数据库连接和事务活动。数据库拦截器始终是实例化的,并且事务拦截器是基于CustomAttributeMatchingRule的,都是通过InterfaceInterceptor实现的。我有在TransactionAttribute中设置的属性:

[Transaction(IsolationLevel.ReadUncommitted, NoRollbackFor = new[] { typeof(TestException) })]

作为我在单元测试中使用的一个例子。我想在我的TransactionCallHandler类调用方法中访问它们。我见过一些例子说

var transactionAttribute = input.MethodBase.GetCustomAttribute<TransactionAttribute>(false);

是访问它的方法,但我的事务var为null。 我的结论是正在检查拦截代理类的自定义属性而不是原始的具体实例。

我的工作是反映一直回到类级别,深入挖掘出被拦截的正确方法,并从那里执行get custom属性。

var methods = input
  .Target
  .GetType()
  .GetMethods()
  .Where(m => m.Name == input.MethodBase.Name)
  .Where(m => m.GetCustomAttribute<TransactionAttribute>(false) != null);

(还有大约30行代码,以确保我没有访问错误的方法名称,如果方法有重载;因此性能拖累......)

所以,毕竟,我的问题是: 我没有正确执行反射吗? 我应该报告Unity中的错误吗?

这是我的容器定义:

Container = new UnityContainer();
Container.AddNewExtension<Interception>();

Container.RegisterType<IMockUseDefaultConnectionString, MockUseDefaultConnectionString>(
  new InterceptionBehavior<PolicyInjectionBehavior>(),
  new Interceptor<InterfaceInterceptor>(),
  new InjectionConstructor(new DatabaseSettings()));

Container.RegisterType<IMockUseHardcodedConnectionString, MockUseHardCodedConnectionString>(
  new InterceptionBehavior<PolicyInjectionBehavior>(),
  new Interceptor<InterfaceInterceptor>(),
  new InjectionConstructor(new DatabaseSettings
    {
      ConnectionString = MockUseHardCodedConnectionString.ConnectionString
    }));
/* IDatabaseSettings is not registered to manually control the settings being used */

var first = new InjectionProperty("Order", 1);
var second = new InjectionProperty("Order", 2);

Container
  .Configure<Interception>()
  .AddPolicy("DatabaseConnectionPolicy")
  .AddMatchingRule<NamespaceMatchingRule>(new InjectionConstructor("MyNamespace.*", true))
  .AddCallHandler<DatabaseConnectionCallHandler>(first);

Container
  .Configure<Interception>()
  .AddPolicy("TransactionPolicy")
  .AddMatchingRule(new CustomAttributeMatchingRule(typeof(TransactionAttribute), inherited: false))
  .AddCallHandler<TransactionCallHandler>(second);

3 个答案:

答案 0 :(得分:2)

我认为您所看到的行为是拦截方法设计的结果。使用InterfaceInterceptor时,会创建一个实现目标接口的代理对象,但代理对象的类型与原始类型完全不同。

如果您使用类型兼容的VirtualMethodInterceptor,那么您应该能够使用原始方法获取自定义属性。当然,VirtualMethodInterceptor的缺点是所有拦截方法都必须是虚拟的。

答案 1 :(得分:1)

另一个选择是从HandlerAttribute创建一个子类。有关详细信息,请参阅此SO post,或阅读this Unity doc。在您实现HandlerAttribute的CreateHandler()时,将您的属性实例传递给您的调用处理程序实例,这样您就不必调用GetCustomAttributes()。或者,在一个类中实现HandlerAttribute和ICallHandler,然后返回:

public sealed class AuditAttribute : HandlerAttribute, ICallHandler
{
    #region attribute properties
    public string Key { get; set; } // your own attribute properties

    public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container)
    {
        return this;
    }

    #endregion

    #region ICallHandler
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        // do stuff ...

        // then
        return getNext()(input, getNext);
    }

    public int Order { get; set; }
    #endregion

}

答案 2 :(得分:0)

我正在查看一些示例代码,我注意到一些非常简单的事情,我没有想过。

当属性创建调用处理程序时,将所需的参数传递给处理程序的构造函数。然后它们位于用于属性的处理程序实例中。问题解决了。