Dezvoltare .NET, Programare Model Binder in .NET MVC – Default sau Custom ?
Cover600x600

Dezvoltare .NET, Programare

Model Binder in .NET MVC – Default sau Custom ?

Model Binder al unei aplicatii .NET MVC este componenta care contribuie la crearea obiectelor .NET primite ca parametri de catre Action Methods din Controller

 

Model Binder asociaza valori pentru toate tipurile de parametrii care sunt declarati prin Action Methods ale unui Controller, in momentul apelului.

 

Vom detalia modul de functionare clasic al Model Binder, puterea conceptului, cum se poate extinde, cum putem sa il facem mai flexibil creand componente personalizate.

 

DefaultModelBinder implementeaza interfata IModelBinder prin metoda unica BindModel. Este folosit de fiecare data cand nu exista un Model Binder customizat. In cele mai multe cazuri, DefaultModelBinder este suficient.

Din momentul in care o metoda de actiune a unui Controller declara parametri de intrare, aceasta se va regasi in perimetrul de actiune al unui Model Binder. Plecand de la numele fiecarui parametru, DefaultModelBinder va parcurge mai multe colectii in momentul apelului, incercand sa indentifice valoarea parametrului : colectia de parametri POST, valorile din rute, parametrii GET, fisierele uploadate.

 

Fig1_ro

Figura 1. Mecanismul analizei datelor primite in scopul initializarii parametrilor 

Mecanismul de identificare al valorilor prin intermediul Model Binder functioneaza pentru toate tipurile de parametri :

    1. Parametrii de tip simplu (int, string, etc) : prin conversii automate ale formatului string initial.
    2. Se ridica erori in cazul conversiilor imposibile, aceste cazuri pot fi anticipate si se pot trata in cod (exemplu : secventa de litere primita pentru un parametru de tip numeric).
    3. Parametrii de tip complex, corespunzatori claselor definite in proiect :Membrii publici de tip complex vor fi descompusi pana la obtinerea de membrii publici de tip simplu.
    4. se identifica toti membrii publici de tip simplu, care vor fi tratati conform mecanismului parametrilor de tip simplu.
  • Parametrii de tip array sau colectie de tipuri simple 

 

    1. Sunt identificate toate elementele ce contin numele parametrului pentru compunerea de liste.
  • Parametrii de tip array sau colectie de tipuri complexe

 

  1. In atributul Nume al datelor, se cauta prefixul « [index]. » ([0]., [1]. etc.) in fata numelui membrilor de tip simplu, pentru a obtine valorile proprietatilor obiectelor unei anumite pozitii dintr-o colectie :

 

Fig2_ro

Figura 2. Flux de date cu Model Binder implicit 

 

Exista situatii in care dorim sa transmitem date catre Action Methods care nu sunt continute in formularul POST, in rute, in lantul GET sau in colectia de fisiere. In aceste cazuri, sunt posibile mai multe solutii :

 

1. Adaugarea datelor in colectiile standard pemtru a intra in perimetrul componentei Model Binder implicit

 

In cazul tipurilor simple de date, este suficienta adaugarea lor in colectiile indicate. Acestea vor fi luate in considerare de mecanismul de asociere al Model Binder. Vor fi adaugate ca si campuri de tip Hidden in formularele POST, ca parametri suplimentari GET, sau ca nivele suplimentare in cererile HTTP.

 

In cazul tipurilor complexe de date, nu este usoara adaugarea unor structuri intregi de date la formularele din pagini sau la cererile HTTP. Aceasta implica si fluxuri suplimentare de date transmise de retea.

 

2. Utilizarea directa a obiectului Sesiune ASP.NET

 

 

Putem face apel la obiectul Sesiune al ASP .NET care realizeaza persistenta datelor la trecerea dintr-o pagina in alta, in limita ramenerii active a sesiunii web curente. In mod implicit datele sunt pastrate in memoria serverului web. Putem plasa obiectele necesare in sesiune, utilizand ulterior referintele lorpentru citirea sau modificarea continutului.

 

Luam exemplul magazin virtual si al unui cos de cumparaturi de produse individuale, cantitati, alte elemente auxiliare si metode. Se implementeaza in aplicatie printr-o clasa « Cart ». Scopul este de a pastra produsele din cos pana la finalizarea procesului de cumparare, chiar daca navigam prin alte pagini ale site-ului.

 

Plasam in sesiune o referinta catre obiect cu sintaxa:

Session[„cart”] = shoppingCart;

 

Si se poate regasi cu :

(Cart)Session[„cart”];

Adaugam astfel o cale paralela pentru pastrarea obiectului cart, gestiunea obiectului din sesiune plasandu-se in Controller.

 

Fig3_ro

Figura 3. Flux de date cu Model Binder implicit si Sesiune

 

