unity拦截GetCustomAttribute
Posted
技术标签:
【中文标题】unity拦截GetCustomAttribute【英文标题】:Unity Interception GetCustomAttribute 【发布时间】:2013-06-17 20:15:32 【问题描述】:提前感谢您的帮助! (是的,底部有个问题)
我正在使用 Unity 3.x 拦截来执行 AOP 前后数据库连接和事务活动。数据库拦截器总是被实例化,事务拦截器是基于 CustomAttributeMatchingRule 的,两者都通过 InterfaceInterceptor。我的 TransactionAttribute 中有正在设置的属性:
[Transaction(IsolationLevel.ReadUncommitted, NoRollbackFor = new[] typeof(TestException) )]
作为我在单元测试中使用的示例。我想在我的 TransactionCallHandler 类调用方法中访问它们。我看过例子说
var transactionAttribute = input.MethodBase.GetCustomAttribute<TransactionAttribute>(false);
是访问它的方式,但我的交易变量为空。 我的结论是拦截代理类正在检查自定义属性而不是原始具体实例。
我的解决方法是一直反映到类级别,深入挖掘以找出被拦截的正确方法并从那里执行获取自定义属性。
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);
【问题讨论】:
【参考方案1】:我浏览了一些示例代码,发现了一些我没有想到的非常简单的东西。
当属性创建调用处理程序时,将你想要的参数传递到处理程序的构造函数中。然后它们位于用于属性的处理程序实例中。问题解决了。
【讨论】:
有趣的想法。您能否提供少量代码来支持这一点?谢谢!【参考方案2】:另一个选择是从 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
【讨论】:
不错。我没有想过这样做,它很好地解决了这个问题。但是,如果我想让多个属性一起工作,比如缓存(cacheResult、InvalidateCacheResult、CacheTimeout 等),那么你仍然需要进行讨厌的反射检查【参考方案3】:我认为您看到的行为是拦截方法设计的结果。当使用 InterfaceInterceptor 时,会创建一个实现目标接口的代理对象,但是代理对象是与原始类型完全不同的类型。
如果您使用类型兼容的 VirtualMethodInterceptor,那么您应该能够使用原始方法获取自定义属性。当然,VirtualMethodInterceptor 的缺点是所有要拦截的方法都必须是虚拟的。
【讨论】:
我同意@Tuzo 同意您缩小虚拟拦截的规模。我不想在常规代码库中引入我必须教每个新开发人员的约定;更不用说在我离开这份合同后希望他们记得为什么要这样做。我将在 Unity 拦截项目中添加一个请求,看看是否可以将其纳入路线图。 我对项目的请求已通过以下方式结束:用户 gmelnik 已更新问题:Unity 拦截 GetCustomAttribute。状态已从 Proposed 更改为 Closed,并带有以下评论:“在 *** 上提供了答案。”以上是关于unity拦截GetCustomAttribute的主要内容,如果未能解决你的问题,请参考以下文章
Unity拦截:如何将参数传递给ICallHandler实现?