I'm trying to do some attribute-based interception using structuremap but I'm开发者_开发问答 struggling to tie up the last loose ends.
I have a custom Registry that scans my assemblies and in this Registry I have defined the following ITypeInterceptor whose purpose it is to match types decorated with the given attribute and then apply the interceptor if matched. The class is defined as such:
public class AttributeMatchTypeInterceptor<TAttribute, TInterceptor>
: TypeInterceptor
where TAttribute : Attribute
where TInterceptor : IInterceptor
{
private readonly ProxyGenerator m_proxyGeneration = new ProxyGenerator();
public object Process(object target, IContext context)
{
return m_proxyGeneration.CreateInterfaceProxyWithTarget(target, ObjectFactory.GetInstance<TInterceptor>());
}
public bool MatchesType(Type type)
{
return type.GetCustomAttributes(typeof (TAttribute), true).Length > 0;
}
}
//Usage
[Transactional]
public class OrderProcessor : IOrderProcessor{
}
...
public class MyRegistry : Registry{
public MyRegistry()
{
RegisterInterceptor(
new AttributeMatchTypeInterceptor<TransactionalAttribute, TransactionInterceptor>());
...
}
}
I'm using DynamicProxy from the Castle.Core to create the interceptors, but my problem is that the object returned from the CreateInterfaceProxyWithTarget(...) call does not implement the interface that triggered the creation of the target instance in structuremap (i.e IOrderProcessor in example above). I was hoping that the IContext parameter would reveal this interface, but I can only seem to get a hold of the concrete type (i.e. OrderProcessor in example above).
I'm looking for guidance on how to have this scenario work, either by calling the ProxyGenerator to return an instance that implements all interfaces as the target instance, by obtaining the requested interface from structuremap or through some other mechanism.
I actually got something working with a slight caveat so I'll just post this as the answer. The trick was to obtain the interface and pass that into the CreateInterfaceProxyWithTarget. My only problem was that I could not find a way to query the IContext about which interface it was currently resolving so I ended up just looking up the first interface on the target which worked for me. See code below
public class AttributeMatchTypeInterceptor<TAttribute, TInterceptor> :
TypeInterceptor
where TAttribute : Attribute
where TInterceptor : IInterceptor
{
private readonly ProxyGenerator m_proxyGeneration = new ProxyGenerator();
public object Process(object target, IContext context)
{
//NOTE: can't query IContext for actual interface
Type interfaceType = target.GetType().GetInterfaces().First();
return m_proxyGeneration.CreateInterfaceProxyWithTarget(
interfaceType,
target,
ObjectFactory.GetInstance<TInterceptor>());
}
public bool MatchesType(Type type)
{
return type.GetCustomAttributes(typeof (TAttribute), true).Length > 0;
}
}
Hope this helps someone
精彩评论