Date post: | 25-May-2015 |
Category: |
Business |
Upload: | radu-vunvulea |
View: | 1,102 times |
Download: | 0 times |
ASP.NET MVC - BAD PRACTICES
Radu Vunvuleavunvulearadu.blogspot.com
Agenda• ASP.NET MVC Introduction• Why “BAD PRACTICES”• Some bad practices• More bad practices• And more bad practices• Q&A• Bibliography
MVC - Model View Controller
Model
ViewController
De ce “BAD PRACTICES”?
De ce “BAD PRACTICES”?
2 km
De ce “BAD PRACTICES”?
20 km
De ce “BAD PRACTICES”?
900 km
View Model = Domain model
Repository View
Domain Model
View Model = Domain model
• In view o sa ajunga mai multe date decat este necesar• Entitatea o sa fie poluata cu diferite atribute ce tin de UI• Nu exista o separare clara a fiecarui layer
• Modelul este un DTO (Data Transfer Object) si ar putea sa fie compus doar din string-uri
• Un convertor se poate folosi pentru a obtine un model dintr-o entitate (intr-un sens, in doua sensuri)
• Un framework pentru maparea entitatilor (AutoMapper)
• Codul care face conversia nu se duplica• Controller-ul nu creste ca si complexitate din cauza conversiei
View Model = Domain model
View-ul contine logica
View-ul contine logica
• In view modelul este procesat• Modelul nu contine date in stare finala
• View-ul ar trebui doar sa afiseze modelul• Logica de procesare nu are ce cauta in view
• Din view nu se apeleaza clase exterioare• Un view poate sa contina IF si FOR (FOREACH)• SWITCH – chiar avem nevoie de el?• Daca populam modelul corect, IF-ul poate sa fie inlocuit cu un
HtmlHelper
Controller si dependintele exterioare
Controller si dependintele exterioare
• Controller-ul nu ar trebui sa acceseze direct HttpContext, baza de date sau orice alta resursa
• Setarile din web.config nu trebuie accesate direct
• Este mai greu de testat• Nu este flexibil• Orice schimbare poate sa genereze foarte multe modificari
• Se poate construi un wrapper peste aceste dependinte• Wrapperul poate sa grupeze datele din punct de vedere logic si nu in
functie de sursa lor• ActionFilter care sa ne ofere aceste date
Controller si dependintele exterioare
Controller si dependintele exterioare
Nu folositi “magic words”
Nu folositi “magic words”
• Cand se acceseaza sesiunea, ViewData, ViewBag, etc• Pot sa apara foarte usor greseli de scriere (misspelling)• Duplicarea informatiei – aceiasi informatie in mai multe locuri• Aceiasi conversie de date se face in mai multe locuri
• Nu o sa stiti cauza pentru care view-ul crapa (misspelling sau datele nu au fost puse unde trebuie)
• Wrapper• Extension methods• Datele de care avem nevoie in view se pot trimite prin model si nu
prin alte mecanisme
Nu folositi “magic words”
Nu hardcodati RouteUrl-urile
• Evitati sa folosti Html.ActionLink in view • Evitati sa folosti RedirectToAction in controller
• Puteti crea extension methods pentru fiecare url• Le puteti refolosi in mai multe locatii (atat in view cat si in controller)• Creati extension methods si pentru locatiile la resurse (image path,
JavaScript path, CSS files path)
Repopulare date comune in Model
• 2 sau mai multe modele contin aceleasi date
• Creati o structura de clase (BaseUserModel, CustomerUserModel, AdminUserModel)
• Populati modelul de baza dintr-un singur loc
Repopulare date comune in Model
• 2 sau mai multe modele contin aceleasi date
• Creati o structura de clase (BaseUserModel, CustomerUserModel, AdminUserModel)
• Populati modelul de baza dintr-un singur loc
?
Agregare date pentru o actiune
• Daca avem nevoie de acelasi ActionFilter in mai multe actiuni, atunci incercati sa le puneti intr-un sigur loc (intr-un BaseController)
• Folositi ActionFilter pentru a transforma datele care vin din diferite locatii in parametri pentru actiune
Fat Controller
• Apeleaza direct baza de date• Proceseaza informatia• Logica din el este foarte complexa – toata partea fun este in controller• Are foarte multe actiuni• Multe entitati sunt cuplate prin intermediul controller-ului
• Greu de inteles, modificat si testat• Controller-ul nu trebuie sa fie strans legat de domeniu• Nu el trebuie sa fie dirijorul aplicatiei noastre
• Un controller per functionalitate si nu per entitate
Fat Controller
• Un controller per functionalitate si nu per entitate
• Fiecare functionalitate care este oferita de catre aplicatia noastra poate sa fie reprezentata de catre un controller
• Un controller per use case – nu este mereu posibil
Actiunile apelate des nu sunt cache-uite
• Daca avem actiuni care sunt apelate des, iar continutul ramane la fel, atunci putem sa folosim OutputCache
• Nu poluati controller-ul cu configurarea cache-ului• Cache-ul trebuie configurat din web.config si nu din controller
Framework-ul de DI este apelat direct
• In anumite factory-uri (ControllerFactory) se apeleaza direct clase care tin de framework-ul de DI
• Diferite proiecte folosesc diferite DI
• Creati un wrapper peste acestea, care sa abstractizeze API-ul• Folositi Common Service Locator
• Este o abstractizare peste mecanismul de DI, care iti permite sa folosesti acelasi API indiferent de ce framework de DI folosesti
HtmlHelper - overused
• Nu creati un extension method la un HtmlHelper daca nu este folosit cel putin in doua locuri
• Incercati sa grupati aceste metode sub un nod comun daca se poate• O sa fie mai usor de folosit si de inteles
HtmlHelper.Table().BoxList().Pivot.Product() – returneaza ProductHtmlHelper
.FormatPrice()
.Stock()…
…
JavaScript in View
• Oricat de scurt este JavaScript-ul nu il puneti in view• JavaScript-ul o sa polueze view-ul si o sa il faca greu de inteles• Nu faceti apeluri AJAX din View
• Nu hardcodati adresa url pentru AJAX in JS – use UrlHelper• Ce se intampla daca o actiune se redenumeste ?• Ce se intampla daca locatia unei resurse se schimba?
• Trebuie facute in mai multe locuri modificari
View-uri foarte lungi
• Cat de normal este sa ai un view de 100 de randuri, iar codul sa se repete?
• Cat de normal este ca intr-un FOR dintr-un view sa se afiseze contintul unui “sub-model” direct?
• Pentru aceste cazuri se poate folosi Partial View• Nu conteaza daca acesta are doar 2 randuri sau 10
• Reutilizarea codului creste• Devine mai clar• Mai usor de citit si testat
Q&A