ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 150
Numărul 149 Numărul 148 Numărul 147 Numărul 146 Numărul 145 Numărul 144 Numărul 143 Numărul 142 Numărul 141 Numărul 140 Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 22
Abonament PDF

AOP folosind Unity

Radu Vunvulea
Solution Architect
@iQuest



PROGRAMARE

În ultimul număr al revistei Today Software Magazine, am discutat despre principiile de bază ale AOP și despre cum putem implementa conceptul de bază al AOP utilizând caracteristici ale .NET 4.5, fără a folosi alte cadre. În acest articol, vom vorbi despre Unity și vom vedea cum putem utiliza acest cadru pentru a implementa AOP.

Recapitulare

Într-o primă parte , vă prezentăm o definiție a acronimului AOP și cum o putem utiliza în .NET 4.5 fără alte cadre.

Aspect Oriented Programming (Programarea Orientată pe Aspecte) este o paradigmă de programare având ca scop principal creșterea modularității unei aplicații. AOP încearcă să atingă acest scop prin permiterea separării aspectelor secante (cross-cutting concerns), folosind interceptarea diferitelor comenzi sau cereri.

Un exemplu bun pentru acest caz este audit-ul și logging-ul. În mod normal, dacă utilizăm OOP pentru a dezvolta o aplicație care necesită logging sau audit, vom avea într-o formă sau alta diverse apelări ale mecanismului de logging în codul nostru. În OOP, acest lucru poate fi acceptat, deoarece aceasta este singura modalitate de a scrie log-uri, de a face prelucrare și așa mai departe. Când utilizăm AOP, implementarea sistemului de logging sau audit va trebui să se afle într-un modul separat. Mai mult decât atât, vom avea nevoie de o cale de a scrie informația de logging fără a scrie cod în alte module care vor face apelarea în sine a sistemului de logging, folosind interceptarea.

Această funcționalitate poate fi implementată utilizând instrumentele din .NET 4.5, cum sunt RealProxy și Attribute. RealProxy este ingredientul special în cazul nostru, dându-ne posibilitatea de a intercepta toate cererile adresate unei metode sau proprietăți.

Unity

Acesta este un cadru binecunoscut de către dezvoltatorii .NET drept un dependency injection container. Acesta este parte a componentelor care formează Pattern-urile și Practicile Microsoft și este undependency injection container în cazul aplicației ASP.NET MVC. Unity a atins un punct critic în momentul în care a fost complet integrat cu ASP.NET MVC. Din acel moment, mii de proiecte web au început să îl utilizeze.

Din punctul de vedere al unui container de injectare dependențe, Unity este un cadru matur care are toate funcțiile pe care un dezvoltator se așteaptă să le găsească la un astfel de cadru. Caracteristici precum configurare XML, înregistrare, rezolver implicit sau special, injectare de proprietăți, container-e personalizate, sunt în întregime susținute de Unity.

În următorul exemplu, vom vedea cum putem înregistra interfața IFoo în containerul de injectare dependențe și cum putem obține o referință la această exemplificare.

IUnityContainer myContainer = new UnityContainer(); 
myContainer.RegisterType<ifoo, foo="">(); 
//or
myContainer. RegisterInstance<ifoo>( new Foo()); 
IFoo myFoo = myContainer.Resolve<foo>();
</foo></ifoo></ifoo,>

Când este folosit cu ASP.NET MVC, dezvoltatorii nu mai trebuie să gestioneze durata resurselor utilizate de Controller-i, Unity este cel care se ocupă de acest aspect în locul lor. Singura operație pe care trebuie să o facă este să înregistreze aceste resurse și să le solicite în controller, ca în următorul exemplu:

public class HomeController : Con
troller
{
    Foo _foo;

    public HomeController(Foo foo)
    {
        _foo = foo;
    }

    public ActionResult Index()
    {
        ViewData["Message"] = "Hello World!";

        return View();
    }

    public ActionResult About()
    {
        return View();
    }
}

După cum putem observa în exemplul de mai sus, Unity va putea rezolva toate dependențele în mod automat.

Unity și AOP

Înainte de a analiza acest subiect mai în amănunt, este necesar să abordăm a atitudine obiectivă. Unity nu este un cadru AOP și, de aceea, nu vom avea toate caracteristicile care formează AOP.

Unity susține AOP la nivel de interceptare. Aceasta înseamnă că avem posibilitatea de a intercepta apelurile către obiectul nostru de la dependency injection container și de a configura un comportament special la acel nivel.

Unity ne oferă posibilitatea de a injecta codul nostru înainte și după o apelare a obiectului nostru țintă. Aceasta poate fi făcută numai cu obiectele care sunt înregistrate în Unity. Noi nu putem modifica cursul pentru obiecte care nu se află în container-ul Unity.

Unity ne oferă această funcționalitate utilizând un mecanism similar cu cel care este obținut prin Decorated Pattern. Singura diferență este că în cazul Unity, container-ul este cel care decorează apelul cu un comportament – atribut "făcut la comandă". La sfârșitul articolului vom vedea cât de ușor este să adaugi un mecanism de urmărire utilizând Unity sau să faci toate apelurile către baza de date să execute, folosind tranzacții.

Putem utiliza Unity pentru obiecte care au fost create în Unity și înregistrate în diferite container-e sau obiecte care au fost create în alte părți ale aplicației noastre. Singura cerință de la Unity este să aibă acces la aceste obiecte într-un fel sau altul.

Cum poate Unity să intercepteze apeluri?

