Framework-ul ASP.NET MVC Antochi Anca Mihaela Sarghie Radu Pricop Lucian
1
Framework-ul ASP.NET MVC.................................................................................................................1 Introducere.................................................................................................................................................3 Ce este ASP.NET MVC?..........................................................................................................................3 Avantaje ASP.NET MVC.................................................................................................................4 Controller-ul.............................................................................................................................................. 5 Exemplu 1: ........................................................................................................................................ 5 Acţiunile unui controller................................................................................................................... 6 Exemplu 2: ........................................................................................................................................ 6 Exemplu 3: ........................................................................................................................................ 7 View-ul......................................................................................................................................................8 Exemplu 4 – \Views\Home\Index.aspx .............................................................................................8 Exemplu 5: ........................................................................................................................................ 9 Exemplu 6 - ProductController.cs: ..................................................................................................10 Exemplu 7 -- \Views\Product\Details.aspx .....................................................................................11 Modelul...................................................................................................................................................11 Exemplu 8 - Models\IMovieRepository.cs .....................................................................................11 Models\MovieRepository.cs............................................................................................................12 Controllers\MoviesController.cs .....................................................................................................12 Direcţionare URL (URL Routing).......................................................................................................... 13 Folosirea Tabelului implicit de direcţionare ................................................................................... 13 Exemplu 8: ..................................................................................................................................... 13 Crearea unei rute proprii..................................................................................................................15 Exemplu 10 – Global.asax ..............................................................................................................15 ArchiveController.cs .......................................................................................................................16 Creare unei aplicaţii ASP.NET MVC cu Visual Studio ..........................................................................17 Adăugarea unei noi clase controller ................................................................................................ 17 Adăugarea unei clase view.............................................................................................................. 17 Concluzii.................................................................................................................................................18
2
Introducere O dată cu apariţia framework-ului ASP.NET, Microsoft a încercat să implementeze modelul din windows forms în dezvoltarea de aplicaţii web. Pentru a simula experienţa programatorului din modelul windows forms, au fost introduse în web forms programarea bazată pe evenimente, Viewstate (pentru a persista schimbările de stare între postback-uri) şi Postback. Acestea au dus la încălcarea naturii fară stare (stateless) a aplicaţiilor web. Ciclul de viaţă a unei pagini în acest model este complex şi duce la o cuplare strânsă, având o singură clasă pentru a afişa interfaţa la client şi pentru tratarea intrării de la utilizator. ASP.NET MVC este o alternativă pentru ASP.NET şi cele două variante vor co-exista. Ambele abordări ţin de alegerea programatorului.
Ce este ASP.NET MVC? Framework-ul ASP.NET MVC implementează şablonul arhitectural Model-View-Controller pentru dezvoltare de aplicaţii. Şablonul MVC a fost introdus iniţial în anul 1979 de către Trygve Reenskaug care lucra la limbajul Smalltalk. Principiul este de a împărţii aplicaţia în trei părţi distincte: controllerul (primeşte şi tratează intrarea), modelul (conţine logica aplicaţiei) şi view-ul (generează ieşirea). În contextul aplicaţiilor web, intrarea este cererea HTTP.
Figura1. Fluxul de cerere (request flow)
În modelul web forms, intrarea ajunge în pagină (View-ul) şi view-ul este responsabil atât cu manipularea intrării (input-ului), cât şi cu generarea ieşirii (outputului). Avantaje ASP.NET MVC •
Controlul integral asupra HTML–ului redat.
•
Separarea conceptelor (separation of concerns SoC).
•
Folosirea cu uşurinţa a programării bazată pe teste (Test Driven Development - TDD).
•
Respectarea designului fără stare a web-ului.
•
•
Include o componentă de mapare a URL-urilor pentru crearea de aplicaţii cu URL-uri simple, permiţând optimizarea pentru motoarele de căutare (SEO). Suportă motoare de vizualizare cum ar fi NVelocity, Brail, NHaml.
•
•
Nu foloseşte modelul existent în web forms de post–back pentru interacţiunea cu serverul. Acest model a fost înlocuit cu direcţionarea interacţiunii utilizatorului la o clasă Controller, astfel se realizează separarea conceptelor şi uşurinţa testării. Framework extensibil. Framework MVC este proiectat pentru a fi uşor de înlocuit şi personalizat (de exemplu este posibil ca un alt motor de vizualizare să fie conectat sau regulile de rutare să fie personalizate). De asemenea suportă injectare de dependenţe (dependecy injection) şi modele de containere IOC (Windsor, Spring.Net, NHibernate, etc) .
Controller-ul Controller-ul este responsabil cu primirea cererilor de la client (din browser). Fiecare cerere în browser este mapată la o clasă controller. De exemplu, controller-ul poate returna la utilizator un view sau poate redirecta spre un alt controller. Numele unei clase controller trebuie să se termine cu sufixul Controller . De exemplu ProductController este corect, dar un controller cu numele Product nu va funcţiona (va arunca excepţie). Un controller este o clasă ce trebuie să extindă clasa System.Web.Mvc.Controller. Exemplu 1: using System; using System.Web; using System.Web.Mvc; namespace MvcApp.Controllers { public class ProductController : Controller { public ActionResult Index() { // Add action logic here throw new NotImplementedException(); } } }
Acţiunile unui controller
Un controller expune acţiuni. O acţiune este o metodă în clasa controller-ului care este apelată atunci când utilizatorul introduce un URL în bara de adrese a browser-ului. În exemplul de mai sus, dacă utilizatorul face o cerere pentru URL-ul http://localhost/Product/Index/3, metoda Index() din clasa ProductController este apelată. O acţiune a controller-ului trebuie să fie o metodă publică. Trebuie avut în vedere faptul că orice metodă publică din clasa controller este automat expusă ca o acţiune a controller-ului. Astfel, poate fi apelată de oricine doar prin scrierea URL-ului corespunzător în bara de adrese a browser-ului. Mai există şi alte reguli ce trebuie respectate de o acţiune a controller-ului: o metodă folosită ca acţiune nu poate fi supraîncărcată şi nu poate fi statică. Ceea ce returnează o acţiune a unui controller reprezintă răspunsul cererii de la browser. Framework-ul ASP.NET MVC suportă saşe tipuri standard de rezultat: 1. ViewResult – Reprezintă HTML. 2. EmptyResult – Reprezintă nici un rezultat. 3. RedirectResult – Reprezintă o redirectare spre un alt URL. 4. RedirectToRouteResult – Reprezintă o redirectare spre o altă acţiune a controlerului. 5. JsonResult – Reprezintă un rezultat JavaScript Object Notation ce poate fi folosit intr-o aplicaţie AJAX. 6. ContentResult – Reprezintă un rezultat text. Toate aceste clase ce pot fi returnate de o acţiune extind clasa de bază ActionResult. În cele mai multe cazuri, acţiunea controller-ului întoarce un ViewResult. Exemplu 2: using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcApp.Controllers { public class BookController : Controller { public ActionResult Index() {
return View(); } } } Când o acţiune returnează un ViewResult, la browser este returnat HTML. Metoda Index() din exemplu de mai sus returnează la browser un view cu numele Index.aspx.
Remarcaţi faptul că acţiunea Index() din exemplu de mai sus nu returnează ViewResult() direct. In schimb, metoda View() din clasa de bază Controller este apelată. De obicei, o acţiune nu returnează direct un rezultat, ci apelează una din metodele din clasa de bază Controller: 1. View – Returnează un rezultat ViewResult. 2. Redirect – Returnează un rezultat RedirectResult. 3. RedirectToAction – Returnează un rezultat RedirectToRouteResult. 4. RedirectToRoute – Returnează un rezultat RedirectToRouteResult. 5. Json – Returnează un rezultat JsonResult. 6. Content – Returnează un rezultat ContentResult. Exemplu 3: using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcApp.Controllers { public class HomeController : Controller { public ActionResult Details(int? Id) { if (Id == null) return RedirectToAction("Index"); return View();
} public ActionResult Index() { return View(); } } }
View-ul Spre deosebire de ASP.NET sau ASP, în ASP.NET MVC nu este inclus ceva ce în mod direct corespunde unei pagini. Într-o aplicaţie ASP.NET MVC nu există o pagină pe disc ce corespunde căii din URL care a fost scrisă de utilizator în browser. Ceva apropiat de paginile din ASP.NET este în ASP.NET MVC un view. După cum a fost descris în secţiunea despre controller, o cerere din browser este mapată unui controller, care poate returna un view. În exemplul 3, metoda Index() conţine linia de cod: return View();
Acestă linie de cod retunează un view care trebuie să se afle la următoarea cale pe serverul web: \Views\Home\Index.aspx
Calea spre view este dedusă din numele controller-ului şi numele acţiunii din controller. Dacă preferaţi să specificaţi în mod explicit view-ul returnat, se poate face astfel: return View(“Example”);
Linia de cod de mai sus returnează un view cu numele Example, iar acest view este căutat la calea următoare: \Views\Home\Example.aspx
View-ul trebuie adăugat în directorul cu acelaşi nume ca şi controller-ul care îl returnează (fără sufixul Controller). Un view este un document standard (X)HTML ce poate conţine script-uri. Exemplu 4 – \Views\Home\Index.aspx <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApp.Views.Home.Index" %>
Index The current date and time is: <% Response.Write(DateTime.Now);%>
Se poate folosi orice limbaj .NET pentru a genera conţinut dinamic într-un view. De cele mai multe ori Visual Basic .NET sau C# vor fi folosite. Pentru a fi mai uşor să se adauge conţinut la un view, se poate folosi un, aşa numit, HTML Helper. Un HTML helper este o metodă care returnează un string şi poate fi folosit pentru a genera elemente HTML standard, cum ar textbox-uri, link-uri, dropdown-uri, etc. Exemplu 5: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index3.aspx.cs" Inherits="MvcApp.Views.Home.Index3" %>
Login Form
Se poate, de asemenea, crea propriile HTML helpere. De exemplu, o metodă helper GridView() care să afişeze un set de câmpuri din baza de date. Se poate folosi o proprietate a view-ului, ViewData pentru a trasmite mai departe date din controller la un view. De exemplu, controller-ul din exemplul de mai jos adaugă un mesaj la ViewData: Exemplu 6 - ProductController.cs: using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcApp.Controllers { public class ProductController : Controller { public ActionResult Details() { ViewData["message"] = "Hello World!"; return View(); } } }
ViewData este o colecţie nume-valoare. View-ul din exemplul mai jos foloseşte mesajul din ViewData şi redă mesajul la browser.
Exemplu 7 -- \Views\Product\Details.aspx <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Details.aspx.cs" Inherits="MvcApp.Views.Product.Details" %>
Product Details <%=Html.Encode(ViewData["message"])%>
Modelul Modelul MVC conţine logica aplicaţiei ce nu ţine de view sau de controller. În particular, modelul MVC conţine logica business a aplicaţiei şi accesul la baza de date. Pot fi folosite o varietate de tehnologii pentru a implementa logica de acces la baza de date, cum ar fi Microsoft Entity Framework, NHibernate, Subsonic, LINQ la SQL sau clase ADO.NET. Exemplu 8 - Models\IMovieRepository.cs using System.Collections.Generic; namespace MvcApplication1.Models { public interface IMovieRepository { IList
ListAll(); } }
Models\MovieRepository.cs using System.Collections.Generic; using System.Linq; namespace MvcApplication1.Models { public class MovieRepository : IMovieRepository { private MovieDataContext _dataContext; public MovieRepository() { _dataContext = new MovieDataContext(); } public IList ListAll() { var movies = from m in _dataContext.Movies select m; return movies.ToList(); } } }
Controllers\MoviesController.cs using System.Web.Mvc; using MvcApplication1.Models; namespace MvcApplication1.Controllers { public class MoviesController : Controller {
private IMovieRepository _repository; public MoviesController() : this(new MovieRepository()) { } public MoviesController(ImovieRepository repository) { _repository = repository; } public ActionResult Index() { return View(_repository.ListAll()); } } }
Direcţionare URL (URL Routing) Direcţionarea URL (URL Routing) este modulul responsabil cu maparea cererilor din browser la o acţiune specifică din controller. Folosirea Tabelului implicit de direcţionare
Direcţionarea URL trebuie setată în două locuri: 1. Fişierul de configurare (Web.config). Există patru secţiuni în fişierul de configurare ce sunt relevante pentru direcţionare (routing): secţiunea system.web.httpModules , secţiunea system.web.httpHandlers , secţiunea system.webserver.modules şi sectiunea system.webserver.handlers . Fără aceste secţiuni prezente în fişierul de configurare direcţionarea nu funcţionează. 2. Tabelul de direcţionare este creat în fişierul Global.asax . Acesta este un fişier special ce conţine tratarea (handler) evenimentelor din ciclul de viaţă al aplicaţiei ASP.NET. Tabelul de direcţionare este creat în timpul evenimentului Application Start. Exemplu 8: using System;
using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace MyApp { public class GlobalApplication : System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( // Route name "Default", //URL with parameters "{controller}/{action}/{id}", // Parameter defaults new { controller = "Home", action = "Index", id = ""}); } protected void Application_Start() { RegisterRoutes(RouteTable.Routes); } } }
Când o aplicaţie ASP.NET MVC rulează pentru prima dată, metoda Application_Start() este apelată. Această metodă, la rândul ei, aplează metoda RegisterRoutes(), care crează tabela de direcţionare (route table). Dacă utilizatorul nu include un nume de controller în URL, atunci valoarea implicită este Home. Dacă nu se oferă numele acţiunii, aceasta va fi implicit Index, iar dacă nu se oferă un id, parametrul id va fi un string gol. Mai jos avem un exemplu de cum ruta implicită mapează acţiunile controller-ului:
Utilizatorul introduce în bara de adrese a browserului: /Home
Aceasta duce la apelarea metodei Index din clasa HomeController using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MyApp.Controllers { public class HomeController : Controller { public ActionResult Index(string Id) { return View(); } } }
În exemplul de mai sus, clasa HomeController include o metodă Index() ce accept un parametru Id, astfel metoda este apelată cu valoarea parametrului un string gol. Dacă metoda Index ar avea un parametru de tip int care nu este nullable, apelarea URL-ului /Home ar aruncara o excepţie. Crearea unei rute proprii
Pentru aplicaţii ASP.NET MVC simple, direcţionarea implicită poate fi de ajuns, dar pentru aplicaţii mai complexe este nevoie să se creeze rute proprii. De exemplu, pentru o aplicaţie blog am putea avea nevoie să introducem un URL care ar arată astfel: / Archive/12-25-2009
Fişierul Global.asax din exemplul de mai jos conţine o noua rută numită blog, care manipulează cererile care arată astfel: /Archive/ entry date. Exemplu 10 – Global.asax using System.Web.Mvc;
using System.Web.Routing;
namespace MyApp { public class GlobalApplication : System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "blog", "Archive/{entryDate}", new {controller = "Archive", action = "Entry"} ); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = ""} // Parameter defaults ); }
protected void Application_Start() { RegisterRoutes(RouteTable.Routes); } } }
Ordinea în care rutele sunt adăugate la tabelul de rutare este importantă. În exemlul de mai sus ruta blog este adaugată înainte de cea implicită. Dacă ordinea ar fi inversată, ruta Default ar fi tot timpul apelată. Ruta proprie mapează toate cererile la un controller numit Archive şi invocă metoda Entry(). Când metoda Entry() este chemată, data este pasată ca parametru. ArchiveController.cs using System;
using System.Web.Mvc; namespace MyApp.Controllers { public class ArchiveController : Controller { public string Entry(DateTime entryDate) { return "You requested the entry on " + entryDate.ToString(); } } }
Metoda Entry() din exemplul de mai sus primeşte un parametru de tip DateTime . Framework-ul ASP.NET MVC va converti, în mod automat, data din URL într-o valoare de tip DateTime . Dacă parametrul din URL nu poate fi convertit la DateTime , o excepţie este aruncată.
Creare unei aplicaţii ASP.NET MVC cu Visual Studio După instalarea framework-ului ASP.NET MVC, în Visual Studio 2008 va exista un template pentru crearea de aplicaţii ASP.NET MVC. Pentru un nou proiect selectaţi File/New Project – apoi ASP.NET MVC Web Application. De fiecare dată când se crează un nou proiect ASP.NET MVC, Visual Studio afişează şi posibilitatea de a crea un proiect separat de unit test. O aplicaţie ASP.NET MVC are un set standard de directoare: Models, Views, Controllers, Scripts şi Contents. La crearea aplicaţiei cu ajutorul Visual Studio, se crează în aceste directoare şi fişiere ce oferă un exemplu pentru fiecare componentă. Adăugarea unei noi clase controller
O nouă clasă controller se poate adăuga în Visual Studio prin click dreapta pe directorul Controllers, selectaţi Add, New Item şi apoi selectaţi MVC Controller Class. Adăugarea unei clase view
Un view trebuie adăugat în directorul protrivit. Dacă se crează un view pentru metoda acţiune Index() a controller-ului HomeController, atunci clasa View trebuie plasată la calea următoare: \Views\Home\Index.aspx
Cu Visual Studio se crează un nou view prin click dreapta pe un subdirector din directorul Views şi selectaţi Add, New Item, iar apoi selectaţi MVC View.
O dată cu ultima lansare a framework-ului (versiunea beta), se poate adăuga un nou view din metoda acţiune a unui Controller, click dreapta şi selectaţi „Add View” (ca alternativa se poate folosi scurtătura Ctrl-M Ctrl-V pentru a invoca meniul contextual fară a lua mâinile de la tastatură). Visual Studio va pre-popula automat numele view-ului bazându-se pe numele metodei acţiune din care s-a deschis meniul.
Concluzii Pentru programatorii care doresc să creeze aplicaţii folosind arhitectura MVC, framework ASP.NET MVC este o opţiune uşoară şi curată. Oferă posibilitatea de a menţine uşor separarea conceptelor în aplicaţie, de asemenea, facilitatea de a crea unit teste şi de a aborda programarea bazată pe teste.