2012-08-10 11 views
17

Estoy tratando de aprender Unity Interceptors y estoy teniendo dificultades.Use Unity para interceptar todas las llamadas a IMyInterface.SomeMethod

Digamos que tiene una interfaz de esta manera:

public interface IMyInterface 
{ 
    void SomeMethod(); 
} 

Y tengo un número desconocido de clases que implementan la interfaz de esta manera:

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

Busco una manera de decir, "para todas las instancias de IMyInterface (no quiero enumerarlas), cuando se llama SomeMethod, ejecute mi interceptor.

Es la no enumeración del classe lo que me está causando problemas mi. (Hay muchos ejemplos si puede enumerar todas sus clases.)

He leído sobre Tipo de interceptación, pero parece que no puedo averiguar si hará lo que estoy buscando.

¿Algún experto en Unity sabe lo que estoy buscando?

Respuesta

0

La configuración de la interceptación requiere múltiples acciones incl. configuración de tipos interceptados, políticas y manejadores.

Primero vea Using Interception in Applications para obtener detalles generales sobre los tipos de situaciones en las que se admite la intercepción (con o sin un contenedor DI por ejemplo). Luego, consulte Type Interception para obtener más detalles sobre los interceptores de tipo compatible. Tome nota especialmente de qué interceptores se pueden usar con el tipo de su clase (de lo contrario, los manipuladores nunca se dispararán).

Cuando haya decidido qué interceptor usar, configúrelo y cree un controlador de llamadas suficiente según los enlaces anteriores. Si todavía tiene problemas en este punto, publique una pregunta más detallada. Si ya ha hecho esto, publique las configuraciones y el código como "no enumeración del classe", simplemente no da ninguna pista de lo que realmente está preguntando. ¿Por casualidad quiere decir con "enumeración" que asigna una política basada en atributos y no puede lograr lo que quiere sin ella?

18

Puede crear InterceptionBehavior y registrarlo en una clase específica. Nota puede filtrar los métodos de ejecución en Invoke thru 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 
    } 
} 

salida de la consola

Method Called 
Interception Called 

Más sobre Interception with Unity

9

@GSerjo, ha descrito el método de intercepción Unidad que funciona bien. Si desea automatizar la configuración de la interceptación, puede usar UnityContainerExtension para cablear automáticamente toda la intercepción de la interfaz, así como los comportamientos. Si desea entrar en una interceptación más específica (nombres de métodos, firmas, valores de retorno, etc.), entonces probablemente necesite consultar Inyección de política (usando reglas de coincidencia con CallHandlers).

Así que en este caso la extensión de contenedores se vería así:

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); 
       } 
      ); 
     } 
    } 
} 

Entonces se podría utilizar de este modo:

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(); 

Ahora, cuando la interfaz se ha registrado en las políticas de interceptación adecuados también serán agregado al contenedor. Entonces, en este caso, si la interfaz registrada es de tipo IMyInterface o IMyOtherInterface, las políticas se configurarán para la intercepción de la interfaz y también se agregarán los Comportamientos de interceptación, MyInterceptionBehavior y AnotherInterceptionBehavior.

Tenga en cuenta que Unity 3 (lanzado después de esta pregunta/respuesta) agregó una característica Registration by Convention que puede hacer lo que hace esta extensión (sin tener que escribir ningún código personalizado). Un ejemplo del 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>() 
    }); 
Cuestiones relacionadas