2012-08-10 12 views
17

Sto cercando di imparare Unity Interceptors e sto facendo un tentativo difficile.Utilizzare Unity per intercettare tutte le chiamate a IMyInterface.SomeMethod

Dire che ho un'interfaccia come questa:

public interface IMyInterface 
{ 
    void SomeMethod(); 
} 

E ho un numero imprecisato di classi che implementano l'interfaccia come questa:

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

Sto cercando un modo per dire, "per tutte le istanze di IMyInterface (non voglio enumerarle), quando SomeMethod è chiamato esegui il mio intercettore.

E 'la non enumerazione della classe che mi sta dando e. (Ci sono molti esempi se è possibile enumerare tutte le classi.)

Ho letto di intercettazione di tipo, ma non riesco a capire se farà quello che sto cercando.

Tutti gli esperti di Unity là fuori sanno come fare quello che sto cercando?

risposta

0

L'impostazione dell'intercettazione richiede più azioni incl. configurazione di tipi, politiche e gestori intercettati.

Prima vedere Using Interception in Applications per informazioni generali sui tipi di situazioni in cui è supportata l'intercettazione (con o senza un contenitore DI, ad esempio). Quindi vedere Type Interception per ulteriori dettagli sugli intercettori di tipo supportati. Soprattutto prendi nota di quali intercettatori possono essere usati con il tipo della tua classe (altrimenti i gestori non si innescheranno mai).

Quando si è deciso quale intercettatore utilizzare, configurarlo e creare un gestore di chiamata sufficiente come indicato nei collegamenti precedenti. Se hai ancora problemi a questo punto, pubblica una domanda più dettagliata. Se l'hai già fatto, ti preghiamo di postare le configurazioni e il codice come "non enumerazione della classe" semplicemente non fornisce alcun indizio su cosa stai effettivamente chiedendo. Per caso intendi con "enumerazione" che assegni una politica basata sugli attributi e non riesci a ottenere ciò che vuoi senza di essa?

18

È possibile creare InterceptionBehavior quindi registrarlo su una classe specifica. Nota è possibile filtrare i metodi di esecuzione in 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 
    } 
} 

uscita Console

Method Called 
Interception Called 

più su Interception with Unity

9

@GSerjo, ha delineato l'approccio intercettazione unità che funziona bene. Se si desidera automatizzare la configurazione dell'intercettazione, è possibile utilizzare UnityContainerExtension per collegare automaticamente tutta l'intercettazione dell'interfaccia e i comportamenti. Se si desidera accedere a un'intercettazione più specifica (nomi di metodi, firme, valori di ritorno, ecc.), Sarà probabilmente necessario consultare Policy Injection (utilizzando le regole di corrispondenza con CallHandlers).

Quindi, in questo caso l'estensione del contenitore sarà simile:

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

allora si potrebbe utilizzare in questo 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(); 

Ora, quando l'interfaccia è iscritto le politiche di intercettazione appropriate saranno anche aggiunto al contenitore. In questo caso, se l'interfaccia registrata è di tipo IMyInterface o IMyOtherInterface, verranno quindi impostate le policy per l'intercettazione dell'interfaccia e verranno aggiunti anche i comportamenti di intercettazione MyInterceptionBehavior e AnotherInterceptionBehavior.

Nota che Unity 3 (rilasciato dopo questa domanda/risposta) ha aggiunto una funzione Registration by Convention che può fare ciò che fa questa estensione (senza dover scrivere alcun codice personalizzato). Un esempio da 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>() 
    }); 
Problemi correlati