Toate apelurile de la client pentru tipuri specifice trec prin Unity Interceptor. Acesta este o componentă a cadrului care poate intercepta toate apelurile și poate injecta unul sau mai multe comportamente la comandă, înainte sau după apel. Aceasta înseamnă că între apelul clientului și obiectul țintă, componenta Unity Interceptor va intercepta apelul, va declanșa comportamentul la comandă și va face apelul real către obiectul țintă.

Toate aceste apeluri sunt interceptate prin folosirea unui substitut care trebuie să fie configurat de către dezvoltator. Odată ce substitutul este setat, toate apelurile vor trece prin Unity. Nu există nicio cale prin care cineva să poată "sparge" sistemul și să treacă pe lângă interceptor.

Comportamentul care este injectat utilizând Unity poate schimba valoarea parametrului de intrare sau valoarea returnată.

Cum să configurezi interceptarea?

Există două moduri de a configura interceptarea – de la cod sau utilizând fișiere de configurare. În ambele cazuri, este nevoie să definim comportamentul special care va fi injectat în container-ele Unity. Personal, eu prefer să folosesc codul, utilizând fluentul API care este disponibil. Recomand utilizarea fișierelor de configurare numai atunci când sunteți siguri că va trebui să schimbați configurarea în timpul execuției sau fără a recompila codul. Chiar dacă facem această recomandare, noi am utilizat frecvent configurarea din fișiere pentru că aceasta este mai flexibilă.

Atunci când folosiți fișiere de configurare, vă asumați riscul de a introduce mai ușor probleme de configurare – scrierea greșită a numelui claselor sau redenumirea unui tip și omiterea de a actualiza și fișierele de configurare.

Primul pas este acela de a defini comportamentul pe care dorim să îl executăm atunci când realizăm interceptarea apelului. Acest lucru se face numai prin cod, implementând InterceptionBehavior.

Cea mai importantă metodă a acestei interfețe este "Invoke" (Invocarea), care este declanșată când cineva apelează metodele care sunt interceptate. De la această metodă este nevoie să facem apelul propriu-zis către metoda reală. Înainte și după apel, putem injecta orice tip de comportament.

Deși era previzibilă existența a două metode, una care este apelată înainte de apelul propriu-zis și una după apel, această funcție nu o deține Unity. O altă componentă importantă a acestei interfețe este proprietatea "WillExecute". Stabilirea drept TRUE (adevărată) a proprietății, condiționează interceptarea apelului.

Utilizând această interfață, avem posibilitatea de a controla apelurile către orice metode de la obiectele aplicației noastre. Avem deplin control de a face apelul real sau de a-l mima:

public class FooBehavior : IInterceptionBehavior
{  
  public IEnumerable<type> GetRequiredInterfaces()
  {
    return Type.EmptyTypes;
  }

  public IMethodReturn Invoke(IMethodInvocation input, 
    GetNextInterceptionBehaviorDelegate getNext)
  {
    Trace.TraceInformation("Before call");

    // Make the call to real object 
    var methodReturn = getNext().Invoke(input, getNext);

     Trace.TraceInformation("After call");
     return methodReturn;
   }

   public bool WillExecute
   {
     get { return true; }
   }   
 }
</type>

Apoi va trebui să adăugăm acest comportament la Unity. Vom adăuga o secțiune specială la fișierul nostru de configurare care să specifice pentru ce tip dorim să facem această interceptare. În următorul exemplu, vom face această interceptare numai pentru tipul Foo:


<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.
  Configuration.InterceptionConfigurationExtension, 
  Microsoft.Practices.Unity.Interception.Configuration"/>
…
<container> 
  <extension type="Interception" /> 
  <register type="IFoo" mapTo="Foo"> 
    <interceptor type="InterfaceInterceptor" /> 
    <interceptionBehavior type="FooBehavior" /> 
  </register> 
</container>

În acest exemplu, specificăm în Unity să folosească interceptorul interfață folosind FooBehavior pentru toate exemplele de obiecte IFoo care sunt asociate cu Foo.

Aceeași configurare poate fi realizată din cod, utilizând configurare fluentă.

unity.RegisterType<ifoo, foo="">(
    new ContainerControlledLifetimeManager(), 
    new Interceptor<interfaceinterceptor>(), 
            new InterceptionBehavior<foobehavior>());</foobehavior></interfaceinterceptor></ifoo,>

Din acest moment, toate apelurile la exemple Ifoo din containerul Unity vor fi interceptate de către interceptorul (comportamentul) nostru special creat.

Mai există și o altă metodă de a implementa acest mecanism, folosind atribute. Dacă utilizați atribute, va trebui să implementați interfața IcallHandler pentru a specifica comportamentul special și pentru a crea atribute speciale care vor fi folosite pentru a decora metoda pe care dorim să o interceptăm. Din punctul nostru de vedere , este de preferat prima versiune, cea a utilizării IInterceptionBehavior.

Concluzie

În acest articol am văzut cât de ușor putem adăuga funcționalitate AOP unui proiect care utilizează deja Unity. Implementarea acestei funcții este foarte simplă și flexibilă. Ne putem imagina foarte ușor scenarii mai complexe, combinând IinterceptionBehavior și atribute speciale.

Chiar dacă nu avem metode specifice apelate de Unity înainte și după invocare, aceasta poate fi foarte ușor extinsă. Vă invit pe toți să încercați Unity.

NUMĂRUL 149 - Development with AI

Sponsori

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • P3 group
  • Ing Hubs
  • Cognizant Softvision
  • Colors in projects