Aceasta solutie vine insa cu un pret : Controller a primit logica de gestionare a obiectelor sesiunii, care nu face parte din atributiile lui normale. Controller devine astfel sensibil la modul de stocare al obiectelor. Daca ne decidem ulterior sa schimbam modul de stocare, va trebui sa modificam Controller, chiar daca functionalitatea sa ramane neschimbata.

In plus, acest mecanism nu poate fi testat usor prin metode Unit tests. In aceasta implementare, trebuie inclusa in unit tests si reproducerea starii sesiunii..

 

3. Utilizarea unui Model Binder customizat ce contine gestiunea obiectelor din Session

 

Aceasta metoda consta in trecerea gestunii obiectelor Sesiunii direct in mecanismul Model Binder, ca si cum ar fi fost transmise din formularul unei pagini catre o alta pagina, impreuna cu restul de date POST. Model Binder implicit nu stie totusi sa citeasca in sesiune, aceasta nefacand parte din colectiie pe care le analizeaza. Acest lucru ar fi totusi posibil, .NET MVC oferind posibilitatea de a crea si de a adauga Model Binders customizati ce contin noi functionalitati pentru diferite modele de date.

Beneficiile sunt vizibile imediat : in ce priveste stocarea unui anumit tip de obiect in sesiune, Controller nu mai cunoaste detaliile de implementare caci el primeste doar o referinta catre obiect.

 

Metodele cu teste automate vor utiliza obiectele fara sa faca referinta la sesiune. In acest caz, gestionarea obiectelor ce implica sesiunea este transferata in Model Binder customizat.
Aceasta solutie pare mai pertinenta decat precedenta.

Fig4-en

Figura 4. Flux de date cu Model Binder customizat, cu integrarea gestiunii Sesiunii

 

Etape pentru implementarea Model Binder customizat:

A.      Crearea noii clase Model Binder

Aceasta clasa va fi adaugata intr-un nou fisier al proiectului, fiind asociata la tipul de obiect model care ne intereseaza. Ea implementeaza interfata IModelBinder (System.Web.Mvc), care are ca unica metoda de implementat BindModel cu semnatura :

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)

  • ControllerContext ofera accesul la obiectele vizibile din clasa Controller, inclusiv sesiunea prin ControllerContext.HttpContext.Session
    • ModelBindingContext ofera accesul la model

Adaugam aici operatiile de plasare si colectare obiect in / din Sesiune, pe care o adaugasem in Controller pentru Solutia anterioara.

Exemplu de cos de cumparaturi : in metoda BindModel avem initializarea atunci cand obiectul nu exista :

cart = new Cart();

ControllerContext.HttpContext.Session[„cart”] = cart;

Recuperarea obiectului existent :

cart = (Cart)ControllerContext.HttpContext.Session[„cart”];

Metoda va returna obiectul

return cart;

 

B.      Inregistrarea noii clase Model Binder in aplicatie

Aplicatia va sti astfel pe ce tip de obiecte sa aplice Model Binder customizat.

– inregistrarea clasei se plaseaza in fisierul Global.asax, metoda Application_Start()

– concretizata prin simpla adaugare la colectia ModelBinders.Binders a unui element compus din tipul obiectului model si dintr-o instanta a Model Binder :

ModelBinders.Binders.Add(typeOf(Cart), new CartModelBinder());

Putem, realiza aceeasi inregistrare fara sa modificam Global.asax, prin adaugarea in clasa obiectului model care ne intereseaza a frazei:

[ModelBinder(typeof(classe Model Binder customizat)]

 

 C.      Curatarea metodelor din Controller

In urma operatiilor prezentate mai sus, obiectul model devine compatibil cu mecanismul Model Binder, fiind luat in considerare de versiunea customizata. Nu ne mai ramane decat sa plasam parametrii in semnaturile Actiunilor.

Valorile acestora vor fi citite prin intermediul metodei BindModel supraincarcata, in cazul nostru, din Session.

Folosirea de obiecte obtinute explicit din Sesiune este inlocuita cu obiecte primite ca parametri.

Metodele Controller-ului nostru care folosesc cosul de cumparaturi va avea semnaturi similare cu :

ViewResult Summary(Cart cart)

RedirectToRouteResult AddToCart(Cart cart, int productID)

 

In concluzie, putem insarcina Model Binder implicit sa asigure gestionarea obisnuita a parametrilor, majoritatea situatiilor vor fi acoperite.

In cazurile particulare in care colectiile implicite nu sunt suficiente sau se doreste un tratament special pentru un model, se pot adauga unul sau mai multe Model Binders customizate. Efortul de implementare nu va fi unul deosebit, toate Binder-ele vor rula impreuna pentru o functionalitate extinsa, pastrand in acelasi timp supletea codului.

 

 

 

 

 

 

 

 

 

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile necesare sunt marcate *

Poți folosi aceste etichete și atribute HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Facebook
Google+
http://blog.beleringenierie.com/ro/2017/06/27/model-binder-en-net-mvc-default-ou-custom/">
Twitter