2012-08-10 83 views
17

的调用我正在尝试学习Unity Interceptors,我正在努力学习它。使用Unity拦截所有对IMyInterface.SomeMethod

说我有一个这样的接口:

public interface IMyInterface 
{ 
    void SomeMethod(); 
} 

我有数目不详的实现像这样的接口类:

public class SpecificClass1 : IMyInterface 
{ 
    public void SomeMethod() 
    { 
     Console.WriteLine("Method Called"); 
    } 
} 

我正在寻找一种方式说, “对于IMyInterface的所有实例(我不想枚举它们),当SomeMethod被称为运行我的拦截器时

它是类的非枚举给我麻烦即(有很多例子,如果你可以列举你所有的类。)

我已经阅读过类型截取,但我似乎无法找出它是否会做我想找的。

任何Unity专家都知道如何去做我正在寻找的东西?

回答

0

设置拦截需要多个操作,拦截类型,策略和处理程序的配置。

有关支持截取的情况类型(例如,有或没有DI容器)的一般细节,请参阅Using Interception in Applications。有关支持的拦截器的更多详细信息,请参见Type Interception。尤其要注意拦截器可以用于你的类的类型(否则处理程序将永远不会触发)。

当你决定使用什么拦截器时,配置它并根据上面的链接创建一个足够的呼叫处理程序。如果您在这一点上仍然有问题,请发布更详细的问题。如果你已经这样做了,请将配置和代码发布为“非枚举类”,根本不会提供任何提示。你有没有机会用“枚举”来指定你分配一个属性驱动的策略,并且无法在没有它的情况下实现你想要的?

18

你可以创建InterceptionBehavior然后在特定的类上注册它。注意:您可以过滤在Invoke执行方法有关Interception with Unity

9

@GSerjo通IMethodInvocation input

using System; 
using System.Collections.Generic; 
using System.Linq; 
using Microsoft.Practices.Unity; 
using Microsoft.Practices.Unity.InterceptionExtension; 
using NUnit.Framework; 

namespace UnitTests 
{ 
    [TestFixture] 
    public class ForTest 
    { 
     [Test] 
     public void Test() 
     { 
      IUnityContainer container = new UnityContainer().AddNewExtension<Interception>(); 
      container.RegisterType<IMyInterface, SpecificClass1>(
       new Interceptor<InterfaceInterceptor>(), 
       new InterceptionBehavior<MyInterceptionBehavior>()); 
      var myInterface = container.Resolve<IMyInterface>(); 
      myInterface.SomeMethod(); 
     } 
    } 

    public interface IMyInterface 
    { 
     void SomeMethod(); 
    } 

    public class SpecificClass1 : IMyInterface 
    { 
     #region IMyInterface 

     public void SomeMethod() 
     { 
      Console.WriteLine("Method Called"); 
     } 

     #endregion 
    } 

    public class MyInterceptionBehavior : IInterceptionBehavior 
    { 
     public bool WillExecute 
     { 
      get { return true; } 
     } 

     #region IInterceptionBehavior 

     public IEnumerable<Type> GetRequiredInterfaces() 
     { 
      return Enumerable.Empty<Type>(); 
     } 

     public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) 
     { 
      IMethodReturn result = getNext()(input, getNext); 
      Console.WriteLine("Interception Called"); 
      return result; 
     } 

     #endregion 
    } 
} 

控制台输出

Method Called 
Interception Called 

更多,概述了统一拦截的做法,效果很好。如果您想自动配置拦截,则可以使用UnityContainerExtension自动连接所有接口拦截以及行为。如果你想进入更具体的拦截(方法名称,签名,返回值等),那么你可能需要看看策略注入(使用与CallHandlers匹配的规则)。

因此,在这种情况下,容器延长会是什么样子:

public class UnityInterfaceInterceptionRegisterer : UnityContainerExtension 
{ 
    private List<Type> interfaces = new List<Type>(); 
    private List<IInterceptionBehavior> behaviors = 
     new List<IInterceptionBehavior>(); 

    public UnityInterfaceInterceptionRegisterer(Type interfaceType, 
     IInterceptionBehavior interceptionBehavior) 
    { 
     interfaces.Add(interfaceType); 
     behaviors.Add(interceptionBehavior); 
    } 

    public UnityInterfaceInterceptionRegisterer(Type[] interfaces, 
     IInterceptionBehavior[] interceptionBehaviors) 
    {    
     this.interfaces.AddRange(interfaces); 
     this.behaviors.AddRange(interceptionBehaviors); 

     ValidateInterfaces(this.interfaces); 
    } 

    protected override void Initialize() 
    { 
     base.Container.AddNewExtension<Interception>(); 

     base.Context.Registering += 
      new EventHandler<RegisterEventArgs>(this.OnRegister); 
    } 

    private void ValidateInterfaces(List<Type> interfaces) 
    { 
     interfaces.ForEach((i) => 
     { 
      if (!i.IsInterface) 
       throw new ArgumentException("Only interface types may be configured for interface interceptors"); 
     } 
     ); 
    } 

    private bool ShouldIntercept(RegisterEventArgs e) 
    { 
     return e != null && e.TypeFrom != null && 
       e.TypeFrom.IsInterface && interfaces.Contains(e.TypeFrom); 
    } 

    private void OnRegister(object sender, RegisterEventArgs e) 
    { 
     if (ShouldIntercept(e)) 
     { 
      IUnityContainer container = sender as IUnityContainer; 

      var i = new Interceptor<InterfaceInterceptor>(); 
      i.AddPolicies(e.TypeFrom, e.TypeTo, e.Name, Context.Policies); 

      behaviors.ForEach((b) => 
       { 
        var ib = new InterceptionBehavior(b); 
        ib.AddPolicies(e.TypeFrom, e.TypeTo, e.Name, Context.Policies); 
       } 
      ); 
     } 
    } 
} 

那么你可以使用它像这样:

IUnityContainer container = new UnityContainer() 
    .AddExtension(new UnityInterfaceInterceptionRegisterer(
     new Type[] { typeof(IMyInterface), 
        typeof(IMyOtherInterface) }, 
     new IInterceptionBehavior[] { new MyInterceptionBehavior(), 
             new AnotherInterceptionBehavior() } 
     )); 

container.RegisterType<IMyInterface, SpecificClass1>(); 

var myInterface = container.Resolve<IMyInterface>(); 
myInterface.SomeMethod(); 

现在,当这个接口已经注册了相应的拦截政策也将是添加到容器中。因此,在这种情况下,如果注册的接口类型为IMyInterface或IMyOtherInterface,则会为接口拦截设置策略,并且还会添加拦截行为MyInterceptionBehavior和AnotherInterceptionBehavior。

请注意,Unity 3(在此问题/答案后发布)添加了Registration by Convention功能,可以执行此扩展的功能(无需编写任何自定义代码)。来自Developer's Guide to Dependency Injection Using Unity的示例:

var container = new UnityContainer(); 

container.AddNewExtension<Interception>(); 
container.RegisterTypes(
    AllClasses.FromLoadedAssemblies().Where(
     t => t.Namespace == "OtherUnitySamples"), 
    WithMappings.MatchingInterface, 
    getInjectionMembers: t => new InjectionMember[] 
    { 
     new Interceptor<VirtualMethodInterceptor>(), 
     new InterceptionBehavior<LoggingInterceptionBehavior>() 
    });